+1 vote

I am creating a 2D game. At one point of the game my player jumps onto a moving object. The first time the player lands on the object, it is fine as the player stays on top of the body collision object. However then the collision objects moves vertically upward, but then the player is falling through. How can I prevent this from happening?

Player is a Kinematic Body 2D
Moving with moveandslide
Collision object is Collision 2D
Collision shape is a line segment

asked Jan 19 in Engine by bribat123 (31 points)

You'll need to be more specific about your setup. It's clear the player is a KinematicBody2D, but what is the floor? "Collision 2D" is not a node type.

Is it also a KinematicBody2D? If so, how are you moving it?
Is it a StaticBody2D? If so, you will need to change, as static bodies can't be moved.

Also, you'll probably need to switch your player's movement to move_and_slide_with_snap(), as that will help keep you "stuck" to the object when it moves vertically.

The player is a KinematicBody2D. I use moveandslide to move it because moveandslidewithsnap causes isonfloor to stop working.

The floor body is a StaticBody2D. The body does not move. However the body is a parent of a CollisionShape2D that moves up and rotates a bit during an animation sequence.

I want the player to be able to stay on the CollisionShape2D as it moves. Is it possible or not?

move_and_slide_with_snap() does not break is_on_floor() unless you're doing it wrong.

Animating the collision shape without moving the body is still moving it. I honestly can't say I've ever tried such a thing, but I would not expect it to work well.

I've done a lot of experimenting with methods of handling moving platforms. To my mind, the best solution is this one: http://kidscancode.org/godot_recipes/2d/moving_platforms/

1 Answer

0 votes
Best answer

A KinematicBody must be moved through code. If you want your kb to be affected by other physics objects and gravity (without handling gravity in your player script), then consider using a RigidBody.

If you want to keep your player a KinematicBody, then you'll need a way to apply the platform velocity to your own player velocity. I suggest you add a circular Area2D at the feet of your character. Then, when is_on_floor() returns true, call get_overlapping_bodies() on your area (make sure the area collision layer is the same as the moving platforms!). Then, iterate on those bodies and apply their velocity to yours.

Implementation for platforms moving on the y axis:

extends KinematicBody2D
[...]
var _player_velocity: Vector2 = Vector2(0, 0)

func _process(delta) -> void:
    [...] # adjust velocity based on input
    if is_on_floor():
        var highest_y = -INF
        for moving_platform: KinematicBody2D in $FootArea.get_overlapping_bodies(): # only check moving platforms layer
            highest_y = max(highest_y, moving_platform.velocity.y) # moving platforms need to expose their velocity
        _player_velocity.y += highest_y # apply vertical platform movement
    [...]
    _player_velocity = move_and_slide(_player_velocity)

The highest_y logic is for the case where your character is in the middle of two moving platforms.

answered Jan 23 by Bernard Cloutier (376 points)
selected Jan 23 by bribat123

Thanks for all the responses! The issue has been resolved.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.