Stopping time in godot 4.2.1

Godot Version

4.2.1

Question

I’m trying to achieve something that most of you may not have attempted before—implementing a time stop effect in Godot, similar to what’s seen in JoJo’s Bizarre Adventure. I’m having trouble getting everything to come to a complete stop. I can create an area of effect, but when it comes to applying the effect, I only get partial results. The speed of the player or object slows down, but doesn’t come to a full stop. I also need objects, like bullets, to freeze and then resume their previous motion.

Here is the script responsible for triggering and the func causing the effect on my player.

extends RigidBody3D

@export var blast_radius: float = 10.0
@export var freeze_duration: float = 5.0
@onready var radius_area: Area3D = $BlastRaidus
@onready var timer: Timer = $Timer

func _ready():
	# Ensure the Timer is properly connected
	if $Timer:
		var callable = Callable(self, "_on_fuse_timeout")
		if not timer.is_connected("timeout", callable):
			timer.connect("timeout", callable)
			print("Debug: Timer connected successfully.")
		else:
			print("Debug: Timer already connected.")
	else:
		push_error("Error: Timer node not found.")

	# Validate the radius_area node
	if not radius_area:
		push_error("Error: Radius Area3D not found. Ensure it is properly set up.")
	else:
		print("Debug: Radius Area3D is ready.")

func _on_fuse_timeout():
	print("Debug: Fuse triggered. Freezing objects in blast radius.")
	if not radius_area:
		push_error("Error: Radius Area3D not found.")
		return

	var bodies = radius_area.get_overlapping_bodies()
	print("Debug: Detected %d objects in blast radius." % bodies.size())

	for body in bodies:
		print("Debug: Processing object: %s" % body.name)
		freeze_object(body)

	print("Debug: Grenade cleanup initiated.")
	queue_free()

func freeze_object(body: Node) -> void:
	print("Debug: Attempting to freeze object: %s" % body.name)
	
	if body.has_method("freeze"):
		body.freeze(freeze_duration)
		print("Debug: %s frozen for %.2f seconds." % [body.name, freeze_duration])
	elif body is RigidBody3D:
		print("Debug: Freezing rigid body: %s" % body.name)
		convert_to_static(body)
	else:
		print("Warning: %s does not support freezing." % body.name)

func convert_to_static(body: RigidBody3D) -> void:
	print("Debug: Converting RigidBody3D %s to StaticBody3D." % body.name)
	
	# Create StaticBody3D and copy properties
	var static_body = StaticBody3D.new()
	static_body.global_transform = body.global_transform
	static_body.collision_layer = body.collision_layer
	static_body.collision_mask = body.collision_mask

	# Replace RigidBody3D with StaticBody3D
	var parent = body.get_parent()
	if parent:
		parent.remove_child(body)
		parent.add_child(static_body)
		print("Debug: StaticBody3D created for %s." % body.name)
	else:
		print("Error: Parent node not found for %s." % body.name)
		return  # Exit to avoid further errors

	# Create and add the timer to the scene tree
	var revert_timer = Timer.new()
	revert_timer.wait_time = freeze_duration
	revert_timer.one_shot = true
	revert_timer.connect("timeout", Callable(self, "_revert_to_rigid").bind(static_body, body))
	
	# Ensure the node is inside the scene tree before adding the timer
	if is_inside_tree():
		add_child(revert_timer)
		revert_timer.start()
		print("Debug: Timer added to scene tree and started for %s." % body.name)
	else:
		print("Warning: Node not in scene tree. Waiting for ready.")
		await_to_tree(revert_timer)

func await_to_tree(timer: Timer) -> void:
	# Wait for the node to be added to the scene tree
	await self.ready
	add_child(timer)
	timer.start()
	print("Debug: Timer added to tree after waiting.")

func _revert_to_rigid(static_body: StaticBody3D, original_body: RigidBody3D) -> void:
	print("Debug: Reverting StaticBody3D %s back to RigidBody3D." % static_body.name)
	var parent = static_body.get_parent()
	if parent:
		var new_rigid_body = RigidBody3D.new()
		new_rigid_body.global_transform = static_body.global_transform
		new_rigid_body.collision_layer = static_body.collision_layer
		new_rigid_body.collision_mask = static_body.collision_mask

		parent.remove_child(static_body)
		parent.add_child(new_rigid_body)
		print("Debug: RigidBody3D restored for %s." % static_body.name)
	else:
		print("Error: Parent node not found for StaticBody3D %s." % static_body.name)



And this is the func for how it should behave for the players. As I mentioned, I’m trying to make it so that when the time stop ends, all moving items (including the player and objects) will return to their original velocity and continue moving as they were before the time stop.

# =====================
# Freeze Object Function
# =====================
func freeze_object(body: Node) -> void:
	print("Debug: Attempting to freeze object: %s" % body.name)

	if body is Player:  # Handle player freezing
		body.freeze(freeze_duration)
	elif body is CharacterBody3D:
		print("Debug: Freezing CharacterBody3D: %s" % body.name)
		if body.has_method("freeze"):
			body.freeze(freeze_duration)
		else:
			print("Warning: %s does not implement freeze method." % body.name)
	elif body is RigidBody3D:
		print("Debug: Freezing rigid body: %s" % body.name)
		convert_to_static(body)  # Call the function to convert to StaticBody3D
	elif body.has_method("freeze"):
		print("Debug: Freezing custom object: %s" % body.name)
		body.freeze(freeze_duration)
	else:
		print("Warning: Object %s does not support freezing." % body.name)

func convert_to_static(body: RigidBody3D) -> void:
	# Convert the RigidBody3D to a StaticBody3D for freezing
	var static_body = StaticBody3D.new()
	static_body.global_transform = body.global_transform
	static_body.collision_layer = body.collision_layer
	static_body.collision_mask = body.collision_mask

	# Replace the RigidBody3D with StaticBody3D
	var parent = body.get_parent()
	parent.remove_child(body)
	parent.add_child(static_body)

	# Start timer to revert back to RigidBody3D
	var timer = Timer.new()
	timer.wait_time = freeze_duration
	timer.one_shot = true
	timer.connect("timeout", Callable(self, "_revert_to_rigid").bind(static_body, body))
	add_child(timer)
	timer.start()
	print("Debug: Converted %s to StaticBody3D." % body.name)

func _revert_to_rigid(static_body: StaticBody3D, original_body: RigidBody3D) -> void:
	# Revert StaticBody3D back to the original RigidBody3D
	var parent = static_body.get_parent()
	var new_rigid_body = RigidBody3D.new()
	new_rigid_body.global_transform = static_body.global_transform
	new_rigid_body.collision_layer = static_body.collision_layer
	new_rigid_body.collision_mask = static_body.collision_mask

	parent.remove_child(static_body)
	parent.add_child(new_rigid_body)

	print("Debug: Reverted StaticBody3D back to RigidBody3D.")


# Freeze the player

func freeze(duration: float) -> void:
	if is_frozen:
		print("Player is already frozen.")
		return

	is_frozen = true
	set_physics_process(false)  # Stop physics calculations
	Input.set_mouse_mode(Input.MOUSE_MODE_CONFINED)  # Restrict input
	set_process_input(false)  # Disable input processing


	# Create a timer to unfreeze
	var timer = Timer.new()
	add_child(timer)
	timer.one_shot = true
	timer.wait_time = duration
	timer.connect("timeout", Callable(self, "unfreeze"))
	timer.start()

	print("Player frozen for %.2f seconds." % duration)

# Unfreeze the player
func unfreeze() -> void:
	is_frozen = false
	set_physics_process(true)  # Resume physics calculations
	Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)  # Restore input
	set_process_input(true)  # Re-enable input processing
	print("Player unfrozen.") 

What is need to make what i want work? and it possible to do for multiplayer

Please update your post to use preformatted text for code snippets with ```
In the current state this is unreadable.

1 Like

dude thank you i was trying to figure that out