How to stop movement of all objects, when character collide with just one object?

Godot Version

4.3

Question

Hi everyone. I’m trying to stop movement of all objects (built from the same kind of node Pipelines.tscn) when a character collide with just one object.

To explain a little the project, it is a Flappy bird clone. The player doesn’t move, it just jumps, like it is shown down bellow

extends CharacterBody2D
var speed = 300
var gravity_constant = 100
var JUMP = -3000

func _physics_process(delta):
	jump()

func jump():
	if Input.is_action_just_pressed("ui_up"):
		velocity.y = JUMP
	else:
		gravity()
		
	move_and_slide()
	
func gravity():
	velocity.y = gravity_constant	
	move_and_slide()

Instead of that, only the pipes moves. Those are build from an instantiate() method, taking the values of Pipelines scene into the Main scene, like it is shown bellow.

Main.gd

extends Node2D
var pipe_node  = preload("res://Scene/pipelines.tscn")
var screen_max_height = DisplayServer.window_get_size()

func spawn_pipes(x_size, y_size, x_position, y_position):
	var pipe = pipe_node.instantiate()
	pipe.create_pipe(x_size, y_size)
	pipe.position = Vector2(x_position, y_position)
	add_child(pipe)
	
#Create a pair of pipeline, from the lower pipeline to the higher one.
func spawn_double_pipes(pipe_location):
	var random_height_size = randi() % 668 + 50
	var gap = 200
	var bottom_size = (screen_max_height.y - random_height_size) - gap
	var bottom_height_position = screen_max_height.y - bottom_size
	var pipe_width = 100
		
	spawn_pipes(pipe_width, random_height_size, pipe_location, 0)
	spawn_pipes(pipe_width, bottom_size, pipe_location, bottom_height_position)```

To solve this issue, I tried the following solution inside Pipelines.gd, However it just stop just one object, instead of stop all object’s movement.

func stop():
	speed = 0

func movement(delta):
	var collision_info = move_and_collide(delta * velocity)
	velocity.x = speed
	
	if collision_info:
		stop()

Is there a way to affect all objects movement?

1 Like

Two ways I could think of off the top of my head:

  1. when the collision is detected emit a signal. connect that signal to all relevant nodes. have all those nodes stop on recieving that signal.

  2. make a group. put all relevant nodes in that group. have a function in those nodes that stops them. on collision iterate through the group and call that stop function on each.

1 Like

Thanks ! As I’m a newbie, it was hard to understand what you were proposing. So after a time researching a while about signals and groups I found the following solution.

  1. First of all, CharacterBody2d was changed into Area2d in pipelines.gd

  2. As this node is not CharacterBody2d anymore, move_and_collide() is not longer available, so now the movement is given through position property.

pipelines.gd

extends Area2D
func movement(delta):
	position.x += -speed * delta
  1. Groups was created using code in Main.gd adding pipe.add_to_group("pipes") as shown below
# Create a pipeline, allowing to specify the size and location.
func spawn_pipes(x_size, y_size, x_position, y_position):
	var pipe = pipe_node.instantiate()
	pipe.create_pipe(x_size, y_size)
	pipe.position = Vector2(x_position, y_position)
	add_child(pipe)
	pipe.add_to_group("pipes")
  1. Funtion stop() was created. it just changed speed variable to 0
func stop():
	speed = 0
  1. Finally _on_body_entered(body) signal was called. It was used get_tree().call_group("pipes", "stop") to reference the groups created and adding behavior in this case the function stop()
func _on_body_entered(body):
	get_tree().call_group("pipes", "stop")

Now the function works as intended, allowing to the player stopping the pipes everytime the player touches it.

Thanks a lot for your help ! It was incredible valuable for my learning.

2 Likes

You did a great job creating that solution and sharing it here. Your are the real MVP.

1 Like

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