Two-pixel gap between moving platform and player

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Brandon
:warning: Old Version Published before Godot 3 was released.

When the player is on a vertically moving platform that is going down, there is a two pixel gap between the player and the platform. It’s not there when moving up or horizontally.

The player and platform are both kinematic bodies and behave exactly the same if the platform is changed to a static body.

Everything I’ve tried has either done nothing or caused the player to stutter due to the platform moving away and then the player falling a short distance.

Attempting to manually alter the position of the player (set_pos()) after it does movement calculations still causes it to reset back to two pixels above the platform.

I printed the positions of the platform and player when moving up and moving down, so I know the distance between the origins of the two when moving down is almost exactly two pixels larger than when moving up.

I can fudge the sprite positioning during this situation to make the gap appear to vanish, but it still exists. I will do this until a solution is found (it isn’t worth it for me to put any more hours than I already have into it). Can anyone figure out exactly why it’s behaving this way, even if you don’t have a solution?

Relevant player code:

func _ready():
    velocity = Vector2(0, 0)
    raycast = get_node("RayCast2D")
    raycast.add_exception(self)

func on_ground():
    return raycast.is_colliding()

func _fixed_process(delta):
    check_input() #left/right movement

    if (on_ground()):
        surface = raycast.get_collider()
        velocity.x += surface.velocity.x
        if (surface.velocity.y > 0):
            velocity.y += surface.velocity.y
    else:
        velocity.y += GRAVITY
        surface = null

    var motion = velocity * delta
    motion = move(motion)

    if (is_colliding()):
        var n = get_collision_normal()
        motion = n.slide(motion)
        velocity = n.slide(velocity)
        move(motion)

Relevant Platform code:

func _ready():
    velocity = Vector2(0, SPEED)
    set_fixed_process(true)

func _fixed_process(delta):
    var cur_pos = get_pos()
    if (cur_pos.y >= BOTTOM or cur_pos.y <= TOP):
        velocity.y *= -1

    var new_pos = cur_pos + velocity * delta

    set_pos(new_pos)

The setup with relevant parts highlighted:

Thanks for your help.

:bust_in_silhouette: Reply From: eons

Vertical moving platforms are a pain even with your own engine, you need to consider special situations…

  • If the platform goes up too fast, the character won’t be able to jump.
    This is more or less easy to solve, adding the platform velocity to the jump may solve most cases.

  • If the platform goes down faster than the character it will float a bit or a lot, which is what happens here (even considering the platform velocity, float precision and collision correction issues will appear).
    This is more complicated to solve and need to be considered in the design, a good thing to have is a special grounded state for those platforms, where you can alter the physics mechanics and not mixed with the normal states.

A couple of ideas to try on that special case:

  • Scale up the gravity vector so the character moves down a bit fast while on the platform.

  • Ignore the gravity and use the platform velocity only.

  • Use the platform “travel” value to apply vertical movement on the character while ignoring gravity and velocity.

Some may work, or not, depends a lot on the design.

And don’t worry about faking things (like altering physics rules), you will need to do that to get a good gameplay experience.

You can see in my code that after a bunch of trial-and-error, I went with the “Only use gravity when not on a surface and use the platform velocity instead,” which just gives me the hovering problem.

I was really close to just not using the physics system at all, but if I was going to do that I was just going to skip using Godot altogether so I could have better control over everything.

My biggest worry is that I’m not smudging physics, I’m just smudging how it looks. The collision box now extends a couple pixels above the sprite, which could be a problem.

Thinking about it later, I’m realizing that it really shouldn’t be a problem because the chance of something hitting you in that two-pixel gap is tiny and the chance of someone noticing is even smaller.
Even better: I don’t think my game is even going to have floating platforms. I was just making a basic platforming thing and got caught up trying to fix this.

Brandon | 2017-02-15 00:15

:bust_in_silhouette: Reply From: k4sma

for me it was settings with the camera2d. try changing the settings for the camera