This commit is contained in:
schmelczerandras 2020-10-25 17:54:45 +01:00
parent a66fa63b4b
commit efa838a2ad
20 changed files with 1691 additions and 368 deletions

132
backend/src/players/npc.ts Normal file
View 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));
}
}