1 Ejemplo
marco edited this page 2026-03-06 16:06:32 +00:00

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.

Escena Base

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