Creating a boundary around a tiled map - ios

I've created a tiled map composed of multiple sprite nodes that are 367x367. I create this map like so:
for var i = 0; i < Int(multiplier); i++ {
for var j = 0; j < Int(multiplier); j++ {
// Positive
var map = SKSpriteNode(imageNamed: "tiledBackground.png")
var x = CGFloat(i) * map.size.height
var y = CGFloat(j) * map.size.height
map.position = CGPointMake(x, y)
self.addChild(map)
}
}
In the above example, the multiplier is 27 and the map size is 10,000x10,000.
This creates the map as expected, however I want this map to have boundaries that the player can't leave. I know how to create the boundaries, but I'm not sure what values to initialize the physics body with.
I've tried this: SKPhysicsBody(rectangleOfSize: map.mapSize) however that produced very erroneous results.
I also tried this: SKPhysicsBody(edgeLoopFromRect: CGRectMake(0, 0, map.mapSize.width, map.mapSize.height)) which built a physics body like it should (I have showPhysics = TRUE), however the physics body seemed to move with the player (I have the player moving and am centering the map on the player). You can see what I mean here: http://gyazo.com/675477d5dd86984b393b10024341188a (It's a bit hard to see, but that green line is the boundary for the physics body. When the tiled map ends (And where it turns grey), the physics body should stop as that's where the player shouldn't be allowed to move any more).
Just leave a comment if you need any more code (I believe I included anything that is relevant).

After messing around with a bit of my code I found a fix was to just add the physicsBody to my map instead of the scene. A rather easy fix, so I'm surprised I didn't think of it sooner.
With this in mind, I've answered my own question and no longer need help.

Related

Box2D: How to use b2ChainShape for a tile based map with squares

Im fighting here with the so called ghost collisions on a simple tile based map with a circle as player character.
When applying an impulse to the circle it first starts bouncing correctly, then sooner or later it bounces wrong (wrong angle).
Looking up on the internet i read about an issue in Box2D (i use iOS Swift with Box2d port for Swift).
Using b2ChainShape does not help, but it looks i misunderstood it. I also need to use the "prevVertex" and "nextVertex" properties to set up the ghost vertices.
But im confused. I have a simple map made up of boxes (simple square), all placed next to each other forming a closed room. Inside of it my circle i apply an impulse seeing the issue.
Now WHERE to place those ghost vertices for each square/box i placed on the view in order to solve this issue? Do i need to place ANY vertex close to the last and first vertice of chainShape or does it need to be one of the vertices of the next box to the current one? I dont understand. Box2D's manual does not explain where these ghost vertices coordinates are coming from.
Below you can see an image describing the problem.
Some code showing the physics parts for the walls and the circle:
First the wall part:
let bodyDef = b2BodyDef()
bodyDef.position = self.ptm_vec(node.position+self.offset)
let w = self.ptm(Constants.Config.wallsize)
let square = b2ChainShape()
var chains = [b2Vec2]()
chains.append(b2Vec2(-w/2,-w/2))
chains.append(b2Vec2(-w/2,w/2))
chains.append(b2Vec2(w/2,w/2))
chains.append(b2Vec2(w/2,-w/2))
square.createLoop(vertices: chains)
let fixtureDef = b2FixtureDef()
fixtureDef.shape = square
fixtureDef.filter.categoryBits = Constants.Config.PhysicsCategory.Wall
fixtureDef.filter.maskBits = Constants.Config.PhysicsCategory.Player
let wallBody = self.world.createBody(bodyDef)
wallBody.createFixture(fixtureDef)
The circle part:
let bodyDef = b2BodyDef()
bodyDef.type = b2BodyType.dynamicBody
bodyDef.position = self.ptm_vec(node.position+self.offset)
let circle = b2CircleShape()
circle.radius = self.ptm(Constants.Config.playersize)
let fixtureDef = b2FixtureDef()
fixtureDef.shape = circle
fixtureDef.density = 0.3
fixtureDef.friction = 0
fixtureDef.restitution = 1.0
fixtureDef.filter.categoryBits = Constants.Config.PhysicsCategory.Player
fixtureDef.filter.maskBits = Constants.Config.PhysicsCategory.Wall
let ballBody = self.world.createBody(bodyDef)
ballBody.linearDamping = 0
ballBody.angularDamping = 0
ballBody.createFixture(fixtureDef)
Not sure that I know of a simple solution in the case that each tile can potentially have different physics.
If your walls are all horizontal and/or vertical, you could write a class to take a row of boxes, create a single edge or rectangle body, and then on collision calculate which box (a simple a < x < b test) should interact with the colliding object, and apply the physics appropriately, manually calling the OnCollision method that you would otherwise specify as the callback for each individual box.
Alternatively, to avoid the trouble of manually testing intersection with different boxes, you could still merge all common straight edge boxes into one edge body for accurate reflections. However, you would still retain the bodies for the individual boxes. Extend the boxes so that they overlap the edge.
Now here's the trick: all box collision handlers return false, but they toggle flags on the colliding object (turning flags on OnCollision, and off OnSeparation). The OnCollision method for the edge body then processes the collision based on which flags are set.
Just make sure that the colliding body always passes through a box before it can touch an edge. That should be straightforward.

How to turn off anti aliasing on a sprite kit node's texture

I'm currently trying to put a test game together in Sprite Kit. I have some code that creates a patch of ground using a pair of PNG images with dimensions 200 * 572.
let textures = [SKTexture(imageNamed: "GrassAni1"), SKTexture(imageNamed: "GrassAni2")]
for (var i = 0; i < 10; i += 1) {
let chunk = SKSpriteNode(texture: textures[0])
chunk.position = CGPointMake(CGFloat(200 * i), 0)
let animate = SKAction.animateWithTextures(textures, timePerFrame: 1)
chunk.runAction(SKAction.repeatActionForever(animate))
//boilerplate physics body codeā€¦
self.addChild(hero)
}
Enter my problem. Here is an up-close of my sprite in the Xcode file viewer:
And here's what it looks like when the game is running:
The in-game sprite appears to be anti-aliased and as a result looks fuzzy. How do I prevent this and make the game look as sharp as the original images?
You will need to change the filteringMode on your SKTexture objects to SKTextureFilteringMode.Nearest.
Then as long as your node is positioned on pixel boundaries, it should be drawn as expected.

Centering Camera on Velocity Applied Node Not Working

I have a subclass of SKNode which consists of a few sprites that make up a player. I would like the "camera" to center on this node (Always have the player in the center). Now before you down vote this for it being a duplicate, hear me out. The Apple documents suggest making the player node completely static, and instead moving around a camera node. However in my case I'm applying multiple properties of physics to my character, including velocity impulses. My first thought would be to just apply these impulses to the camera node itself, however this has become impossible due to the fact that the character has a small soft-body physics engine on it. I'm applying velocity to it like so:
player.primaryCircle.physicsBody!.velocity = CGVector(dx: player.primaryCircle.physicsBody!.velocity.dx+relVel.dx*rate, dy: player.primaryCircle.physicsBody!.velocity.dy+relVel.dy*rate)
I managed to get it to partially work with the following code:
override func didSimulatePhysics() {
self.player.position = player.primaryCircle.position
self.camera.position = player.position
centerOnNode(camera)
}
func centerOnNode(node: SKNode) {
let cameraPositionInScene: CGPoint = node.scene!.convertPoint(node.position, fromNode: node.parent!)
node.parent!.position = CGPoint(x:node.parent!.position.x - cameraPositionInScene.x, y:node.parent!.position.y - cameraPositionInScene.y)
}
However that didn't 100% work, as seen here: (It should be focused on the red circle)
http://gyazo.com/b78950e6cc15b60f390cd8bfd407ab56
As you can see, the world/map is moving, however it doesn't seem to be moving fast enough to center the player in the middle. (And note that the "Unamed" text is at a fixed spot on the screen -- That's why it seems to always be in the center)
I think this should still work with physics unless I am not truly understanding the question. We did something similar with our SKATiledMap with that Auto Follow Feature. What you need to do is make sure the player is added to a node you can move (usually a map) as a child and then in the update function you do something like this...(sorry it isn't in swift)
-(void)update
{
if (self.autoFollowNode)
{
self.position = CGPointMake(-self.autoFollowNode.position.x+self.scene.size.width/2, -self.autoFollowNode.position.y+self.scene.size.height/2);
//keep map from going off screen
CGPoint position = self.position;
if (position.x > 0)
position.x = 0;
if (position.y > 0)
position.y = 0;
if (position.y < -self.mapHeight*self.tileWidth+self.scene.size.height)
position.y = -self.mapHeight*self.tileWidth+self.scene.size.height;
if (position.x < -self.mapWidth*self.tileWidth+self.scene.size.width)
position.x = -self.mapWidth*self.tileWidth+self.scene.size.width;
self.position = CGPointMake((int)(position.x), (int)(position.y));
}
}
Map being the node that the player is added to. Hopefully that helps. Also here is the link to the git hub project we have been working on. https://github.com/SpriteKitAlliance/SKAToolKit

setting the angle of a b2revolutejoint

From what I have read, in Box2d, you get the angle of a revolute joint with the GetJointAngle function, but when trying to set the angle the member m_referenceAngle is protected. Can the angle not be programmatically set?
I found that I can apply the angle from one joint to another body as:
float FirstAngle = firstArmJoint->GetJointAngle();
secondArmBody->SetTransform(b2Vec2((750.0/PTM_RATIO),(520.0f+100)/PTM_RATIO),hourAngle);
I put this in ccTouchesMoved so that when the user drags the first object (from which FirstAngle is retrieved) the second object (secondArmBody) is also moved.
What happens is that the second body rotates at the top of the image and not at the anchor point.
Any ideas?
SetTransform() can be used to set the position and rotation of a body. This happens completely independently of any joints on the body. For example, if you want to make sure a body is perfectly upright at a given moment, you can call
body->SetTransForm(body->GetPosition(), 0);
passing 0 as the angle value (upright). I've never tried this for a body with a joint on it, but I doubt it would work properly.
When I ran into the problem of having to make a revolutejoint point at a certain angle, I solved it by enabling motor on the joint and adjusting the motor speed until the angle matched the one I wanted. This simulates realistic motion of the joint. Example:
Creating the joint
b2RevoluteJointDef armJointDef;
armJointDef.Initialize(body1, body2,
b2Vec2(body1->GetPosition().x,
((body1->GetPosition().y/PTM_RATIO));
armJointDef.enableMotor = true;
armJointDef.enableLimit = true;
armJointDef.motorSpeed = 0.0f;
armJointDef.maxMotorTorque = 10000.0f;
armJointDef.lowerAngle = CC_DEGREES_TO_RADIANS(lowerArmAngle);
armJointDef.upperAngle = CC_DEGREES_TO_RADIANS(upperArmAngle);
_world->CreateJoint(&armJointDef);
Pointing the joint
float targetAngle = SOME_ANGLE;
b2JointEdge *j = body->GetJointList();
b2RevoluteJoint *r = (b2RevoluteJoint *)j->joint;
if(r->GetAngle() > targetAngle){
r->SetMotorSpeed(-1);
} else { r->SetMotorSpeed(1); }
Basically, you see what side of the current angle the target angle is on, and then set the motor speed to move the joint in the correct direction. Hope that helps!
http://www.box2d.org/manual.html

Vertices behind are being drawn infront - XNA

Well, I am creating a minecraft terrain thing just for the heck of it. The problem I have is that if you look on a certain angle some faces which are actually behind others are drawn in front of them, thus not showing the actual ones which are there. Like minecraft I have the terrain seperated into regions, and when the vertexbuffer is built, only the "outside" faces are shown. It is also for some reason is not drawing the very top nor the left blocks. In addition to all of these problems faces seem to be overlapping ie (only half of a face can be seen)
Here is what it looks like (note I am only drawing the top faces because I have to fix the others up): http://s1100.photobucket.com/albums/g420/darestium/?action=view&current=minecraftliketerrain.png
I am also drawing all the regions in one go with the following method (i'm using reimer's effect file until I can write my own :):
public void Draw(Player player, World world)
{
effect.CurrentTechnique = effect.Techniques["TexturedNoShading"];
effect.Parameters["xWorld"].SetValue(Matrix.Identity);
effect.Parameters["xProjection"].SetValue(player.Camera.ProjectionMatrix);
effect.Parameters["xView"].SetValue(player.Camera.ViewMatrix);
effect.Parameters["xCamPos"].SetValue(player.Camera.Position);
effect.Parameters["xTexture"].SetValue(world.TextureAlias.SheetTexture);
effect.Parameters["xCamUp"].SetValue(player.Camera.UpDownRotation);
for (int x = 0; x < world.regions.GetLength(0); x++)
{
for (int y = 0; y < world.regions.GetLength(1); y++)
{
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
Region region = world.regions[x, y];
if (player.Camera.BoundingFrustum.Contains(region.BoundingBox) != ContainmentType.Disjoint)
{
device.SetVertexBuffer(region.SolidVertexBuffer);
//device.Indices = region.SolidIndices;
device.DrawPrimitives(PrimitiveType.TriangleList, 0, region.VertexCount);
//device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, region.VertexCount, 0, region.SolidIndices.IndexCount / 3);
}
}
}
}
}
Help would be much appreciated thanks :)
Looks like the Z-buffer is disabled. Try setting:
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
The issue with it not drawing the top/left blocks, that you mention, is probably an issue to do with your vertex buffer generation code (if so, try asking another question specifically about that issue).

Resources