Add basic animal AI
This commit is contained in:
parent
9ab05fe40b
commit
a9c8114096
|
@ -1,6 +1,6 @@
|
|||
import * as planck from 'planck'
|
||||
import { AnimalDefinition, CreatureDefinition } from '../data/animals'
|
||||
import { Action } from "./Action"
|
||||
import { Action, adjustAction } from "./Action"
|
||||
import { Entity, Sensor } from "./Entity"
|
||||
import { PuddleEntity } from './PuddleEntity'
|
||||
import { WorldContext } from './World'
|
||||
|
@ -11,9 +11,13 @@ export class AnimalEntity extends Entity {
|
|||
isPlayer: boolean = false
|
||||
isMonster: boolean = false
|
||||
thinkTimer: number = 0 // Time since last thought, used by AI.
|
||||
target?: Entity
|
||||
wanderTimer: number = 0 // Time since last wander.
|
||||
nextWander: number = 100 // Time to next wander.
|
||||
smelledTarget?: Entity
|
||||
seenTarget?: Entity
|
||||
def: AnimalDefinition
|
||||
mode: CreatureDefinition
|
||||
desiredActions: Action[] = []
|
||||
|
||||
constructor(def: AnimalDefinition) {
|
||||
super(`${def.name}.animal.stand.west.0`)
|
||||
|
@ -110,7 +114,7 @@ export class AnimalEntity extends Entity {
|
|||
if (Math.abs(this.velocity[1]) < this.mode.maxSpeed) {
|
||||
this.velocity[1] -= Math.sin(r) * this.mode.acceleration
|
||||
}
|
||||
let cardinal = this.getCardinal()
|
||||
let cardinal = this.getCardinal(this.direction)
|
||||
this.sprite.setKey = 'run'
|
||||
if (this.sprite.subsetKey !== cardinal || this.sprite.subsetKey !== 'run') {
|
||||
this.sprite.setCtor(`${this.sprite.spriteKey}.${this.sprite.animationKey}.${this.sprite.setKey}.${cardinal}.${this.sprite.frameIndex}`)
|
||||
|
@ -119,7 +123,7 @@ export class AnimalEntity extends Entity {
|
|||
} else {
|
||||
this.sprite.animate = false
|
||||
this.sprite.setKey = 'stand'
|
||||
this.sprite.setCtor(`${this.sprite.spriteKey}.${this.sprite.animationKey}.${this.sprite.setKey}.${this.getCardinal()}.0`)
|
||||
this.sprite.setCtor(`${this.sprite.spriteKey}.${this.sprite.animationKey}.${this.sprite.setKey}.${this.getCardinal(this.direction)}.0`)
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -129,9 +133,9 @@ export class AnimalEntity extends Entity {
|
|||
// Eh... let's manually handle velocity
|
||||
this.body?.setLinearVelocity(planck.Vec2(this.velocity[0], this.velocity[1]))
|
||||
}
|
||||
getCardinal(): string {
|
||||
getCardinal(direction: number): string {
|
||||
const degreesPerDirection = 360 / 4
|
||||
const angle = this.direction + degreesPerDirection / 2
|
||||
const angle = direction + degreesPerDirection / 2
|
||||
|
||||
if (angle >= 0 * degreesPerDirection && angle < 1 * degreesPerDirection) {
|
||||
return 'west'
|
||||
|
@ -144,19 +148,51 @@ export class AnimalEntity extends Entity {
|
|||
}
|
||||
think(delta: number) {
|
||||
this.thinkTimer += delta
|
||||
while (this.thinkTimer >= 500) {
|
||||
while (this.thinkTimer >= 100) {
|
||||
if (!this.isMonster) {
|
||||
if (this.target) {
|
||||
// Flee from target
|
||||
if (this.seenTarget) {
|
||||
let r = Math.atan2(this.y-this.seenTarget.y, this.x-this.seenTarget.x)
|
||||
let a = r * (180 / Math.PI)
|
||||
if (a < 0) {
|
||||
a += 360
|
||||
}
|
||||
a -= 180
|
||||
if (a < 0) {
|
||||
a = 360 - a
|
||||
}
|
||||
this.desiredActions = adjustAction([], this.getCardinal(a), 0.85)
|
||||
this.desiredActions = adjustAction(this.desiredActions, this.getCardinal(Math.random()*360), Math.random())
|
||||
} else if (this.smelledTarget) {
|
||||
let r = Math.atan2(this.y-this.smelledTarget.y, this.x-this.smelledTarget.x)
|
||||
let a = r * (180 / Math.PI)
|
||||
if (a < 0) {
|
||||
a += 360
|
||||
}
|
||||
a -= 180
|
||||
if (a < 0) {
|
||||
a = 360 - a
|
||||
}
|
||||
// 5% to walk away, otherwise just chill.
|
||||
if (Math.random() > 0.95) {
|
||||
this.desiredActions = adjustAction([], this.getCardinal(a), 0.85)
|
||||
}
|
||||
} else {
|
||||
// Wander.
|
||||
this.wanderTimer += delta
|
||||
if (this.wanderTimer >= this.nextWander) {
|
||||
this.nextWander = Math.max(10, Math.random() * 100)
|
||||
if (Math.random() > 0.15) {
|
||||
this.desiredActions = []
|
||||
} else {
|
||||
this.desiredActions = adjustAction([], this.getCardinal(Math.random()*360), 1)
|
||||
}
|
||||
this.wanderTimer = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
this.thinkTimer -= 500
|
||||
this.thinkTimer -= 100
|
||||
this.act(this.desiredActions)
|
||||
}
|
||||
}
|
||||
setTarget(entity: Entity) {
|
||||
}
|
||||
sense(sensor: Sensor, entity: AnimalEntity) {
|
||||
if (this.isPlayer) return
|
||||
if (sensor.type === 'long') {
|
||||
|
@ -175,38 +211,22 @@ export class AnimalEntity extends Entity {
|
|||
}
|
||||
smell(entity: AnimalEntity) {
|
||||
if (entity.isPlayer) {
|
||||
if (!this.isMonster) {
|
||||
console.log('alert, we can smell player')
|
||||
} else {
|
||||
console.log('we smell the player, wander towards them')
|
||||
}
|
||||
this.smelledTarget = entity
|
||||
}
|
||||
}
|
||||
unsmell(entity: AnimalEntity) {
|
||||
if (entity.isPlayer) {
|
||||
if (!this.isMonster) {
|
||||
console.log('no longer smell player, wander around')
|
||||
} else {
|
||||
console.log('no longer smell player, wander around')
|
||||
}
|
||||
this.smelledTarget = undefined
|
||||
}
|
||||
}
|
||||
see(entity: AnimalEntity) {
|
||||
if (entity.isPlayer) {
|
||||
if (!this.isMonster) {
|
||||
console.log('oh no, run from player')
|
||||
} else {
|
||||
console.log('oh ho, chase player')
|
||||
}
|
||||
this.seenTarget = entity
|
||||
}
|
||||
}
|
||||
unsee(entity: AnimalEntity) {
|
||||
if (entity.isPlayer) {
|
||||
if (!this.isMonster) {
|
||||
console.log('oh ye, we safe')
|
||||
} else {
|
||||
console.log('hunt last seen location')
|
||||
}
|
||||
this.seenTarget = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user