RigidBody2D inconsistent response to apply_impulse

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

I’m seeing inconsistent rotation behavior using apply_impulse() to a RigidBody2D. Using this simple code:

extends RigidBody2D

func _ready():
	set_process_input(true)
	apply_impulse(Vector2(-10, 0), Vector2(0, -200))

func _input(event):
	if event.is_action_pressed("ui_select"):
		apply_impulse(Vector2(-10, 0), Vector2(0, -200))

As you can see, the apply_impulse() has an offset, so the body should rotate in response. However, when the scene is run, the body does move upward but without any rotation. The same apply_impulse() when run from the _input() function does result in rotation.

I noticed this because I had similar inconsistent rotation response when using apply_impulse() in other functions. Anyone run across this before?

How much is the angular damp? maybe is nullifying the impulse on fixed process.

eons | 2017-06-29 22:27

No angular damp. And the impulse applied by _input()doesn’t get damped at all. Even with damping, you’d think there’d be some rotation, but it’s exactly 0.

kidscancode | 2017-06-29 22:51

And the shape is not a circle? I have noticed something weird (like no change on initial rotation) with bouncing circles but didn’t tested much.

eons | 2017-06-30 11:35

:bust_in_silhouette: Reply From: wombatstampede

Problem may be that you put the apply_impulse in _ready()

I experienced oddities when working with 3D Physics and not letting it “settle down” at least some fractions of a second directly after scene start. (Usually I give it 0.1sec). Can be that this is similar in 2D.

You can use a one-time timer or a counter (add up deltas) in _fixed_process for delaying the initial impulse.

For example:

extends RigidBody2D

var initialWait = 0.1

func _ready():
	set_process_input(true)
	set_fixed_process(true) 

func _fixed_process(delta):
	if initialWait>0:
		initialWait=initialWait-delta
		return

	set_fixed_process(false)

	apply_impulse(Vector2(-10, 0), Vector2(0, -200))

func _input(event):
    if event.is_action_pressed("ui_select"):
        apply_impulse(Vector2(-10, 0), Vector2(0, -200))

I thought of this, but the _ready() example was just to demonstrate the problem. It also occurs when the impulse is applied in another function called during the game.

kidscancode | 2017-06-30 16:21

:bust_in_silhouette: Reply From: luislodosm

Wait one frame to get rid of the problem with apply_torque_impulse

Example for instantiating a spinning axe:

export var axe_scene: PackedScene
const IMPULSE = 300
const TORQUE  = 100000

func throw_axe():
	var axe = axe_scene.instance() as RigidBody2D
	get_tree().get_root().add_child(axe)
	axe.position = global_position
	axe.apply_central_impulse(IMPULSE)
	yield (get_tree(),"idle_frame")
	axe.apply_torque_impulse(TORQUE)

This has worked for me. Thanks!

gapizaver | 2021-02-11 17:45

I found this bug today. My work around is to use call_deferred().

extends RigidBody2D

export var impulse: Vector2 = Vector2(100, -300)
export var torque: float = 200


func _ready() -> void:
	call_deferred("apply_impulse", impulse)
	call_deferred("apply_torque_impulse", torque)

arthurZ | 2021-12-27 21:45