grunk/src/world/meet_spook/meet_spook_mob.gd
2025-04-10 19:33:43 -06:00

63 lines
1.5 KiB
GDScript

class_name MeetSpookMob extends Node3D
## Mob spawned and controlled by a meet-spook event
enum State { WAITING, FREEZE, MOVING }
const RAY_MASK := 0b00000101
const BASE_SPEED := 6.0
@export var source: MeetSpook
@export var target: Node3D
@export var freeze_time: float
@export var lifespan: float
var state := State.WAITING
@onready var camera := get_viewport().get_camera_3d()
func activate() -> void:
print_debug(self, " spotted!")
state = State.FREEZE
get_tree().create_timer(freeze_time).timeout.connect(_unfreeze)
get_tree().create_timer(lifespan).timeout.connect(destroy)
source.resolve()
func is_active() -> bool:
return state != State.WAITING
func move_toward_target(delta: float) -> void:
# Should probably be overridden by implementations
global_position = global_position.move_toward(target.global_position, BASE_SPEED * delta)
func _unfreeze() -> void:
state = State.MOVING
func _physics_process(delta: float) -> void:
match state:
State.WAITING:
# Not yet seen by the player
if camera.is_position_in_frustum(global_position):
var query := PhysicsRayQueryParameters3D.create(
camera.global_position, global_position, RAY_MASK
)
# TODO exceptions should include this mob's collision body
var raycast := get_world_3d().direct_space_state.intersect_ray(query)
if not raycast:
# Player has line-of-sight!
activate()
State.FREEZE:
# Just stand there for a sec
pass
State.MOVING:
move_toward_target(delta)
func destroy() -> void:
print_debug("Destroying ", self)
queue_free()