• 2D
  • How to properly move Rigidbody2d in kinematic mode?

Hi,

I want to switch the behaviour of a Rigidbody2d node from kinematic to rigid and vice versa. Currently I am trying out 3.1 beta2.

What confuses me however, is how to properly move the rigidbody, when in kinematic mode. What i find is, that i should be altering the position directly, which is what is stated one should not do, reading from the documentation.

After debugging the behavior of the body. I found that It looks like, once in kinematic mode, the body's state is forced set to sleeping (though cansleep is false), and the _integrateforces function is not called. Applying forces or impulse won't move the body, so altering the position(setposition/setglobal_position) is all that's left. And once I do that, integrate is called, the body moves and is interacting with other bodies in the scene.

https://docs.godotengine.org/en/latest/classes/class_rigidbody2d.html#enum-rigidbody2d-mode

According to the latest doc, it should behave like the KinematicBody2d, but in the rigidbody class, we don't have access to the "move_*" functions , which is the recommended way to use that node type.

Asked already on on the QA site, but I thought I'd add it here as well. https://godotengine.org/qa/39960/how-to-properly-move-rigidbody2d-in-kinematic-mode

You could try setting linear_velocity.

(I don't work with Kinematic though, so I didn't try so far.)

No that actually does not do anything : )

Tried setting the linear velocity in the physics process , via RigidBody2D.set_linear_velocity().

Hi Flonka

rigidbody i think should only be moved as kinematic.

for kinematic just use the example code from

https://docs.godotengine.org/en/3.0/tutorials/2d/2d_movement.html#summary

`extends KinematicBody2D

export (int) var speed = 200

var velocity = Vector2()

func get_input(): velocity = Vector2() if Input.is_action_pressed('right'): velocity.x += 1 if Input.is_action_pressed('left'): velocity.x -= 1 if Input.is_action_pressed('down'): velocity.y += 1 if Input.is_action_pressed('up'): velocity.y -= 1 velocity = velocity.normalized() * speed

func _physics_process(delta): get_input() move_and_slide(velocity)`

Yeah, @Sparrow one would think that is the case, reading from the docs, as i noted in my initial post. However, the move_and_slide/move_and_collide methods, are not available on the RigidBody2D class. And this is the reason for me opening this thread :).

Ok, it seems that setting the mode of RigidBody actually makes it a KinematicBody. But like you already noticed it just doesn't give the useful move/test methods that KinematicBody offers. Therefore I fail to find much use in the mode = Kinematic of RigidBody.

I sometimes use the mode to just move a RigidBody to some static state by settting it to StaticBody (similar to sleep).

Perhaps you tell us the reason why you need to switch from RigidBody to KinematicBody. Then one of us might have another idea to get there.

Oh cool, I did not think to check if the type changed , or perhaps cast it as a KinematicBody2D. I will check out if thats a possibility. Not sure if theres much of a performance imapct in doing so, probably some downside , I guess.

I want to use the mode switch kinematic<->rigid , to be able to first control the node with precise position set from mouse while affecting the physics world ( I guess, the features the KinematicBody2D gives), and then go to pure physics simulation on an event. So it seems to me that using these modes on the rigidbody should be the way to do so.

I see problems typecasting the node from Rigid to Kinematic or vice versa. (Never tried it though.)

One could think of some crazy ideas like using two bodies and toggling visibility & collision masks. In that case I'd propose switching the RigidBody to static before assigning a new transform. It should be possible to use the same script for both nodes if required but variables won't be automatically shared.

But that approach would be a bit complicated and probably be overkill...

a month later

After experimenting myself, I found that the approach that works.

When controlling the RigidBody2D in kinematic mode , one needs to alter the position of the node, in order to have the _integrate_forces called. There, one also needs to update the Physics2DDirectBodyState transform , to not get into problems later on when switching back and forth between rigid mode and kinematic mode.

E.g. for altering the position , you would change the state.transform.origin to be the global position of the node.

  • Bouc replied to this.
    3 years later

    Flonka how can I " update the Physics2DDirectBodyState transform"?

    6 months later

    In case someone else would want to switch between RigidBody2D CHARACTER and KINEMATIC modes.

    When the rigid body mode is KINEMATIC, the global position of the rigid body will be directly setted in the _physics_process() method, this then will trigger the call to the method: func _integrate_forces(state: Physics2DDirectBodyState) of the rigid body.

    This is in the _integrate_forces(state: Physics2DDirectBodyState) call, that the Physics2DDirectBodyState.transform.origin has to be updated with the new global position, so the body state remains sync with the manually setted position.

    In my case, i had to override the _integrate_forces(...) like this :

    func _integrate_forces(state: Physics2DDirectBodyState):
    	if mode != MODE_KINEMATIC:
    		return
    	# In Kinematic mode, the RigidBody2D
    	# global position is updated in _physics_process(),
    	# then RigidBody2D state transform.origin needs
    	# to be update with global_position to insure
    	# world position sync.
    	state.transform.origin = global_position