73 lines
1.8 KiB
TypeScript
73 lines
1.8 KiB
TypeScript
import { Area3D, Callable, Node, NodePath, Variant } from 'godot'
|
|
import Interactable from './interactable'
|
|
import { export_ } from 'godot.annotations'
|
|
|
|
class InteractableDistance {
|
|
static Empty = new InteractableDistance(Infinity)
|
|
|
|
interactable?: Interactable
|
|
distance: number
|
|
|
|
constructor(distance: number, interactable?: Interactable) {
|
|
this.distance = distance
|
|
this.interactable = interactable
|
|
}
|
|
}
|
|
|
|
export default class Interactor extends Area3D {
|
|
@export_(Variant.Type.TYPE_NODE_PATH)
|
|
private _root_node: NodePath = new NodePath('.')
|
|
private _root!: Node
|
|
|
|
get root_node() {
|
|
return this._root
|
|
}
|
|
|
|
_interactables: Array<Interactable> = []
|
|
|
|
_ready(): void {
|
|
this._root = this.get_node(this._root_node)
|
|
|
|
this.area_entered.connect(Callable.create(
|
|
this,
|
|
this._on_area_entered
|
|
))
|
|
|
|
this.area_exited.connect(Callable.create(
|
|
this,
|
|
this._on_area_exited
|
|
))
|
|
}
|
|
|
|
_on_area_entered(area: Area3D) {
|
|
if (area instanceof Interactable) {
|
|
this._interactables.push(area)
|
|
}
|
|
}
|
|
|
|
_on_area_exited(area: Area3D) {
|
|
const index = this._interactables.indexOf(area as Interactable)
|
|
|
|
if (index >= 0) {
|
|
this._interactables.splice(index, 1)
|
|
}
|
|
}
|
|
|
|
try_interact_nearest() {
|
|
// @ts-ignore
|
|
const nearest = this._interactables.reduce(this.find_nearest.bind(this), InteractableDistance.Empty)
|
|
|
|
if (nearest !== InteractableDistance.Empty && nearest.interactable != null) {
|
|
nearest.interactable.interact(this)
|
|
}
|
|
}
|
|
|
|
find_nearest(nearest: InteractableDistance, target: Interactable): InteractableDistance {
|
|
const distance = this.global_position.distance_to(target.global_position)
|
|
if (distance < nearest.distance) {
|
|
return new InteractableDistance(distance, target)
|
|
} else {
|
|
return nearest
|
|
}
|
|
}
|
|
}
|