How can I activate Line2D, the reflection line with RayCast2D?

I want to make a Bubble Shooter style work with Godot 4.3. First of all, I drew a virtual line to target objects from the bottom and first I created RayCast2D and then I added 2 Line2Ds as its child node. As you can see in the video below, the first line works and takes the color of the object I am targeting, but the second virtual line is active as a continuation of the first line when I target the edges, but it does not detect objects and after reaching the object, it does not take the color of the object and does not end its length. How can I solve these two problems?
Thank you for your help.
Screenshot:


My Code:

extends RayCast2D

@onready var vl = $FirstLine
@onready var dl = $SecondLine
var vector_line_length = 600
@onready var manager = $"../../../Manager"
var default_color: Color = Color(0.388,0.643,0.969,1)

func _physics_process(_delta: float) -> void:
	
	if not $"../../Control3".was_shooted or not $"../../Control4".was_shooted or not $"../../Control5".was_shooted:

		vl.visible = true
		dl.visible = true

		if $"../../Control3".can_be_shot or $"../../Control4".can_be_shot or $"../../Control5".can_be_shot:
			look_at(get_global_mouse_position())

		if is_colliding():
			if not manager.items.has(get_collider()):
				var collision_point = to_local(get_collision_point())
				vl.default_color = default_color
				dl.default_color = default_color
				vl.points[1].x = collision_point.x
				dl.position = collision_point
				dl.rotation_degrees = (rotation_degrees * 2) * -1
				dl.visible = true
			else:
				var collision_point = to_local(get_collision_point())
				if get_collider().color != null:
					vl.default_color = get_collider().color
					dl.default_color = get_collider().color
				else:
					vl.default_color = default_color
					dl.default_color = default_color
				vl.points[1].x = collision_point.x
				dl.visible = false
		else:
			vl.default_color = default_color
			vl.points[1].x = vector_line_length
			dl.visible = false
	else:
		vl.visible = false
		dl.visible = false
1 Like

you have to update the physics_frame first. try to call force_raycast_update() after you set the new position.

i think it would be easier to use two raycasts here.

Can you explain these two options in more detail?

you can create a raycast in code with

var colliding_data = get_world_2d().direct_space_state.intersect_ray(ray_params)

you need to define PhysicsRayQueryParameters2D first:

var ray_params = PhysicsRayQueryParameters2D.new()
# set ray_params properties here

after you call intersect_ray you can use the colliding_data to determine the colliding_point and start a second raycast the same way from there:

if collider_data:
    var collision_point = collider_data["position"]
1 Like

Where exactly should I use them. I tried to add them into the codes given above, but the line took a different shape this time and did not fix it?

you would use them instead of the raycast you currently use.
Can you show your current implementation?

Is it an example of using the codes you provided in my own project?

Lets say your raycast has hit something and now you need to create the second raycast:

var collision_point # this is the global collision_point of the
# first raycast

var ray_params = PhysicsRayQueryParameters2D.new()
ray_params.from = collision_point
ray_params.to = ... # determine the new raycast direction with rotation and collision_point
ray_params.collision_mask = collision_mask # your collision_mask
ray_params.collide_with_areas = true # if you want to collide with areas
var colliding_data = get_world_2d().direct_space_state.intersect_ray(ray_params)
if colliding_data:
	vl.default_color = colliding_data["collider"].color
	dl.default_color = colliding_data["collider"].color

I tried the codes this way but I get an error.
I wonder if your answer will be added to the existing codes?
I would appreciate it if you help me over the existing codes.
Thanks for your help.

extends RayCast2D

@onready var vl = $FirstLine
@onready var dl = $SecondLine
var vector_line_length = 600
@onready var manager = $"../../../Manager"
var default_color: Color = Color(0.388,0.643,0.969,1)

func _physics_process(_delta: float) -> void:
	if not $"../../Control3".was_shooted or not $"../../Control4".was_shooted or not $"../../Control5".was_shooted:
		vl.visible = true
		dl.visible = true
		
		if $"../../Control3".can_be_shot or $"../../Control4".can_be_shot or $"../../Control5".can_be_shot:
			look_at(get_global_mouse_position())

		if is_colliding():
			var collision_point = to_local(get_collision_point())
			var ray_params = PhysicsRayQueryParameters2D.new()
			ray_params.from = collision_point
			ray_params.to = get_global_position() + Vector2(collision_point.x, collision_point.y)
			ray_params.collision_mask = collision_mask  # Adjust this value as needed
			ray_params.collide_with_areas = true
			
			var colliding_data = get_world_2d().direct_space_state.intersect_ray(ray_params)
			
			if colliding_data:
				vl.default_color = colliding_data["collider"].color
				dl.default_color = colliding_data["collider"].color
				
			else:
				var target_color = colliding_data["collider"].color if colliding_data["collider"].color != null else default_color
				vl.default_color = target_color
				dl.visible = false
		else:
			vl.default_color = default_color
			vl.points[1].x = vector_line_length
			dl.visible = false
	else:
		vl.visible = false
		dl.visible = false
1 Like

What does the error say?

var ray_params = PhysicsRayQueryParameters2D.new()
ray_params.from = get_collision_point()
ray_params.to = get_collision_point() + target_position.rotated((rotation_degrees * 2) * -1).normalized()
ray_params.collision_mask = collision_mask  # Adjust this value as needed
ray_params.collide_with_areas = true

Maybe try this. Im not sure if its correct

1 Like

I get this error: ”Invalid access to property or key ‘collider’ on a base object of type ‘Dictionary’."

It shows this line: ”var target_color = colliding_data[“collider”].color if colliding_data[“collider”].color != null else default_color"

1 Like

can you print out the dictionary before that?

print(colliding_data)
if colliding_data:
    ...

And see what it contains and send it here

1 Like

My first shortcoming in this question was that the second Raycast was not active, that is, its length and position were elsewhere and therefore it was not in the same place as the second line and I fixed it.
My problem now is that I have no problem with the first Raycast and the FirstLine.
Only the second Raycast and SecondLine are not detecting the objects and the connection with the first line is missing.
Now the second line is working but it can’t get the color because it doesn’t detect the object.
The current code is as follows.
Thanks for your help.

My Code:

extends RayCast2D

@onready var vl = $FirstRay
@onready var dl = $SecondRay
@onready var one = $FirstRay/FirstLine
@onready var two = $SecondRay/SecondLine
var vector_line_length = 600
@onready var manager = $"../Manager"
var default_color: Color = Color(0.388,0.643,0.969,1)

func _physics_process(_delta: float) -> void:
	
	if not $"../Control3".was_shooted or not $"../Control4".was_shooted or not $"../Control5".was_shooted:

		vl.visible = true
		dl.visible = true

		if $"../Control3".can_be_shot or $"../Control4".can_be_shot or $"../Control5".can_be_shot:
			look_at(get_global_mouse_position())

		if is_colliding():
			if not manager.items.has(get_collider()):
				var collision_point = to_local(get_collision_point())
				
				one.default_color = default_color
				two.default_color = default_color
				one.points[1].x = collision_point.x
	
				dl.position = collision_point
				dl.rotation_degrees = (rotation_degrees * 2) * -1
				dl.visible = true
			else:
				var collision_point = to_local(get_collision_point())
				if get_collider().color != null:
					one.default_color = get_collider().color
					two.default_color = get_collider().color
					
					
				else:
					one.default_color = default_color
					two.default_color = default_color
				one.points[1].x = collision_point.x
				dl.visible = false
		else:
			
			one.default_color = default_color
			one.points[1].x = vector_line_length
			dl.visible = false
	else:
		vl.visible = false
		dl.visible = false


1 Like

Can you print out the second collider?

			else:
				print(get_collider())
				var collision_point = to_local(get_collision_point())
				if get_collider().color != null:
					one.default_color = get_collider().color
					two.default_color = get_collider().color

It looks like its no colliding. Are you sure you set up the collision_mask correctly?

For the second RayCast2D I have to do a new “is_colliding()” operation.
This solved the problem by adding some code.
Thanks for your help.

1 Like