Godot Version
4.6.stable
Question
I have had an amazing time working in Godot so far, but despite multiple videos, reading over the documents over and over, and attempts at writing code for it, I cannot wrap my head around how custom signals work.
I understand the pieces of it:
#This creates a new signal
signal signal_name
#and I know something like this would send the signal out to other nodes
func _process()
signal_name.emit()
But what I’m really struggling to figure out is how a different node with a completely different script can read this signal. I understand it involves using connect() in some way?
I know there’s the thing in the inspector to connect signals to other nodes but I’d rather avoid putting in code that breaks if a node happens to be deleted later.
As of right now I have a top-down game where you can push different types of boxes around. It’s pretty much just that as of right now.
What I want is when certain boxes are pushed, different things happen. Like, one that’s a bomb and explodes after being pushed, or one that crumbles to pieces after being pushed for a certain amount of time.
Basically, I want the player to send a signal to the box when the player is pushing it, which I feel like should be way simpler than I’m making it out to be.
Below is my current player script.
#The player script (in case that wasn't obvious)
extends CharacterBody2D
@export var speed = 64
@export var player_animated_sprite : AnimatedSprite2D
var outer_force := Vector2.ZERO
const PUSH_FORCE := 16
const MIN_PUSH_FORCE := 8
func _physics_process(_delta):
var direction = Input.get_vector("left", "right", "up", "down")
print(direction)
velocity = (direction * speed) + outer_force
if velocity.x > 0:
player_animated_sprite.play("right")
if velocity.x < 0:
player_animated_sprite.play("left")
if velocity.y > 0:
player_animated_sprite.play("down")
if velocity.y < 0:
player_animated_sprite.play("up")
move_and_slide()
#this is what detects and allows the player to push boxes
for i in get_slide_collision_count():
var c = get_slide_collision(i)
if c.get_collider() is RigidBody2D and c.get_collider().is_in_group("box"):
var push_force = (PUSH_FORCE * velocity.length() / speed)
c.get_collider().apply_central_impulse(-c.get_normal() * push_force)
#I know c.get_collider() is the box node so I feel like I could send the signal here somehow
And this is my current script for the boxes. It feels like much more of a mess but I assume I would put my connect into some kind of function here, but how do I get the script to know the signal?
extends RigidBody2D
var previous_velocity : Vector2 = Vector2.ZERO
var snap_timer := 0.1
@export var sprite_box : AnimatedSprite2D
@export var sprite_collision : CollisionShape2D
enum Type { WOODEN, METAL, ICE, BOUNCE, STONE, BOMB }
@export var box_type : Type
func _ready():
#I know this is ugly and I will probably switch to making a box class for all the different types once I understand classes a bit better
match box_type:
Type.WOODEN:
physics_material_override.bounce = 0
physics_material_override.friction = 0.8
physics_material_override.absorbent = true
physics_material_override.rough = true
mass = 2.0
linear_damp = 16
sprite_box.play("wooden")
Type.METAL:
physics_material_override.bounce = 0
physics_material_override.friction = 1
physics_material_override.absorbent = true
physics_material_override.rough = true
mass = 4.0
linear_damp = 16
sprite_box.play("metal")
Type.ICE:
physics_material_override.bounce = 0
physics_material_override.friction = 0
physics_material_override.absorbent = true
physics_material_override.rough = false
mass = 0.5
linear_damp = 0.0
sprite_box.play("ice")
Type.BOUNCE:
physics_material_override.bounce = 1
physics_material_override.friction = 0
physics_material_override.absorbent = false
physics_material_override.rough = false
mass = 1.0
linear_damp = 0.05
sprite_box.play("bubble")
Type.STONE:
physics_material_override.bounce = 0
physics_material_override.friction = 1
physics_material_override.absorbent = false
physics_material_override.rough = true
mass = 15.0
linear_damp = 16
sprite_box.play("stone")
Type.BOMB:
physics_material_override.bounce = 0
physics_material_override.friction = 0.8
physics_material_override.absorbent = true
physics_material_override.rough = true
mass = 1.0
linear_damp = 16
sprite_box.play("bomb")
contact_monitor = true
max_contacts_reported = 4
func _physics_process(delta):
#this is just meant to snap the block into a grid if it isn't moving for some time. I would happily take advice on how to clean it up if have any.
if sleeping:
global_position = snapped(global_position,Vector2(2,2))
if snap_timer <= 0 and linear_velocity != Vector2.ZERO:
linear_velocity = Vector2.ZERO
snap_timer = 0.1
else:
snap_timer -= delta
else:
snap_timer = 0.1
#I think here I would have some kind of function which activates once the box is being pushed? But I don't quite understand where or how I should put connect() into it.