Add player container
This commit is contained in:
parent
1cd8f5fbe6
commit
b55e927a34
3 changed files with 159 additions and 133 deletions
49
backend/src/players/player-container.ts
Normal file
49
backend/src/players/player-container.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { CharacterTeam, PlayerInformation, Random } from 'shared';
|
||||
import { PhysicalContainer } from '../physics/containers/physical-container';
|
||||
import { Player } from './player';
|
||||
|
||||
export class PlayerContainer {
|
||||
private _players: Array<Player> = [];
|
||||
|
||||
constructor(private readonly objects: PhysicalContainer) {}
|
||||
|
||||
public createPlayer(playerInfo: PlayerInformation, socket: SocketIO.Socket): Player {
|
||||
const player = new Player(
|
||||
playerInfo,
|
||||
this,
|
||||
this.objects,
|
||||
socket,
|
||||
this.getTeamOfNextPlayer(),
|
||||
);
|
||||
this._players.push(player);
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
public get players(): Array<Player> {
|
||||
return this._players;
|
||||
}
|
||||
|
||||
public get count(): number {
|
||||
return this.players.length;
|
||||
}
|
||||
|
||||
public step(deltaTimeInSeconds: number) {
|
||||
this.players.forEach((p) => p.step(deltaTimeInSeconds));
|
||||
}
|
||||
|
||||
private getTeamOfNextPlayer(): CharacterTeam {
|
||||
const declaCount = this._players.filter((p) => p.team === CharacterTeam.decla).length;
|
||||
const redCount = this._players.filter((p) => p.team === CharacterTeam.red).length;
|
||||
|
||||
if ((declaCount === redCount && Random.getRandom() >= 0.5) || declaCount < redCount) {
|
||||
return CharacterTeam.decla;
|
||||
} else {
|
||||
return CharacterTeam.red;
|
||||
}
|
||||
}
|
||||
|
||||
public deletePlayer(player: Player) {
|
||||
this._players = this._players.filter((p) => p !== player);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import { CharacterTeam, Random } from 'shared';
|
||||
|
||||
let declaCount = 0;
|
||||
let redCount = 0;
|
||||
|
||||
export const requestTeam = (): { team: CharacterTeam; colorIndex: number } => {
|
||||
if ((declaCount === redCount && Random.getRandom() > 0.5) || declaCount < redCount) {
|
||||
declaCount++;
|
||||
return { team: CharacterTeam.decla, colorIndex: 0 };
|
||||
} else {
|
||||
redCount++;
|
||||
return { team: CharacterTeam.red, colorIndex: 1 };
|
||||
}
|
||||
};
|
||||
|
||||
export const freeTeam = (team: CharacterTeam) => {
|
||||
if (team === CharacterTeam.decla) {
|
||||
declaCount--;
|
||||
} else {
|
||||
redCount--;
|
||||
}
|
||||
};
|
||||
|
|
@ -29,8 +29,8 @@ import { PhysicalContainer } from '../physics/containers/physical-container';
|
|||
import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle';
|
||||
import { isCircleIntersecting } from '../physics/functions/is-circle-intersecting';
|
||||
import { PlayerCharacterPhysical } from '../objects/player-character-physical';
|
||||
import { freeTeam, requestTeam } from './player-team-service';
|
||||
import { PlanetPhysical } from '../objects/planet-physical';
|
||||
import { PlayerContainer } from './player-container';
|
||||
|
||||
export class Player extends CommandReceiver {
|
||||
private character?: PlayerCharacterPhysical | null;
|
||||
|
|
@ -66,52 +66,15 @@ export class Player extends CommandReceiver {
|
|||
},
|
||||
};
|
||||
|
||||
private findEmptyPositionForPlayer(): vec2 {
|
||||
let possibleCenter = this.players.find(
|
||||
(p) => p.character?.isAlive && p.team === this.team,
|
||||
)?.center;
|
||||
|
||||
if (!possibleCenter) {
|
||||
possibleCenter = vec2.create();
|
||||
}
|
||||
|
||||
let rotation = 0;
|
||||
let radius = 0;
|
||||
for (;;) {
|
||||
const playerPosition = vec2.fromValues(
|
||||
radius * Math.cos(rotation) + possibleCenter.x,
|
||||
radius * Math.sin(rotation) + possibleCenter.y,
|
||||
);
|
||||
|
||||
const playerBoundingCircle = new Circle(
|
||||
playerPosition,
|
||||
PlayerCharacterPhysical.boundRadius,
|
||||
);
|
||||
|
||||
const playerBoundingBox = getBoundingBoxOfCircle(playerBoundingCircle);
|
||||
const possibleIntersectors = this.objects.findIntersecting(playerBoundingBox);
|
||||
if (!isCircleIntersecting(playerBoundingCircle, possibleIntersectors)) {
|
||||
return playerPosition;
|
||||
}
|
||||
|
||||
rotation += Math.PI / 8;
|
||||
radius += 30;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly team: CharacterTeam;
|
||||
private colorIndex: number;
|
||||
|
||||
constructor(
|
||||
private readonly playerInfo: PlayerInformation,
|
||||
private readonly players: Array<Player>,
|
||||
private readonly objects: PhysicalContainer,
|
||||
private readonly playerContainer: PlayerContainer,
|
||||
private readonly objectContainer: PhysicalContainer,
|
||||
private readonly socket: SocketIO.Socket,
|
||||
public readonly team: CharacterTeam,
|
||||
) {
|
||||
super();
|
||||
const { team, colorIndex } = requestTeam();
|
||||
this.team = team;
|
||||
this.colorIndex = colorIndex;
|
||||
|
||||
this.createCharacter();
|
||||
|
||||
|
|
@ -129,13 +92,12 @@ export class Player extends CommandReceiver {
|
|||
this.playerInfo.name.slice(0, 20),
|
||||
this.sumKills,
|
||||
this.sumDeaths,
|
||||
this.colorIndex,
|
||||
this.team,
|
||||
this.objects,
|
||||
this.objectContainer,
|
||||
this.findEmptyPositionForPlayer(),
|
||||
);
|
||||
|
||||
this.objects.addObject(this.character);
|
||||
this.objectContainer.addObject(this.character);
|
||||
this.objectsPreviouslyInViewArea.push(this.character);
|
||||
|
||||
this.socket.emit(
|
||||
|
|
@ -146,7 +108,7 @@ export class Player extends CommandReceiver {
|
|||
|
||||
private center: vec2 = vec2.create();
|
||||
private timeUntilRespawn = 0;
|
||||
public step(deltaTime: number) {
|
||||
public step(deltaTimeInSeconds: number) {
|
||||
if (this.character) {
|
||||
this.center = this.character?.center;
|
||||
|
||||
|
|
@ -161,7 +123,7 @@ export class Player extends CommandReceiver {
|
|||
this.character = null;
|
||||
this.timeUntilRespawn = settings.playerDiedTimeout;
|
||||
}
|
||||
} else if ((this.timeUntilRespawn -= deltaTime) < 0) {
|
||||
} else if ((this.timeUntilRespawn -= deltaTimeInSeconds) < 0) {
|
||||
this.createCharacter();
|
||||
}
|
||||
|
||||
|
|
@ -171,7 +133,7 @@ export class Player extends CommandReceiver {
|
|||
bb.size = viewArea.size;
|
||||
|
||||
const objectsInViewArea = Array.from(
|
||||
new Set(this.objects.findIntersecting(bb).map((o) => o.gameObject)),
|
||||
new Set(this.objectContainer.findIntersecting(bb).map((o) => o.gameObject)),
|
||||
);
|
||||
|
||||
const newlyIntersecting = objectsInViewArea.filter(
|
||||
|
|
@ -210,6 +172,41 @@ export class Player extends CommandReceiver {
|
|||
);
|
||||
}
|
||||
|
||||
private findEmptyPositionForPlayer(): vec2 {
|
||||
let possibleCenter = this.playerContainer.players.find(
|
||||
(p) => p.character?.isAlive && p.team === this.team,
|
||||
)?.center;
|
||||
|
||||
if (!possibleCenter) {
|
||||
possibleCenter = vec2.create();
|
||||
}
|
||||
|
||||
let rotation = 0;
|
||||
let radius = 0;
|
||||
for (;;) {
|
||||
const playerPosition = vec2.fromValues(
|
||||
radius * Math.cos(rotation) + possibleCenter.x,
|
||||
radius * Math.sin(rotation) + possibleCenter.y,
|
||||
);
|
||||
|
||||
const playerBoundingCircle = new Circle(
|
||||
playerPosition,
|
||||
PlayerCharacterPhysical.boundRadius,
|
||||
);
|
||||
|
||||
const playerBoundingBox = getBoundingBoxOfCircle(playerBoundingCircle);
|
||||
const possibleIntersectors = this.objectContainer.findIntersecting(
|
||||
playerBoundingBox,
|
||||
);
|
||||
if (!isCircleIntersecting(playerBoundingCircle, possibleIntersectors)) {
|
||||
return playerPosition;
|
||||
}
|
||||
|
||||
rotation += Math.PI / 8;
|
||||
radius += 30;
|
||||
}
|
||||
}
|
||||
|
||||
private getOtherPlayers(): Array<OtherPlayerDirection> {
|
||||
if (!this.character) {
|
||||
return [];
|
||||
|
|
@ -220,12 +217,12 @@ export class Player extends CommandReceiver {
|
|||
bb.topLeft = viewArea.topLeft;
|
||||
bb.size = viewArea.size;
|
||||
|
||||
const playersInViewArea = this.objects
|
||||
const playersInViewArea = this.objectContainer
|
||||
.findIntersecting(bb)
|
||||
.map((o) => o.gameObject)
|
||||
.filter((g) => g instanceof PlayerCharacterPhysical);
|
||||
|
||||
const otherPlayers = this.players.filter(
|
||||
const otherPlayers = this.playerContainer.players.filter(
|
||||
(p) => playersInViewArea.indexOf(p.character!) < 0,
|
||||
);
|
||||
|
||||
|
|
@ -247,10 +244,7 @@ export class Player extends CommandReceiver {
|
|||
|
||||
public destroy() {
|
||||
this.isActive = false;
|
||||
freeTeam(this.team);
|
||||
|
||||
if (this.character) {
|
||||
this.character.destroy();
|
||||
}
|
||||
this.character?.destroy();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue