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