game_actor_npc_npc.js

import MovingActor from "../moving_actor.js";
import Vec2 from "../../vector/vec2.js";

/**
 * @module NPC
 * @fileoverview Contains NPC class.
 */

/**
 * @class
 * @extends MovingActor
 * NPC that extends MovingActor. Has the ability to generate and walk along a path.
 */
export default class NPC extends MovingActor {
    /**
     * Create a new NPC.
     * @param {Vec2} pos Initial position of actor
     * @param {number} rotation Rotation of actor
     * @param {number|Vec2} Scale of actor
     * @param {string|Sprite|null} sprite Sprite for visual rendering
     * @param {string|null} collision Collision (optional)
     * @param {Actor|null} follow Actor to follow (optional)
     * @param {number} stopDist Distance to stop following at
     * @constructor
     */
    constructor({
        pos = new Vec2(),
        rotation = 0,
        scale = 4,
        sprite = null,
        collision = null,
        follow = null,
        stopDist = 8
    } = {}) {
        super({
            pos: pos,
            rotation: rotation,
            scale: scale,
            sprite: sprite,
            collision: collision
        });

        this.speed = 200;

        this.follow = follow;
        this._followTimer = 0;
        this._followTimerLength = 1;

        this.path = null;
        this.stopDist = stopDist;
    }

    init() {
        super.init();

        if (this.follow !== null)
            this.moveTo(this.follow.pos);
    }

    update(elapsed) {
        if (this.controller === null) {
            this.move = new Vec2(0, 0);

            if (this.path !== null) {
                const dest = this.path.getDestination(this.pos);
                if (dest !== null) {
                    this.move = dest.sub(this.pos).norm();

                    this.speedMultiplier = 1;
                    const unit = this.space.getUnitAt(this.pos.x, this.pos.y);
                    if (unit !== null)
                        if (!unit.canWalkOn)
                            this.speedMultiplier = 0.4;
                }
            }
        }

        super.update(elapsed);

        if (this.path !== null)
            if (this.path.getEnd().dist(this.pos) <= this.stopDist)
                this.path = null;

        if (this.follow !== null) {
            this._followTimer += elapsed;
            if (this._followTimer >= this._followTimerLength) {
                this._followTimer = 0;

                this.moveTo(this.follow.pos);
            }
        }
    }

    drawDebug(ctx, showID = true, showDot = true) {
        super.drawDebug(ctx, showID, showDot);

        if (this.path !== null)
            this.path.drawDebug(ctx);
    }

    /**
     * Generate a path in the space to walk to a specified destination.
     * @param {Vec2} pos Position to generate a path to
     */
    moveTo(pos) {
        if (this.path !== null)
            if (this.path.getEnd().dist(pos) < 4)
                return;
        if (this.pos.dist(pos) < this.stopDist)
            return;

        this.path = this.space.generatePath(this.pos.copy(), pos);
    }
}