add dead state
This commit is contained in:
+116
-73
@@ -7,11 +7,6 @@ import Team from './team.js'
|
||||
|
||||
export default class Entity {
|
||||
id = crypto.randomUUID()
|
||||
speed = 400
|
||||
radius = 0
|
||||
health = 1
|
||||
maxHealth = 1
|
||||
height = 40
|
||||
abilities = [
|
||||
Ability.rangedAttack,
|
||||
Ability.straightShot,
|
||||
@@ -19,18 +14,24 @@ export default class Entity {
|
||||
Ability.blink,
|
||||
]
|
||||
casting = null
|
||||
cooldowns = {}
|
||||
dead = false
|
||||
health = null
|
||||
height = 40
|
||||
maxHealth = 1
|
||||
radius = 0
|
||||
speed = 400
|
||||
team = Team.neutral
|
||||
|
||||
cooldowns = {}
|
||||
|
||||
#attack = false
|
||||
#attacking = false
|
||||
#dest = null
|
||||
#game = null
|
||||
#logic = null
|
||||
#move = false
|
||||
#moving = false
|
||||
#path = []
|
||||
#position = new Vector2()
|
||||
#position = null
|
||||
#scheduledPathfinding = null
|
||||
#spawnPosition = new Vector2()
|
||||
|
||||
static collider(x, y, radius) {
|
||||
return new SAT.Circle(new SAT.Vector(x, y), radius)
|
||||
@@ -38,6 +39,12 @@ export default class Entity {
|
||||
|
||||
constructor(options = {}) {
|
||||
Object.entries(options).forEach(([key, value]) => this[key] = value)
|
||||
if (this.#position == null) {
|
||||
this.#position = this.#spawnPosition.clone()
|
||||
}
|
||||
if (this.health == null) {
|
||||
this.health = this.maxHealth
|
||||
}
|
||||
}
|
||||
|
||||
get destination() { return this.#dest }
|
||||
@@ -45,6 +52,7 @@ export default class Entity {
|
||||
get game() { return this.#game }
|
||||
get position() { return this.#position }
|
||||
get scheduledPathfinding() { return this.#scheduledPathfinding }
|
||||
get spawnPosition() { return this.#spawnPosition }
|
||||
get x() { return this.position.x }
|
||||
get y() { return this.position.y }
|
||||
|
||||
@@ -53,6 +61,7 @@ export default class Entity {
|
||||
set game(value) { this.#game = value }
|
||||
set position(value) { this.#position = value }
|
||||
set scheduledPathfinding(value) { this.#scheduledPathfinding = value }
|
||||
set spawnPosition(value) { this.#spawnPosition = value }
|
||||
set x(value) { this.position.x = value }
|
||||
set y(value) { this.position.y = value }
|
||||
|
||||
@@ -101,7 +110,7 @@ export default class Entity {
|
||||
}
|
||||
|
||||
if (halt) {
|
||||
this.#move = false
|
||||
this.#moving = false
|
||||
}
|
||||
|
||||
const cursor = new Vector2(x, y)
|
||||
@@ -118,42 +127,26 @@ export default class Entity {
|
||||
}
|
||||
|
||||
haltAction() {
|
||||
this.#move = false
|
||||
this.#moving = false
|
||||
}
|
||||
|
||||
moveAction(x, y, attack = false) {
|
||||
if (this.casting != null && (!this.#attack || this.casting.ability.id != this.abilities[0].id)) {
|
||||
if (this.casting != null && (!this.#attacking || this.casting.ability.id != this.abilities[0].id)) {
|
||||
this.casting = null
|
||||
}
|
||||
|
||||
this.#attack = attack
|
||||
this.#move = true
|
||||
this.#attacking = attack
|
||||
this.#moving = true
|
||||
this.#dest = SATX.fixCollisions(new Vector2(x, y), this.collidables(), this.radius, this.game?.width, this.game?.height)
|
||||
}
|
||||
|
||||
stopAction() {
|
||||
this.casting = null
|
||||
this.#move = true
|
||||
this.#attack = false
|
||||
this.#moving = true
|
||||
this.#attacking = false
|
||||
}
|
||||
|
||||
cast() {
|
||||
if (this.casting == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
const castTime = this.game?.secToTick(this.casting.ability.castTime) ?? 0
|
||||
const castStart = this.casting.timestamp
|
||||
const timestamp = this.game?.currentTick ?? 0
|
||||
if (castStart + castTime > timestamp) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.casting.ability.effect(this, this.casting.cursor)
|
||||
|
||||
this.casting = null
|
||||
return true
|
||||
}
|
||||
// --- Actions above --- //
|
||||
|
||||
collidables() {
|
||||
const entityColliders = (this.game?.entities ?? []).filter((e) => e.id != this.id).map((e) => e.collider)
|
||||
@@ -186,6 +179,12 @@ export default class Entity {
|
||||
return SATX.collideObjects(this.collider, colliders)
|
||||
}
|
||||
|
||||
respawn() {
|
||||
this.#position = this.#spawnPosition.clone()
|
||||
this.health = this.maxHealth
|
||||
this.dead = false
|
||||
}
|
||||
|
||||
state() {
|
||||
return {
|
||||
...this,
|
||||
@@ -201,21 +200,89 @@ export default class Entity {
|
||||
this.fixPosition()
|
||||
}
|
||||
|
||||
move(distanceTraveled = 0) {
|
||||
if (this.casting != null) { return false }
|
||||
|
||||
if (this.#attack && this.game?.entities.some((e) => e.team != this.team && e.position.clone().sub(this.position).length() < this.abilities[0].range)) {
|
||||
const cooldown = this.game?.secToTick(this.abilities[0].cooldown) ?? 0
|
||||
const lastCast = this.cooldowns[this.abilities[0].id]
|
||||
const timestamp = this.game?.currentTick ?? 0
|
||||
if (lastCast != null && lastCast + cooldown > timestamp) { return false }
|
||||
|
||||
const target = this.#dest ?? this.position
|
||||
this.castAction(0, target.x, target.y, false)
|
||||
return true
|
||||
update() {
|
||||
if (this.dead) {
|
||||
// TODO: do something while the entity is dead
|
||||
}
|
||||
else {
|
||||
this.#cast()
|
||||
this.#checkHealth()
|
||||
this.#move()
|
||||
this.fixPosition()
|
||||
}
|
||||
|
||||
if (!this.#move || this.#dest == null) { return false }
|
||||
if (this.#logic != null) {
|
||||
this.#logic()
|
||||
}
|
||||
}
|
||||
|
||||
waypoints() {
|
||||
const entityColliders = (this.game?.entities ?? []).filter((e) => e.id != this.id)
|
||||
const terrainColliders = (this.game?.terrains ?? [])
|
||||
const unadjustedWaypoints = entityColliders.concat(terrainColliders).map((e) => e.unadjustedWaypoints).flat()
|
||||
|
||||
return unadjustedWaypoints.map(([waypoint, direction]) => {
|
||||
return SATX.clamp(
|
||||
waypoint.clone().add(direction.clone().multiplyScalar(this.radius)),
|
||||
this.game?.width,
|
||||
this.game?.height,
|
||||
this.radius,
|
||||
)
|
||||
}) ?? []
|
||||
}
|
||||
|
||||
#cast() {
|
||||
if (this.casting == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
const castTime = this.game?.secToTick(this.casting.ability.castTime) ?? 0
|
||||
const castStart = this.casting.timestamp
|
||||
const timestamp = this.game?.currentTick ?? 0
|
||||
if (castStart + castTime > timestamp) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.casting.ability.effect(this, this.casting.cursor)
|
||||
|
||||
this.casting = null
|
||||
return true
|
||||
}
|
||||
|
||||
#checkHealth() {
|
||||
if (this.health <= 0) {
|
||||
this.dead = true
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: make scheduled pathfinding continue until collision to make the entity more "alive"
|
||||
#move(distanceTraveled = 0) {
|
||||
if (this.casting != null) { return false }
|
||||
|
||||
if (this.#attacking) {
|
||||
const attackCursor = this.#dest ?? this.position
|
||||
const targets = this.game?.entities.filter((e) => e.team != this.team && e.position.clone().sub(attackCursor).length() < this.abilities[0].range)
|
||||
const target = targets.reduce((prev, e) => {
|
||||
if (prev == null || e.position.clone().sub(attackCursor).length() > prev.position.clone().sub(attackCursor).length()) {
|
||||
return e
|
||||
}
|
||||
else {
|
||||
return prev
|
||||
}
|
||||
}, null)
|
||||
|
||||
if (target != null && target.position.clone().sub(this.position).length() < this.abilities[0].range) {
|
||||
const cooldown = this.game?.secToTick(this.abilities[0].cooldown) ?? 0
|
||||
const lastCast = this.cooldowns[this.abilities[0].id]
|
||||
const timestamp = this.game?.currentTick ?? 0
|
||||
if (lastCast != null && lastCast + cooldown > timestamp) { return false }
|
||||
|
||||
this.castAction(0, attackCursor.x, attackCursor.y, false)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.#moving || this.#dest == null) { return false }
|
||||
|
||||
const collidables = this.collidables()
|
||||
const fixedDest = SATX.clamp(SATX.fixCollisions(this.#dest, collidables, this.radius), this.game?.width, this.game?.height, this.radius)
|
||||
@@ -262,37 +329,13 @@ export default class Entity {
|
||||
if (this.position.equals(destination)) {
|
||||
this.#path = this.#path.slice(1)
|
||||
if (this.#path.length > 0) {
|
||||
this.move(distance)
|
||||
this.#move(distance)
|
||||
}
|
||||
else {
|
||||
this.#dest = null
|
||||
this.#move = false
|
||||
this.#moving = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
this.cast()
|
||||
this.move()
|
||||
this.fixPosition()
|
||||
if (this.#logic != null) {
|
||||
this.#logic()
|
||||
}
|
||||
}
|
||||
|
||||
waypoints() {
|
||||
const entityColliders = (this.game?.entities ?? []).filter((e) => e.id != this.id)
|
||||
const terrainColliders = (this.game?.terrains ?? [])
|
||||
const unadjustedWaypoints = entityColliders.concat(terrainColliders).map((e) => e.unadjustedWaypoints).flat()
|
||||
|
||||
return unadjustedWaypoints.map(([waypoint, direction]) => {
|
||||
return SATX.clamp(
|
||||
waypoint.clone().add(direction.clone().multiplyScalar(this.radius)),
|
||||
this.game?.width,
|
||||
this.game?.height,
|
||||
this.radius,
|
||||
)
|
||||
}) ?? []
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user