Godot Version
4.2.2
Question
I was wondering about 2 different ways of going about an idea, and wanted an experienced opinion on the performance of both methods.
I saw a similar issue here: Making a raycast not stop after the first collision - #6 by Monday
I have the same concept, I wanted to make a raycast that would hit something, and then continue on and find everything within the path. I considered making it a recursive function that would just call it self with the same end point everytime, but a new start point based upon the previous collision but I was unsure about a few aspects.
- The documentation says that accessing space safely can only be done during physics_process, but if I wanted to make a recursive function, would calling that function within physics_process, and passing the space as a parameter still be safe?
- Would calling multiple raycasts be more efficient than just creating one ShapeCast2D? The documentation says that ShapeCast2D is more computationally expensive, but I was unsure by how much. I assume it’s based upon the amount of shapes created for the ShapeCast2D.
Currently, to make the ShapeCast2D shapes small enough, I have to make them very small and that makes a lot of them, which I would think is less than ideal. It’s currently set as squares that are 1x1.
I was also confused about the margin property, as it says if it is set higher, it is more consistent, sacrificing precision. Is there a visual reference of what that looks like? Is it like a buffer between each shape within the ShapeCast2D? I couldn’t tell when I looked at it.
Here is a picture of a working version of my concept with visible ShapeCast2Ds, where they are intersecting with each other (shows by the white stars).
Here is the code used for this:
#below is within the script for the beams, which is on each player and the statue
func _physics_process(delta):
var size_beginning_point
var size_end_point
if is_end_tether:
size_beginning_point = Vector2((.1 * -(self.global_position.x - previous_object.global_position.x)), (.1 * -(self.global_position.y - previous_object.global_position.y)))
size_end_point = Vector2((-(self.global_position.x - previous_object.global_position.x) + .2 * ((self.global_position.x - previous_object.global_position.x))),
(-(self.global_position.y - previous_object.global_position.y) + .2 * ((self.global_position.y - previous_object.global_position.y))))
beam_shape_cast.position = size_beginning_point
beam_shape_cast.target_position = size_end_point
else:
size_beginning_point = Vector2((.1 * -(self.global_position.x - previous_object.global_position.x)), (.1 * -(self.global_position.y - previous_object.global_position.y)))
size_end_point = Vector2((-(self.global_position.x - previous_object.global_position.x) + .2 * ((self.global_position.x - previous_object.global_position.x))),
(-(self.global_position.y - previous_object.global_position.y) + .2 * ((self.global_position.y - previous_object.global_position.y))))
beam_shape_cast.position = size_beginning_point
beam_shape_cast.target_position = size_end_point
if tethered_object != null:
var next_tether = tether_vertices[tether_vertices.find(self) + 1]
if "beam_collision" in previous_tether:
beam_shape_cast.add_exception(previous_tether.beam_area)
beam_shape_cast.add_exception(next_tether.beam_area)
else:
beam_shape_cast.add_exception(next_tether.beam_area)
else:
if "beam_collision" in previous_tether:
beam_shape_cast.add_exception(previous_tether.beam_area)
if !beam_shape_cast.collision_result.is_empty():
for element in beam_shape_cast.collision_result:
if element["collider"] != null:
if ((anchor != element["collider"].get_parent().previous_object) && (previous_object != element["collider"].get_parent().anchor) && (anchor != element["collider"].get_parent().anchor)):
beam_intersection(size_beginning_point, size_end_point, beam_shape_cast.get_collision_point(beam_shape_cast.collision_result.find(element)), beam_area, element["collider"])
func beam_intersection(raycast_beginning, raycast_ending, point_of_collision, beam_1, beam_2):
manage_intersection.emit(point_of_collision, beam_1, beam_2)
#below code is on the parent node, which manages all beams and intersections
func manage_intersections(point_of_collision, beam_1, beam_2):
var found = false
if !created_intersections.is_empty():
for element in created_intersections:
if (beam_1 == element.beam_1 && beam_2 == element.beam_2) || ((beam_2 == element.beam_1 && beam_1 == element.beam_2)):
element.receive_info(point_of_collision)
found = true
break
if !found:
var intersection = intersection_sprite.instantiate()
created_intersections.append(intersection)
intersection.global_position = -(self.global_position - point_of_collision)
intersection.beam_1 = beam_1
intersection.beam_2 = beam_2
intersection.intersection_queue_free.connect(remove_created_intersection)
add_child(intersection)
else:
var intersection = intersection_sprite.instantiate()
created_intersections.append(intersection)
intersection.global_position = -(self.global_position - point_of_collision)
intersection.beam_1 = beam_1
intersection.beam_2 = beam_2
intersection.intersection_queue_free.connect(remove_created_intersection)
add_child(intersection)
#this last part is the code for the intersection sprite
extends AnimatedSprite2D
var beam_1
var beam_2
var location
@onready var timer = $Timer
signal intersection_queue_free
func _process(delta):
if beam_1 == null || beam_2 == null:
intersection_queue_free.emit(self)
self.queue_free()
pass
func _physics_process(delta):
if location != null:
self.global_position = location
func receive_info(point_of_collision):
if point_of_collision == null:
intersection_queue_free.emit(self)
self.queue_free()
else:
location = point_of_collision
timer.start(0.05)
func _on_timer_timeout():
intersection_queue_free.emit(self)
self.queue_free()
Any help would be appreciated, still learning godot and gdscript and so if anything here is a bad habit to get into or a bad practice let me know, thanks!