I have an unreleased platformer protoype with platforms that move both horizontally and vertically. The logic I have is pretty hacky and doesn't handle some situations, but I should just be able to put a few more cases in and it'll be ok.
I forbid the player ever being inside a wall/platform (simulation is required to always keep them out). However, I have made the game design decision that if a player gets crushed by platforms, it's ok to kill them, rather than fully resolve the physics and prevent that (e.g. player crushed between platform and terrain).
Also, all of this stuff is designed so that I can get high performance, as, for reasons, I may need to simulate something like 20,000 players and 5,000 platforms per frame at 60fps.
Here is the simulation logic:
Every tick:
- iterate over all platforms and try to move them. if the new location overlaps another platform, don't move (think some of the Braid puzzles with vertical "platforms" blocking horizontal platforms)
- iterate over all the players
- save their current position to variable 'before-moved', which is supposed to be a place where the simulation can put them if all else fails that won't be colliding with terrain. (however, if a platform moved onto them, it won't be valid, so we have to fix that below)
- if they were standing on a platform last frame (stored in a variable on the player)
- move them by the same distance that platform moved this tick (many ways to do this; I save the location of all objects at start of tick, so vector moved is 'plat.loc - plat.prevloc')
- up to four times (arbitrarily chosen, likely to detect all platforms and avoids infinite loop)
- check if the player is colliding with a platform (the first time through this can't be the one they were standing on, but they might have been carried onto another one, or another might have moved onto them, and then once this loop repeats all bets are off)
- if the player's feet are less than two pixels below the platform, move them up to stand on it (this limits platfor upwards movement to only 2 pixels/frame, but that's plenty)
- else if the player's center is left of the platform's center, push the player left to not overlap platform
- else push the player right to not overlap platform
- bug: if a platform moves down onto the player, they teleport to the left or right side of the platform since above doesn't handle that case
- store the new "pushed" player location to 'before-moved' (because the old 'before-moved' point is definitely colliding with a platform, and we're trying to find a spot that isn't)
- note that you might get moved one way by platform A, then the other way by platform B, then you're back colliding with platform A and it repeats and would infinite loop if we didn't have a max iteration count; this way it times out, and probably the logic below makes the player die in this case
- handle player input for movement & jumping (if jumping add in velocity from any platform they're standing on)
- try to move the player from their new position by their velocity delta, checking for collision against terrain & platform
- just check for discrete overlaps at end point; if motion vector is far, check for overlaps at multiple points along path and stop early
- this and the following tests allow the player to stick their feet in the ground a little, and pushes them back up if they do; this allows uneven terrain of a few pixels to be well-behaved
- if the above doesn't find a safe point
- try moving as if their Y velocity=0 (works if they're hitting floor or ceiling)
- try moving as if their X velocity=0 (works if they're hitting a wall)
- if you had slopes you would want to detect the slope they're colliding with and try moving them along that; the above is just a hard-coded assumption that all "slopes" are vertical or horizontal
- try leaving them at the place they were before we added velocity
- try moving them back to the location in before-move, which hopefuly isn't in terrain/platforms
- (This is necessary when a player rides a platform into a wall, it returns them to where they were before the platform carried them. This works for me because my platforms don't move > 1pix/tick; for faster platforms you might see the player is more than 1 pixel out from the blocking terrain, so you might want to search along the path from 'before-moved' to after moved to find the furthest point the player can safely reach.)
- if the player is inside terrain or a platform at this point, kill them.
- check if the player is NOW standing on something, and if so store what they're standing on in the standing-on variable. I believe I allow the player to be a little above the ground (as long as they're moving down), and I teleport them down to the ground in that case (i don't have to handle the case that the player has overshot and their feet are in the ground, because if that happens and doesn't get fixed up, the previous bullet point just killed them)