Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have my character "ride" along with moving platforms?

Im experiencing a problem with my Hero Character, when he lands on a moving platform, rather then moving along with it, he literally stands on the same X position until the platform moves offscreen. I searched many answers with no avail.

Here is my methods for my hero character and the moving platforms.

-(void)HeroAdd
{    
    _Hero = [SKSpriteNode spriteNodeWithImageNamed:@"Hero-1"];
    _Hero.name = @"Daniel";
    _Hero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_Hero.size];
    _Hero.physicsBody.categoryBitMask = fPlayerCategory;
    _Hero.physicsBody.contactTestBitMask = fPlatformCategory | fEnemyCategory;
    _Hero.physicsBody.usesPreciseCollisionDetection = YES;
    _Hero.physicsBody.affectedByGravity = YES;
    _Hero.physicsBody.dynamic = YES;
    _Hero.physicsBody.friction = .9;
    _Hero.physicsBody.restitution = 0;
    _Hero.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    _Hero.position = CGPointMake(_Hero.position.x - 252, _Hero.position.y + 50);

    if (self.size.width == 480) {
        _Hero.position = CGPointMake(_Hero.position.x + 44, _Hero.position.y);
    }

    [self addChild:_Hero];
}

My moving platform code

-(void)createPlatform {

    SKTexture *objectTexture;

    switch (arc4random_uniform(2)) {
        case (0):
            objectTexture = [SKTexture textureWithImageNamed:@"shortPlatform"];
            break;
        case (1):
            objectTexture = [SKTexture textureWithImageNamed:@"highPlatform"];
        default:
            break;
    }

    SKSpriteNode *variaPlatform = [SKSpriteNode spriteNodeWithTexture:objectTexture];
    variaPlatform.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    variaPlatform.position = CGPointMake(variaPlatform.position.x + 500, variaPlatform.position.y - 140);
    variaPlatform.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:variaPlatform.size];
    variaPlatform.physicsBody.usesPreciseCollisionDetection = YES;
    variaPlatform.physicsBody.categoryBitMask = fPlatformCategory;
    variaPlatform.physicsBody.contactTestBitMask = fPlatformCategory |fPlayerCategory | fEnemyCategory;
    variaPlatform.physicsBody.dynamic = NO;
    variaPlatform.physicsBody.affectedByGravity = NO;

    SKAction *moveLeft = [SKAction moveTo:CGPointMake(180, variaPlatform.position.y) duration:3];
    SKAction *moveDown = [SKAction moveTo:CGPointMake(180, -700) duration:4];
    SKAction *removeFromParent = [SKAction removeFromParent];

    SKAction *AllThree = [SKAction sequence:@[moveLeft, moveDown, removeFromParent]];

    [self addChild:variaPlatform];

    [variaPlatform runAction:AllThree];

}

Any type of information would be truly appreciated.

like image 723
Blank Avatar asked Jul 28 '14 12:07

Blank


1 Answers

I ran into the same issue when I added conveyer belts into a game. Sprite Kit does not drag objects no matter how much resistance is added. You currently have 2 options.

Option 1 - Add a ledge at each end of your platform. This is the easiest to implement but is less graceful and still allows the player to slide off if he lands on the ledge.

enter image description here

Option 2 -

Step 1: Add code which makes the player move in sync with the horizontal moving platform. You can either use something like self.physicsBody.velocity = CGVectorMake(-50, self.physicsBody.velocity.dy); or use self.position = CGPointMake(self.position.x+10, self.position.y);. You will have to play around with the x values to sync them to the platform's speed.

Step 2: Activate the above code whenever the player makes contact with the platform and deactivate when contact is lost.

Step 3: In case the platform switches directions, set up left and right limits which notify you via contact when the platform switches direction. Depending on the platform's direction you apply either +x or -x movement values to your player.

I know this option sounds complicated but it is not. You just need to go step by step.

* EDIT to provide sample code *

This is the logic I have behind the horizontal moving platforms:

PLATFORMS If you have more than 1 horizontal moving platform, you will need to store them in an array in the GameScene (my Levels). I have created my own class for them but you do not have to do this.

You will have to set left and right limits (invisible SKNodes with contacts) to set a BOOL property for the platform which tells the player class which way to push as each platform will probably not be the same length. This is why you need to keep a reference to each platform (hence the array).

PLAYER When the player jumps on the platform, set a Player class property BOOL to TRUE which activates the constant left or right push depending on which way the platform is currently moving. On the flip side, losing the contact cancels the push.

// This code in my "Levels class" which is the default GameScene class.
- (void)didBeginContact:(SKPhysicsContact *)contact
{
    uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);

    if (collision == (CategoryPlatformHorizontal | CategoryPlayer))
    {
        [_player setPlatformHorizontalContact:true];

        for(Platform *platformObject in platformArray)
        {
            if(([platformObject.name isEqualToString:contact.bodyB.node.name]) || ([platformObject.name isEqualToString:contact.bodyA.node.name]))
            {
                _player.currentPlatform = platformObject;
            }
        }
    }
}

- (void)didEndContact:(SKPhysicsContact *)contact
{
    uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);

    if (collision == (CategoryPlatformHorizontal | CategoryPlayer))
    {
        [_player setPlatformHorizontalContact:false];
    }
}

// This code is in Player.h
@property (strong) Platform *currentPlatform;
@property BOOL platformHorizontalContact;

// This code is in Player.m
- (void)update:(NSTimeInterval)currentTime
{
    if(self.platformHorizontalContact == true)
    {
        if(self.currentPlatform.movingLeft == true)
        {
            self.physicsBody.velocity = CGVectorMake(-75, self.physicsBody.velocity.dy); // set your own value depending on your platform speed
        } else {
            self.physicsBody.velocity = CGVectorMake(75, self.physicsBody.velocity.dy); // set your own value depending on your platform speed
        }
    }
}
like image 183
sangony Avatar answered Oct 29 '22 16:10

sangony