SpriteKit turtles collision with curved or sloped floor tiles

I am planning a platformer game for iOS using SpriteKit and Swift. I did some research on how to handle player sprite conflicts and came across this article.

http://www.learn-cocos2d.com/2013/08/physics-engine-platformer-terrible-idea/

For this article, you shouldn't use SpriteKit's built-in physics engine, but to implement things like move, jump, and collision handling. The platform tutorial on Ray Wenderlish's site takes a similar approach.

So far so good, but we can talk about floor tiles that the player can stand on. A custom physics implementation would be straightforward if the tiles are rectangular and have a flat surface (for example, in the tutorial from Ray Wenderlich), since you used CGRectIntersectsRect for collision detection. But how do you check for player collisions with curved or inclined plates? From what I've read, CGRectIntersectsRect doesn't account for the transparent pixel inside the sprites rectangle.

http://i.stack.imgur.com/lRP2Q.png

Take a look at the above tile for example. The white area (top left) will be transparent. Now, if the game sprite lands on this tile, a collision will be detected at the top border of the tile rectangle, although there are no ground pixels there (blue area, bottom right). So ultimately the player will float above this tile. I could press the sprite button a few pixels, but this is a bit hacky and gets tricky if the curved floor tiles have different angles.

So the question is, how can I handle these types of conflicts with SpriteKit alone (no additional frameworks like Cocos2D, Kobold Kit, ...)? Or is this approach completely wrong and the collisions in the SpriteKit platformer have to be made fundamentally different?

Any help is greatly appreciated!

+3


source to share


2 answers


I disagree that I am not using physics to handle collisions and contacts. You are really just trying to reinvent the wheel here without using physics or implementing your own code.

If you are using the Tiled app, then assigning a physical body is an easy task. Use Object in Tiled to assign different body types. In your code, you can proceed to create a specific body for each type of object.

For example:

enter image description here

In the above image, I've created a 45 degree right side sloped floor. The object I added is called floor45R.

The next step is to analyze your map objects. In the case of 45floorR, you will create a physical body like this:



NSArray *arrayObjects = [group objectsNamed:@"floor45R"];
    for (NSDictionary *dicObj in arrayObjects) {
        CGFloat x = [dicObj[@"x"] floatValue];
        CGFloat y = [dicObj[@"y"] floatValue];
        CGFloat w = [dicObj[@"width"] floatValue];
        CGFloat h = [dicObj[@"height"] floatValue];

        SKSpriteNode *myNode = [SKSpriteNode spriteNodeWithColor:[SKColor clearColor] size:CGSizeMake(w, h)];
        myNode.position = CGPointMake(x, y);
        myNode.zPosition = 100;
        CGMutablePathRef trianglePath = CGPathCreateMutable();
        CGPathMoveToPoint(trianglePath, nil, -myNode.size.width/2, myNode.size.height/2);
        CGPathAddLineToPoint(trianglePath, nil, myNode.size.width/2, -myNode.size.height/2);
        CGPathAddLineToPoint(trianglePath, nil, -myNode.size.width/2, -myNode.size.height/2);
        CGPathAddLineToPoint(trianglePath, nil, -myNode.size.width/2, myNode.size.height/2);
        myNode.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:trianglePath];
        myNode.physicsBody.dynamic = NO;
        myNode.physicsBody.restitution = 0;
        myNode.physicsBody.friction = 0.0;
        myNode.physicsBody.categoryBitMask = CategoryFloor45;
        myNode.physicsBody.collisionBitMask = 0x00000000;
        CGPathRelease(trianglePath);

        [worldNode addChild:myNode];
    }

      

This works for any level of floor incline. Remember to set the player and any other node collision bit mask to collide with the floor.

In order for your player to move smoothly on an inclined floor, I recommend building the player's physical body in 2 parts. A circle at the bottom and a rectangle at the top. The circle will prevent it from getting stuck in any potential cracks caused by attaching to physical bodies.

SKPhysicsBody *firstBody = [SKPhysicsBody bodyWithCircleOfRadius:10 center:CGPointMake(0, 0)];
SKPhysicsBody *secondBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(5, 50) center:CGPointMake(0, 10)];
self.physicsBody = [SKPhysicsBody bodyWithBodies:@[firstBody, secondBody]];

      

You will need to adjust the position and center coordinates to match your sprite image.

+3


source


You can use the Tiled Level Editor to handle curved and sloped floor tiles along with JSTileMap, which processes the TMX map.

It will be able to handle contact with curved and sloped floor slabs, but to adjust the angle of objects standing on top of these slabs you will need to use some math functions, a good example can be found here



You can still use SpriteKit's collision detection, which will make things easier for you, but create your own jump or motion engine.

+1


source







All Articles