2

I have my first game application in development. In this game, the only character that the user controls will get to jump from one block to another. It's like Mario (in Mario Brothers) jumping from one moving lift to another. If he fails, he'll die. So how could you tell a free fall from a short fall as a result of a successful jump? One thing I thought I could do is measuring character's vertical velocity. So I have the following lines of code. It's used with didSimulatePhysics

SKNode *player = [self childNodeWithName:@"//player"]; // It's the node characterizing the game character
CGVector v = player.physicsBody.velocity;

if (v.dy < -2000) {
    [self endTheScene:kEndReasonLose]; // The character has died from free fall => game is over
}

When the game character jumps, the game application can record a vertical velocity of -2022.466797. So this measure won't work. What else can I do? Set an invisible bar and see if the game character has touched it with intersectsNode? That can also fail. I have never developed a game before. So I don't know how they do it, which kind of makes me realize how impressive Nintendo game developers are. Some 30 years later, I still can't do it.

Thank you for your advice.


Update

The following can tell whether or not the character has died from free fall, I think.

- (void)didSimulatePhysics {
    if (self.isMoving) {
    // isMoving is an instance variable (BOOL): YES if the game has started
        CGVector v = player.physicsBody.velocity;
        BOOL hasFallen = self.lastFallenDate ? [self.lastFallenDate timeIntervalSinceNow] < -2.0 : YES; // lastFallenDate is an instance variable recording the time when the character fell last time
        if (hasFallen) {
            if (v.dy < -1500) {
                [self endTheScene:kEndReasonLose];
            }
        }
    }
}

Yet, I think Apple has a bug to fix as far as SKAction is concerned. No matter I do, audio will kick in exactly about 5 seconds after the game started although the character is not falling.

- (void)endTheScene:(EndReason)endReason {
    if (endReason == kEndReasonLose) {
        SKAction *lossAudio = [SKAction playSoundFileNamed:@"failureAudio.caf" waitForCompletion:NO];
        [self runAction:lossAudio];
    }
}
El Tomato
  • 6,479
  • 6
  • 46
  • 75
  • I'm no game dev, but measuring the velocity sounds like the right way to do it. Maybe decrease your velocity check to -5000 if 2000 is a normal velocity. – Millie Smith Feb 28 '14 at 14:32
  • for the "death" part, just check if the player's position.y < 0 + sprite.size.height so that the character will be entirely off screen before the game ends – user2277872 Feb 28 '14 at 14:35
  • @user2277872 what if he hits the floor? – Millie Smith Feb 28 '14 at 14:36
  • that's where you have to do the collision between the floor and the character, and find the calculations to keep him up above the floor – user2277872 Feb 28 '14 at 14:37
  • imageine this: player is a sprite, floor is a sprite, and whatever other obstacles you have in your game is sprite(s). If the user hits the floor sprite, you have to keep him up by figuring out how; same with any other obstacle, but with free falling, you just have to find the y position of the character on the screen. when y = 0, it is at the bottom, meaning that its "off screen" so he dies.. – user2277872 Feb 28 '14 at 14:39
  • Millie, no, that won't work. I'll see if user2277872's advice will work. One measure that has just come up to my mind is saving NSDate when the first negative velocity occurred and then seeing if a negative velocity happens 1 or 2 seconds later. Hmm... Mario Brothers is still phenomenal. – El Tomato Feb 28 '14 at 14:47

1 Answers1

2

Super Mario Bros was a tile-based game: the screen was divided up into a number of square regions each of which being represented by a value. Each tile would have a separate sprite blitted to that region of the screen depending on the tile id, and based on that tile's properties Shigeru et al could determine if mario could stand on it, if it would hurt him or if he was free to fly. There's no magic to this, you just have to check where he is!

If you aren't concerned with the damage your Mario will take (i.e can he land a jump from any height as long as it is onto solid ground) this is easy: If his y position is ever lower than the lowest solid platform in your world, he has died:

  • Ignore velocity; check y position.

If you don't want him to survive a jump from the top of a building, you need to look at his velocity: Is he travelling fast enough that the force of impact would end his life?:

  • Ignore y position; check velocity

How do you know he is on a platform? A physic node?

Honestly, you can put a 'floor' plane stretching your world and anchor it at the bottom of your scene to catch dying plumbers and it won't impact performance - infact it will be more efficient than running these checks in your Update method.

Edit to add

Don't bother with intersections, -(void)didBeginContact:(SKPhysicsContact*)contact will alert you to any collision that occurred as long as you are a delegate. Skip the update loop completely: this will trigger for any collisions and won't be missed

davbryn
  • 7,156
  • 2
  • 24
  • 47
  • Thanks, but seeing character's position is not going to do it. I already said it. – El Tomato Feb 28 '14 at 23:53
  • Why won't that work? Use the delegation method and you won't miss the contact. You are testing for object intersection improperly and at the wrong time. What was the problem? – davbryn Mar 01 '14 at 00:28