Table of Contents
Ejemplo de Implementación
Basándonos en la documentación oficial de Godot sobre Raycasting. Vamos a usar un nodo PathFollow3D y BallisticPath3D con los cuales crearemos varios raycast que detecten colisiones.
La estructura de la escena será Node3D > BallisticPath3D > PathFollow3D.
Crearemos un script en el nodo padre y agregaremos las siguientes variables:
var life := 0.0
@onready var last_pos = get_global_position()
var : Vector3
@onready var speed = float($BallisticPath3D.speed)
@onready var loss = $BallisticPath3D.loss_speed
La variable life nos servirá para controlar el fin de recorrido y que el PathFollow3D no trate de salir de la curva; last_pos y new_pos servirán para generar los raycast; speed y loss nos permitirán tener un comportamiento más apegado a lo expresado en el BallisticPath3D.
Ahora agregaremos una función _physics_process(), en la cual anidaremos el comportamiento de la escena. Esto debido a que queremos que se sincronice con el procesamiento de físicas y no el de gráficos.
Para calcular el proceso del PathFollow3D usaremos:
life += delta
if life <= $BallisticPath3D.time_life:
life += delta
speed -= speed / 100 * loss * delta
$BallisticPath3D/PathFollow3D.progress += speed * delta
new_pos = $BallisticPath3D/PathFollow3D.get_global_position()
else:
queue_free()
Basicamente, estamos recreado un calculo similar al que se hizo para dibujar la curva del BallisticPath3D, pero ahora lo usaremos para que el recorrido del PathFollow3D sea los mas coherente posible a la balistica que quisimos representar.
Tambien, podemos observa que ahora ya temos un valor en new_pos, lo que nos permite calcular un raycast y validar colisiones:
var space_state = get_world_3d().direct_space_state
var query = PhysicsRayQueryParameters3D.create(last_pos, new_pos)
var hit = space_state.intersect_ray(query)
if hit:
if hit.collider.has_method("_hit"):
hit.collider._hit()
queue_free()
Vemos que se usa last_pos y new_pos como marcadores para calcular el raycast, podríamos decir que verificamos lo que se atravesó previamente y no lo que se está impactando. La respuesta de space_state.intersect_ray(query) es un diccionario con los datos de la colisión y, en este caso, usamos la información del objeto colisionado y llamamos a la función _hit() del objeto.
Por último, agregaremos last_pos = new_pos actualizando last_pos para la siguiente iteración. Quedando todo el código de la siguiente forma:
extends Node3D
var life := 0.0
@onready var last_pos = get_global_position()
var : Vector3
@onready var speed = float($BallisticPath3D.speed)
@onready var loss = $BallisticPath3D.loss_speed
func _physics_process(delta: float) -> void:
# Calculamos la nueva posicion
life += delta
if life <= $BallisticPath3D.time_life:
life += delta
speed -= speed / 100 * loss * delta
$BallisticPath3D/PathFollow3D.progress += speed * delta
new_pos = $BallisticPath3D/PathFollow3D.get_global_position()
else:
queue_free()
# Verificamos colisiones
var space_state = get_world_3d().direct_space_state
var query = PhysicsRayQueryParameters3D.create(last_pos, new_pos)
var hit = space_state.intersect_ray(query)
if hit:
if hit.collider.has_method("_hit"):
hit.collider._hit()
queue_free()
# actulizamos la ultima posiocion
last_pos = new_pos
