AI/behaviours/path.js

import { Behaviour } from "./behaviour.js"
import { Vector2, map } from "../../math/index.js"
import { Path } from "../paths/index.js"
const tmp1 = new Vector2()
const tmp2 = new Vector2()
/**
 * Creates a behaviour that follows a certain path.
 * 
 * @augments Behaviour
 */
export class PathFollowing extends Behaviour {
  /**
   * The path taken by a pathfollowing behaviour.
   * 
   * @type {Path}
   */
  path
  /**
   * @param {Path} path
   */
  constructor(path) {
    super()
    this.path = path
    path.speed = this.maxSpeed
  }
  /**
   * @inheritdoc
   * @param {Vector2} position
   * @param {Vector2} velocity
   * @param {Vector2} target
   * @param {number} inv_dt
   * @returns {Vector2} the first parameter
   */
  calc(position,velocity,target, inv_dt) {
    tmp1.copy(position)
    let [p1, p2] = this.path.current()
    tmp2.copy(p2).sub(p1).normalize()

    let proj = tmp2.dot(tmp1.sub(p1))
    let projPoint = this.path.update(proj)
    tmp1.copy(projPoint).sub(position)
    let length = tmp1.magnitude()
    if (length < velocity.magnitude()) {
      tmp1.setMagnitude(map(length, 0, this.maxSpeed, 0, this.maxSpeed))
    }
    let steering = tmp1.sub(velocity).multiply(inv_dt)

    steering.clamp(0, this.maxForce)
    target.add(steering)

    return target
  }
  /**
   * Removes all points on the path.
   */
  clear() {
    this.path.clear()
  }
  /**
   * Adds a point into the path.
   * 
   * @param { Vector2} point
   */
  add(point) {
    this.path.add(point)
  }
  /**
   * If the agent should start at the beginning after reaching the ent of the path.
   * 
   * @type boolean
   */
  set loop(x) {
    this.path.loop = x
  }
  get loop() {
    return this.path.loop
  }
  /**
   * Sets a new path to follow.
   *
   * @param {Path} path
   */
  setPath(path) {
    this.path = path
  }
}