Prevent player from falling through the ground - Sprite Kit

a 夏天 提交于 2019-12-05 19:19:20

you definitely can't set its dynamic to no brother. you need gravity effect that player. (he is not effected by physic world so he is flying right now. we need him to fall down to ground aren't we? :)

So here is the simple solution. idea is that you create a "invisible rectangle block" on the ground surface that has physic body. and you need to set its dynamic to no in order to prevent it falling down

so this block is a node obviously, and its size : as high as the ground , and as wide as the screen. and you need to adjust the position a little bit to put its upper bound right on the ground surface.

good luck

i actually drew a picture but i can't post it here because of my reputation :(

Your problem is with physicsBody's categoryBitMask and collisionTestBitMask. Your bitwise declarations :

static const uint32_t redBallCategory =  0x1 << 0;
static const uint32_t playerCategory =  0x1 << 1; 

This has actually set the following bit patterns (i've shortened to 8 bits for the example) : redBallCategory - 00000001 and playerCategory - 00000010

However in the following code, you tell the player to only collide with collision bit mask - 00000000; self.playerSprite.physicsBody.collisionBitMask = 0;

So your first problem is here. The player will not collide with any category that you have defined.

Your second problem is you have not given the ground a categoryBitMask, or collisionBitMask. By default this means all bits are set, IE the ground's collisionBitMask is equal to 11111111;

There will be no collision between these two physics bodies.

Try this - i have simply added a third physics category, and edited your code slightly to set the ground categoryBitMask / collisionBitMask, and your player collisionBitMask.

static const uint32_t redBallCategory =  0x1 << 0;
static const uint32_t playerCategory =  0x1 << 1;
static const uint32_t groundCategory = 0x1 << 2;

@implementation MyScene

-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
    /* Setup your scene here */

    //Sets player location
    playerLocX = 50;
    playerLocY = 100;

    //Sets player score
    score = 0;

    //Set Background
    self.backgroundColor = [SKColor colorWithRed:0.53 green:0.81 blue:0.92 alpha:1.0];

    //Set Ground
    SKSpriteNode *ground = [SKSpriteNode spriteNodeWithImageNamed:@"ground"];
    ground.position = CGPointMake(CGRectGetMidX(self.frame), 34);
    ground.xScale = 0.5;
    ground.yScale = 0.5;
    ground.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ground.size];
    ground.physicsBody.categoryBitMask=groundCategory;
    ground.physicsBody.collisionBitMask=playerCategory|redBallCategory;
    ground.physicsBody.dynamic = NO;

    //Player
    self.playerSprite = [SKSpriteNode spriteNodeWithImageNamed:@"character"];
    self.playerSprite.position = CGPointMake(playerLocX, playerLocY);

    //Set Player Physics
    self.playerSprite.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.playerSprite.size];
    self.playerSprite.physicsBody.dynamic = YES;
    self.playerSprite.physicsBody.categoryBitMask = playerCategory;
    self.playerSprite.physicsBody.contactTestBitMask = redBallCategory;
    self.playerSprite.physicsBody.collisionBitMask = groundCategory|redBallCategory;
    self.playerSprite.physicsBody.usesPreciseCollisionDetection = YES;

    //Score Label
    self.scoreLabel = [SKLabelNode labelNodeWithFontNamed:@"Arial-BoldMT"];
    self.scoreLabel.text = @"0";
    self.scoreLabel.fontSize = 40;
    self.scoreLabel.fontColor = [SKColor blackColor];
    self.scoreLabel.position = CGPointMake(50, 260);

    //Pause Button
    self.pauseButton = [SKSpriteNode spriteNodeWithImageNamed:@"pauseButton"];
    self.pauseButton.position = CGPointMake(self.frame.size.width / 2, self.frame.size.height - 40);
    self.pauseButton.name = @"pauseButton";

    //Add nodes
    [self addChild:ground];
    [self addChild:self.playerSprite];
    [self addChild:self.scoreLabel];
    //[self addChild:self.pauseButton];

    //Sets gravity
    self.physicsWorld.gravity = CGVectorMake(0,-2);
    self.physicsWorld.contactDelegate = self;

}
return self;

}

Just:

self.playerSprite.physicsBody.dynamic = NO;

should work.

Your problem occurs due to scaling. For some reason in sprite kit scaling an image doesn't change it's size when used in following code. Judging by your pictures, your physics body rectangle for your ground is actually twice as big as you think and already engulfing the player, which is why there would by no collision detection. This is from recent experience with a very similar style game.

Do you have an edge loop physcis body around the scene? Collision flags and category flags set correctly so the player collides with the ground?

i had same problem and i soved it simply...

On the update method i've putted an if statement:

if(player.position.y<your_closest_value_near_ground){

player.position.y == your_Closest_value_near_ground

}

The comparition differs by the anchor point you have.. hope it helps someone

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!