Search code examples
godotgdscriptgodot3

How to make collidable moving platform using KinematicBody2D?


I'm trying to make a levitating platform using KinematicBody2D and when my character (also KinematicBody2D) falls on top the platform stops moving

enter image description here

Code for the platform:

extends KinematicBody2D

export var levitation_speed: float = 1000
var _velocity: Vector2

# for simplicity sake I've only shown the platform moving up
func _physics_process(delta):
    _velocity += levitation_speed * delta * Vector2.UP
    _velocity = move_and_slide(_velocity)

code for the player:

extends KinematicBody2D
class_name Humanoid

var velocity:Vector2
export var gravity_speed=3500
export var jump_speed=-1800
export var horizontal_speed=600

func _physics_process(delta):
    var direction=Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
    velocity.x=horizontal_speed * direction
    
    if(is_on_floor()):
        if(Input.is_action_just_pressed("ui_up")):
            velocity.y+=jump_speed
    
    velocity.y += gravity_speed * delta
    velocity=move_and_slide(velocity, Vector2.UP)

How do I make the player move along the platform no matter the direction it moves in? If this is not possible with KinematicBody2D I'm open to using RigidBody2D

Note: I'm intentionally using _physics_process() & not AnimationPlayer or Tween so if you suggest a work around please involve it


Edit:

Based on the provided answer by @Theraot it sort of works when the player falls on top of platform but fails when the player tries to enter from below as such:

enter image description here

as any good platform in a game, the player should be able to pass through it from underneath


Solution

  • Using move_and_slide_with_snap instead of move_and_slide on the player, should keep it snap to the ground when the ground is moving.

    It needs an snap vector, which you can imagine as a ray that checks for the platform.

    The code would be like this:

    velocity=move_and_slide_with_snap(velocity, Vector2.DOWN, Vector2.UP)
    

    However, after testing this didn't solve the problem at hand.


    global_position

    What we can do is move the platoform without move_and_slide nor move_and_slide_with_snap, but by changing its global_position instead, like this:

    global_position += _velocity * delta
    

    This means that the platform will move ignoring any obstacles (to be clear: it will go through static obstacles), however it can still push the player.

    This solution also allows to enable motion/sync_to_physics however that is not necesary since we would be moving in _physics_process.


    one_way_collision

    I found another way: We can set one_way_collision to true on the collider of the player.

    The player and platform can then still use move_and_slide or move_and_slide_with_snap and both will collide with static obstacles.

    Thus this solution does not require any code change.