A few days ago I decided to add support for moving platforms to my platformer engine.
However, my brain is having a hard time coming up with an implementation that's fast and doesn't cause all kinds of havoc.
By moving platform I mean any object that is "solid" and movable within the game world, e.g. blocks that can be kicked or thrown etc, enemies that can be used as platforms like in SMB2 or Gimmick.
I - Collision detection between platforms and sprites
I'm not entirely sure how to handle this efficiently, yet. Code for checking whether two sprites' collision boxes overlap is already available and it's quite fast. Moving platforms would basically be sprites that require more advanced collision checks than that.
II - What happens if a sprite is standing on a moving platform?
There are two ways I can think of to handle this.
First of all, the following is done once per frame.
Method A
Method B
III - What happens if a sprite is pushed into a solid tile by a platform?
Haven't given much thought to this, yet, but here's how I'd attempt it:
So... am I on the right track? Are there any other pitfalls that I am not aware of?
How do you handle this kind of stuff / how do commercial games do it?
Any kind of input is appreciated.
However, my brain is having a hard time coming up with an implementation that's fast and doesn't cause all kinds of havoc.
By moving platform I mean any object that is "solid" and movable within the game world, e.g. blocks that can be kicked or thrown etc, enemies that can be used as platforms like in SMB2 or Gimmick.
I - Collision detection between platforms and sprites
I'm not entirely sure how to handle this efficiently, yet. Code for checking whether two sprites' collision boxes overlap is already available and it's quite fast. Moving platforms would basically be sprites that require more advanced collision checks than that.
II - What happens if a sprite is standing on a moving platform?
There are two ways I can think of to handle this.
First of all, the following is done once per frame.
Code:
update_position:
sprite_x = sprite_x + sprite_xspeed
bgcollision_check_horz() //checking for background collision, ejecting the sprite if it's in a solid tile
sprite_y = sprite_y + sprite_yspeed
bgcollision_check_vert() //same, but for vertical movement
sprite_x = sprite_x + sprite_xspeed
bgcollision_check_horz() //checking for background collision, ejecting the sprite if it's in a solid tile
sprite_y = sprite_y + sprite_yspeed
bgcollision_check_vert() //same, but for vertical movement
Method A
- Change update_position to:
Code:
sprite_x = sprite_x + sprite_xspeed
sprite_x = sprite_x + platform_xspeed
bgcollision_check_horz()
sprite_y = sprite_y + sprite_yspeed
sprite_y = sprite_y + platform_yspeed
bgcollision_check_vert()
sprite_x = sprite_x + platform_xspeed
bgcollision_check_horz()
sprite_y = sprite_y + sprite_yspeed
sprite_y = sprite_y + platform_yspeed
bgcollision_check_vert()
Unfortunately, now sprite_xspeed and sprite_yspeed don't reflect the sprite's absolute movement speed anymore. E.g. background collision will be broken since it uses sprite_yspeed to decide whether the sprite should be ejected upward or downward.
To solve this issue we separate the different kinds of movement speed and add them together before running the original, unaltered update_position.
Code:
sprite_xspeed = platform_xspeed + sprite_xspeed_rest
sprite_yspeed = platform_yspeed + sprite_yspeed_rest
sprite_yspeed = platform_yspeed + sprite_yspeed_rest
That's 2 or 4 additional bytes of RAM per sprite depending on if you use 8-bit (like Super Mario Bros. 3/Super Mario World) or 16-bit speed values (like my engine currently does).
Method B
- Changes of platform speed affect sprite speed directly.
Code:
speed_add(xchange,ychange) //platform speed should only be changed using this function
{
platform_xspeed = platform_xspeed + xchange
platform_yspeed = platform_yspeed + ychange
if(sprite_standing_on_platform) {
sprite_xspeed = sprite_xspeed + xchange
sprite_yspeed = sprite_yspeed + ychange
}
}
speed_add(3,0) //increase platform's x speed by 3
{
platform_xspeed = platform_xspeed + xchange
platform_yspeed = platform_yspeed + ychange
if(sprite_standing_on_platform) {
sprite_xspeed = sprite_xspeed + xchange
sprite_yspeed = sprite_yspeed + ychange
}
}
speed_add(3,0) //increase platform's x speed by 3
This method is slow because of all the checks needed, setting platform speed to an absolute value would require even more awkward calculations while sprite speed cannot be set to an absolute value at all without breaking everything(?). Yup, now that I've written all of this down I realize it's not a good method at all. It just feels a bit closer to the real world where the car, elevator or whatever moves YOU (in b4 "tepples: But in Soviet Russia...").
III - What happens if a sprite is pushed into a solid tile by a platform?
Haven't given much thought to this, yet, but here's how I'd attempt it:
- - the background collision code ejects the sprite and sets flags on where the collision occured (up, down, left or right side of the sprite)
- if one of these flags is set, either...
- - the platform won't try to push/eject the sprite into that direction anymore (platform can move through sprite, boring)
or...
- platform should stop movement in that direction and "rest" on the sprite (multiple objects could be stacked if done properly, interesting!)
So... am I on the right track? Are there any other pitfalls that I am not aware of?
How do you handle this kind of stuff / how do commercial games do it?
Any kind of input is appreciated.