Game physic changes after restarting the level

Godot Version

Godot 4.2.2

Question

I’m trying to make a puzzle game that involves moving boxes and precise and trustworthy interaction between them. (I want them to act the same each time the interaction happens)
My problem is that after restarting the level, for some reason the physics change (even if I reposition everything on the exact spot they spawned the first time)
This happens randomly and with seemingly no reason at all, sometimes the blocks get into the place they need fast, and sometimes they take ages.

This is what’s happening, look at the crate on the right the first run and the second run (hovering only makes the sprite bigger)

In case it could help understand the situation, I’ll link both the scene explanation and the full code of the crate.


block_spawner never moves, and it’s a node that I just use to move the box back to its position each time the game starts
Sprite2D and CollisionShape2D do exactly what their name says.
I use fallTimer and hitSfx to make a sound when the block has been falling for too long.
Material menu is a button that I just use to send a signal on hover to make the sprite bigger.
hoverSfx is a sound that plays on hover, and timeOnGround is used to decide when to start rotating the block to free it from being stuck, however I don’t think it works like it’s supposed to (duration is 0.5s)

extends RigidBody2D

var mat:int = 0
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
var falling:bool = false
var tempRotation:float
var savedArea
var notMoving:bool = false
var readyForGame:bool = false
var baseGravity = gravity

var tween:Tween

func _ready() -> void:
	lock_rotation = false
	freeze = true
	resetBlock()
	check_material()

func _physics_process(delta) -> void:
	
	if readyForGame != get_parent().get_parent().get_parent().running: 
		readyForGame = !readyForGame
		if readyForGame: freeze = false
		else: freeze = true
		resetBlock()
		
	if get_parent().get_parent().get_parent().running:
		if notMoving:
			var roundRotation:float = fmod(rotation_degrees, 90.0)
			tempRotation = round(rotation_degrees/90)*90
			if linear_velocity.x + linear_velocity.y < 1 and (rotation_degrees > tempRotation+0.1 or rotation_degrees < tempRotation-0.1) and\
			 $"../timeOnGround".time_left < 0.05 and notMoving:
				rotation_degrees = lerp(rotation_degrees, tempRotation, 0.3)
		
		if linear_velocity.x > 270: linear_velocity.x = 270	
		if linear_velocity.y > 270: linear_velocity.y = 270
		if linear_velocity.x > 40 or linear_velocity.y > 40: 
			if $fallTime.is_stopped() and !falling: 
				$fallTime.start() #Starts a timer that controls fall time
			if $fallTime.time_left <= 0.05 and savedArea == null: 
				falling = true
		notMoving = linear_velocity.x < 2 and linear_velocity.y < 2
		if notMoving and $"../timeOnGround".is_stopped(): $"../timeOnGround".start()
		else: $"../timeOnGround".stop()
func check_material() -> void: 
	if mat == 0: 
		add_to_group("pushable")
		modulate.hex(101010)

func _on_area_2d_area_entered(area):
	if area.is_in_group("ground") and falling: 
		savedArea = area
		falling = false 
		$hitSfx.play()
	if area.is_in_group("jumpPad"):
		linear_velocity.y = -400
	if area.is_in_group("superJumpPad"):
		linear_velocity.y = -600

func _on_area_2d_area_exited(area) -> void:
	if savedArea == area: savedArea = null

func resetBlock() -> void:
	global_position = $"..".global_position
	linear_velocity.y = 0; linear_velocity.x = 0
	rotation_degrees = 0

func _on_material_menu_mouse_entered() -> void:
	if !readyForGame:
		$"../hoverSfx".play()
		resetTween()
		tween.tween_property($Sprite2D, "scale", Vector2(1.2,1.2), 0.05).set_ease(Tween.EASE_IN_OUT)

func _on_material_menu_mouse_exited() -> void:
	if !readyForGame:
		resetTween()
		tween.tween_property($Sprite2D, "scale", Vector2(1.0,1.0), 0.05).set_ease(Tween.EASE_IN_OUT)
	
func resetTween() -> void:
	if tween:
		tween.kill() # Abort the previous animation.
	tween = create_tween()

I have no idea in why this happens, any help is appreciated.
TLDR: blocks get unstuck fast the first time i play a level, get unstuck slow the second time i play and it goes randomly after that
Thanks in advance

Are you using a deterministic physics engine? I doubt Godot’s default physics engine is deterministic.

I’ve seen Rapier, but have not yet used it myself, could require re-writing most components of your game.

1 Like

I’m doing this game for a game jam and I still need to do a lot of things for my game.
I’ll definitely get this engine for new projects, but I don’t think I have the time to rewrite most components.
Gonna take a look at that after the jam tho

1 Like