Push object jitter

4.3 stable

Weird jitter on object push

Hi everyone ! I’m implementing a push object mechanic in my game, but i’ve noticed a strange jitter while pushing the object. The fixed fps rate in project settings is set to 60 fps, and my moniter maximum refresh rate is 75 hz.

This is the code that is responsible for pushing the item :

player.gd

func _physics_process(delta: float) -> void:

	if push_ray.is_colliding(): ## push_ray is a raycast
		_crate = push_ray.get_collider() as Crate
		if _crate.is_on_floor() && action_handler.move().x != 0.0:
			_crate.slide(data.push_force * orientation * 15.0 * delta) # 15.0 is a speed mutiplier
	else:
		if _crate:
			_crate.velocity.x = 0.0
			_crate = null
	
	move_and_slide()

And this is the code in Crate.gd :

extends CharacterBody2D
class_name Crate

@export var gravity: float = 1500

func _physics_process(delta: float) -> void:
		velocity.y += gravity * delta
		
		if !is_on_floor():
			velocity.x = 0.0
		
		move_and_slide()


func slide(vector: float) -> void:
	velocity.x = vector

This is a video that shows this issue, at 60fps (Physics Ticks per second) :

And I tried to set Physics Ticks per second to 240 fps, and here is the result :

It’s better, but at the cost of huge performance usage.
I’m currently lost, as i’ve tried many things vainly to make the crate move smoothly.
Can you help me please ?

I’ve also attached pictures of my settings :




Is it off the table to make your crate a RigidBody2D? you could even lock rotation

Your script is very jitter-prone, setting velocity to push force (thus forcing it out of the touch zone) when touching, and zero when not. You would do better to leverage the physics system more; even getting slide collisions for it’s depth would be a better “push” value, but I think RigidBody2D would suite best.

1 Like

I tried rigidbody2d earlier, with locked rotation. Got also a little jitter …
Hmm quite strange ?

I’m going to re-try implementing rigid body, and i will communicate you my results.
And i’ll fix my code too :slight_smile: .
Thank you !

@gertkeno
OK. So i’ve tried rigidbody, and the result is better, at 60 physics ticks per seconds.
My new code is this:

player.gd

func _physics_process(delta: float) -> void:
	for i in get_slide_collision_count():
		var collision = get_slide_collision(i)
		var collision_crate = collision.get_collider()
		if collision_crate.is_in_group("Crate"):
			collision_crate.apply_central_impulse(-collision.get_normal() * data.push_force * delta)
	
	move_and_slide()

I encounter an issue though :

The crate stops randomly against a tile. How to solve this ? (Sorry to bother you)

Probably a floating point rounding issue, maybe when applying the force you can nudge the block up half a pixel? Very cludgy, but it’s going to be hard to tell a microscopic gap from a great wall; if only we had rounded edges.

Obviously if the floor was a solid plane this wouldn’t happen, but that’s no fun to design levels manually placing collisions like that.

1 Like

Thank you very much for your help :smiley: . I’ll try to lift up a little bit the rigidbody, or try to make rounded collider by using CollsionPolygon2D :+1:

Ok so after a morning of numerous tests, i’ve ended up by using a character body 2d for my crate as its physic behaviour was quite unpredictable with rigidbody2D, and it was stopping against some tiles. Moreover, there was still some jittering.

So i’ve changed its type to characterbody2D and i’ve changed the code a little bit to make it work (I’m currently using a finite state machine) :

player_push_state.gd


func _physics_process(delta: float) -> void:
	player.velocity.x  = action.move().x * data.push_force * delta
	apply_push_force()


func apply_push_force():
	for i in player.get_slide_collision_count():
		var collision = player.get_slide_collision(i)
		var collision_crate = collision.get_collider()
		if collision_crate.is_in_group("Crate"):
			collision_crate.velocity.x = player.velocity.x

As for the crate :

crate.gd

extends CharacterBody2D
class_name Crate

@onready var floor_ray_l: RayCast2D = $FloorRay_L
@onready var floor_ray_r: RayCast2D = $FloorRay_R

@onready var player_ray_r: RayCast2D = $PlayerRay_R
@onready var player_ray_l: RayCast2D = $PlayerRay_L


func _physics_process(delta: float) -> void:
	
	if !_on_floor() or !_contact():
		velocity.x = 0.0
	
	if !is_on_floor():
		velocity.y += 1500 * delta

	move_and_slide()


func _on_floor() -> bool:
	return floor_ray_l.is_colliding() or floor_ray_r.is_colliding()

func _contact() -> bool:
	return player_ray_r.is_colliding() or player_ray_l.is_colliding()


Physics ticks per second is 75, that is the same as my monitor refresh rate, so i’ve managed to get rid of the jitter, which is barely noticeable.
If Physics ticks per second is set to 120, jitter will disappear.

I hope that, if you encounter some day the same issue as me, this article will help you resolve that issue :smiley:

Have nice day !

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.