Add npcs
This commit is contained in:
parent
a66fa63b4b
commit
efa838a2ad
20 changed files with 1691 additions and 368 deletions
132
backend/src/players/npc.ts
Normal file
132
backend/src/players/npc.ts
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import {
|
||||
PlayerInformation,
|
||||
CharacterTeam,
|
||||
settings,
|
||||
Circle,
|
||||
Random,
|
||||
MoveActionCommand,
|
||||
} from 'shared';
|
||||
import { PhysicalContainer } from '../physics/containers/physical-container';
|
||||
import { PlayerContainer } from './player-container';
|
||||
import { PlayerBase } from './player-base';
|
||||
import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle';
|
||||
import { PlayerCharacterPhysical } from '../objects/player-character-physical';
|
||||
import { PlanetPhysical } from '../objects/planet-physical';
|
||||
|
||||
export class NPC extends PlayerBase {
|
||||
private moveTarget: vec2 = vec2.create();
|
||||
private planet?: PlanetPhysical;
|
||||
private timeSinceLastFindTarget = 10000;
|
||||
private timeSinceLastFindShootTarget = 10000;
|
||||
|
||||
constructor(
|
||||
playerInfo: PlayerInformation,
|
||||
playerContainer: PlayerContainer,
|
||||
objectContainer: PhysicalContainer,
|
||||
team: CharacterTeam,
|
||||
) {
|
||||
super(playerInfo, playerContainer, objectContainer, team);
|
||||
this.createCharacter();
|
||||
this.step(0);
|
||||
}
|
||||
|
||||
private findTarget() {
|
||||
const observableArea = getBoundingBoxOfCircle(new Circle(this.center, 100));
|
||||
const nearObjects = this.objectContainer.findIntersecting(observableArea);
|
||||
|
||||
const enemies = nearObjects.filter(
|
||||
(o) =>
|
||||
o.gameObject instanceof PlayerCharacterPhysical &&
|
||||
o.gameObject.team !== this.team,
|
||||
);
|
||||
const allies = nearObjects.filter(
|
||||
(o) =>
|
||||
o.gameObject instanceof PlayerCharacterPhysical &&
|
||||
o.gameObject.team === this.team,
|
||||
);
|
||||
const notControlledPlanets = nearObjects.filter(
|
||||
(o) => o.gameObject instanceof PlanetPhysical && o.gameObject.team !== this.team,
|
||||
);
|
||||
|
||||
if (enemies.length > allies.length) {
|
||||
console.log('fleeing');
|
||||
const enemiesCenter = enemies.reduce(
|
||||
(sum, e) => vec2.add(sum, sum, (e.gameObject as PlayerCharacterPhysical).center),
|
||||
vec2.create(),
|
||||
);
|
||||
vec2.scale(enemiesCenter, enemiesCenter, 1 / enemies.length);
|
||||
const enemiesDelta = vec2.subtract(enemiesCenter, this.center, enemiesCenter);
|
||||
if (vec2.length(enemiesDelta) > 0) {
|
||||
vec2.scale(enemiesDelta, enemiesDelta, 200 / vec2.length(enemiesDelta));
|
||||
}
|
||||
vec2.add(this.moveTarget, this.center, enemiesDelta);
|
||||
} else if (!this.planet) {
|
||||
if (notControlledPlanets.length > 0) {
|
||||
this.planet = notControlledPlanets[0] as PlanetPhysical;
|
||||
this.moveTarget = this.planet.center;
|
||||
} else {
|
||||
this.moveTarget = vec2.fromValues(
|
||||
Random.getRandomInRange(-5000, 5000),
|
||||
Random.getRandomInRange(-5000, 5000),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private findShootTarget(): vec2 | undefined {
|
||||
const observableArea = getBoundingBoxOfCircle(new Circle(this.center, 1000));
|
||||
const nearObjects = this.objectContainer.findIntersecting(observableArea);
|
||||
|
||||
const enemies = nearObjects.filter(
|
||||
(o) =>
|
||||
o.gameObject instanceof PlayerCharacterPhysical &&
|
||||
o.gameObject.team !== this.team,
|
||||
);
|
||||
if (enemies.length > 0) {
|
||||
return (enemies[0].gameObject as PlayerCharacterPhysical).center;
|
||||
}
|
||||
}
|
||||
|
||||
private timeUntilRespawn = 0;
|
||||
public step(deltaTimeInSeconds: number) {
|
||||
if (this.character) {
|
||||
this.center = this.character?.center;
|
||||
|
||||
if (!this.character.isAlive) {
|
||||
this.sumDeaths++;
|
||||
this.sumKills = this.character.killCount;
|
||||
|
||||
this.character = null;
|
||||
this.timeUntilRespawn = settings.playerDiedTimeout;
|
||||
}
|
||||
} else {
|
||||
if ((this.timeUntilRespawn -= deltaTimeInSeconds) < 0) {
|
||||
this.createCharacter();
|
||||
this.center = this.character!.center;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.planet && Math.abs(this.planet.ownership - 0.5) > 0.3) {
|
||||
this.planet = undefined;
|
||||
this.findTarget();
|
||||
} else {
|
||||
if ((this.timeSinceLastFindTarget += deltaTimeInSeconds) > 1) {
|
||||
this.timeSinceLastFindTarget = 0;
|
||||
this.findTarget();
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.timeSinceLastFindShootTarget += deltaTimeInSeconds) > 0.5) {
|
||||
const shootTarget = this.findShootTarget();
|
||||
if (shootTarget) {
|
||||
this.character?.shootTowards(shootTarget);
|
||||
}
|
||||
this.timeSinceLastFindShootTarget = 0;
|
||||
}
|
||||
|
||||
const targetDelta = vec2.subtract(vec2.create(), this.moveTarget, this.center);
|
||||
vec2.normalize(targetDelta, targetDelta);
|
||||
this.character?.handleMovementAction(new MoveActionCommand(targetDelta, false));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue