signalis/src/interactor.ts

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
}
}
}