Add basic animal AI

This commit is contained in:
Ketchetwahmeegwun T. Southall 2022-01-30 00:24:56 -08:00
parent 9ab05fe40b
commit a9c8114096

View File

@ -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
}
}
}