85 lines
2.4 KiB
JavaScript
85 lines
2.4 KiB
JavaScript
import { Vector2 } from 'three'
|
|
import Ability from './ability.js'
|
|
import Team from './team.js'
|
|
|
|
export default class Template {
|
|
static minion(team, options = {}) {
|
|
return {
|
|
abilities: [options.ranged ? Ability.rangedAttack.id : Ability.meleeAttack.id, null, null, null],
|
|
height: options.ranged ? 40 : 38,
|
|
logic: this.#minionLogic(options.route),
|
|
maxHealth: options.ranged ? 300 : 450,
|
|
position: team == Team.blue ? new Vector2(200, 200) : new Vector2(1800, 1800),
|
|
radius: 48,
|
|
speed: 325,
|
|
team,
|
|
visualRadius: options.ranged ? 36 : 38,
|
|
}
|
|
}
|
|
|
|
static player(overrides) {
|
|
return {
|
|
abilities: [
|
|
Ability.rangedAttack.id,
|
|
Ability.straightShot.id,
|
|
Ability.shieldThrow.id,
|
|
Ability.blink.id,
|
|
],
|
|
height: 80,
|
|
logic: this.#playerLogic,
|
|
maxHealth: 600,
|
|
spawnPosition: new Vector2(500, 150),
|
|
radius: 65,
|
|
visualRadius: 40,
|
|
...overrides,
|
|
}
|
|
}
|
|
|
|
// TODO: minion aggro
|
|
// TODO: incremental pathfinding stuck in thicker than recalculateDestRadius walls
|
|
static #minionLogic(route = []) {
|
|
const checkpointSize = 300
|
|
const maxDestDistance = 100
|
|
const recalculateDestRadius = 50
|
|
|
|
return function builtMinionLogic() {
|
|
const entity = this
|
|
if (entity.dead) { entity.despawn() }
|
|
|
|
if (route.length > 0) {
|
|
const routeIndex = entity.memory.routeCheckpoint ?? 0
|
|
const goal = route[routeIndex].clone()
|
|
if (goal instanceof Vector2) {
|
|
if (entity.distanceTo(goal) < checkpointSize) {
|
|
if (routeIndex + 1 < route.length) {
|
|
entity.memory.routeCheckpoint = routeIndex + 1
|
|
}
|
|
}
|
|
|
|
if ((entity.destination?.distanceTo(entity.position) ?? 0) < recalculateDestRadius) {
|
|
const distanceToGoal = entity.distanceTo(goal)
|
|
if (distanceToGoal > maxDestDistance) {
|
|
const direction = goal.clone().sub(entity.position).normalize().multiplyScalar(maxDestDistance)
|
|
goal.copy(entity.position.clone().add(direction))
|
|
}
|
|
|
|
entity.attackAction(goal)
|
|
}
|
|
}
|
|
|
|
if (entity.position.equals(route.at(-1))) {
|
|
entity.despawn()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: proper respawn
|
|
static #playerLogic() {
|
|
const entity = this
|
|
if (entity.dead) {
|
|
entity.respawn()
|
|
}
|
|
}
|
|
}
|