This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Moving platforms / movable objects

Moving platforms / movable objects
by on (#66095)
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.
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


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()

    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

    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

    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..."). :P

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.

by on (#66097)
I haven't implemented this yet, but what I plan to do in order to move the player along with the platform he's standing on is this:

A variable indicates if the player is standing on another object (it will be set when the player and the object collide and the player is on top) and which object it is (an index that points to one of the active objects). Using that I can read from the object's memory how much it moved last time (in absolute pixels - objects that can be stood on have to calculate this and put the result in a specific location) and change the absolute position of the player by the same amount.

That sounds simple enough, and shouldn't screw up the physics because accelerations and speeds are not modified at all.

I'll get back to you on collisions, 'cause I have to go out now.

by on (#66142)
Sounds good, but there's one case in which it will screw up my movement speed-dependant BG collision.
Code:
---+
 W |
 A |
 L |  +-----+
 L |  | PLA |
---+  | YER |-> slowly moving right
      +-----+
    +----------+
<---| PLATFORM | moving left at a higher speed
    +----------+

If the player gets pushed into the left wall while he's moving right bad things will happen.
That's not much of a problem, though. I can just merge platform and player speed like in Method A, but instead of wasting RAM I'd use temporary variables and feed them to the BG collision code. Cool! :)


Ok, what should happen if the player jumps off a moving platform?
I take it that if you wanted to keep the momentum you'd do the following once upon leaving the platform:
Code:
sprite_xspeed = sprite_xspeed + platform_xspeed
sprite_yspeed = sprite_yspeed + platform_yspeed

by on (#66143)
miau wrote:
Sounds good, but there's one case in which it will screw up my movement speed-dependant BG collision.
Code:
---+
 W |
 A |
 L |  +-----+
 L |  | PLA |
---+  | YER |-> slowly moving right
      +-----+
    +----------+
<---| PLATFORM | moving left at a higher speed
    +----------+

If the player gets pushed into the left wall while he's moving right bad things will happen.

From the point of view of the player character, standing on a moving platform going left relative to objects in the background is the same as standing on a stationary platform and having background objects move to the right. So ideally, you should have sprite cels drawn for "bad things" that happen to the player character, such as getting bonked upside the head and falling flat on his face.

by on (#66233)
tepples wrote:
So ideally, you should have sprite cels drawn for "bad things" that happen to the player character, such as getting bonked upside the head and falling flat on his face.

The term "sprite cels" is confusing me, do you mean I should divide the sprite into smaller regions and check where the collision occured?


Anyway, thanks for your advice. I'll be trying to come up with actual code this weekend and will let you know how it went.

by on (#66236)
A "cel" is the term that I have used for the set of tiles that make up a particular frame of a critter's animation, derived from the animation term. For example, each cel of Mario's animation in Super Mario Bros. 3 is made up of eight tiles. The "sprites" are the hardware constructs used to display tile data. It takes four sprites to display the eight tiles of each cel of Mario's body.

by on (#66561)
tepples wrote:
A "cel" is the term that I have used for the set of tiles that make up a particular frame of a critter's animation, derived from the animation term. For example, each cel of Mario's animation in Super Mario Bros. 3 is made up of eight tiles. The "sprites" are the hardware constructs used to display tile data. It takes four sprites to display the eight tiles of each cel of Mario's body.


Neat naming actually... I've been using different awkward terms such as "spriteImage", "spriteFrame" etc for this. Guess I'll follow you on this as soon as I find some time to clean up the variable names in my code :)

by on (#66566)
I tend to call it a metasprite, alongside the idea of a metatile - one object made up of many.

by on (#66714)
Alright, I whipped up some C code to test my ideas.

This doesn't have all of the features I talked about, yet, but it's simple and the collision detection should be pretty fast when converted to 6502 ASM. Currently, the platforms behave like Item-1, 2 and 3 in Mega Man 2. You can stand on them, but also move through them from below.

Here's the source (uses Allegro) and here's a Windows binary. Maybe it will be of use to someone someday.

For now that's all I need, so I'll leave it at that and get back to it when solid objects become a necessity.

by on (#66804)
I just want to say thank you for offering the C source. That gave ideas on how to eject objects for my current project.

My previous attempts was, well, I prefer not saying more! ;;^_^

by on (#66815)
Glad you found it to be useful, Banshaku. It seems to translate well to 6502 ASM, but I don't claim it's the best way to do it. Anyone is welcome to modify/improve/extend the code or provide other ideas.


tokumaru wrote:
I'll get back to you on collisions, 'cause I have to go out now.

Tokumaru, I'd still be interested in hearing your take on collisions. I haven't yet figured out a decent way to handle them, so it would surely come in handy for me or others who discover this thread. If it's not too much of a hassle for you, that is. :)

by on (#66817)
miau wrote:
Glad you found it to be useful, Banshaku. It seems to translate well to 6502 ASM, but I don't claim it's the best way to do it. Anyone is welcome to modify/improve/extend the code or provide other ideas.


I didn't do exactly the same but just by seeing the C code, it helped me to think differently. Especially with the re-factored code with a better camera approach proposed by Tokumaru. Maybe my code is still not great but the code is getting better.

When you first write a game engine and have no background on game engine theory, the solution you may find are not always optimum since you're re-inventing the wheel without understanding the complete domain at hand. This is my issue at the moment and that bring quite some funky code ;;^_^ But some of that craziness do pay in the end since I learned to try ideas and code them in a language that is maybe not as easy as C to express yourself when you use it on a very irregular basis.

After thinking about Concrete man stage, I remembered that some moving platform exist near the end of it (...). So I will have to figure out a solution too about that issue. But they are quite simple in that stage thought. They either go up or down depending on the arrow on the platform.

by on (#66832)
miau wrote:
Tokumaru, I'd still be interested in hearing your take on collisions. I haven't yet figured out a decent way to handle them

Really? Everything seems to work so well in your demo... What exactly are you not happy with?

by on (#66857)
Well, I'm not even sure if my current method is any good, it basically goes like this:
The platform and player keep their Y-position of the previous frame in memory. If their collision boxes overlap, it is checked whether the player was above the platform in the previous frame. If so, he's ejected upward and the "standing on ground" flag is set.

It is a very dumbed down version of what I originally had in mind since it only handles landing on top of a platform.

Before that I've been trying to come up with code that checks for collisions on all sides (like SMB seems to do for its platforms) which always resulted in a buggy mess.