Skip to content
This repository has been archived by the owner on Sep 21, 2024. It is now read-only.

Commit

Permalink
bug fixes and optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
hsanger committed Mar 6, 2023
1 parent 677e613 commit 7355fcd
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 140 deletions.
7 changes: 6 additions & 1 deletion .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

271 changes: 149 additions & 122 deletions src/game/game.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import crypto from "crypto";
import { removeFrom } from "../utils";
import { Bodies, Body, Collision, Composite, Engine, Vector } from "matter-js";

import {
Expand All @@ -22,10 +23,29 @@ import { MapPacket } from "../packets/mapPacket";
import { KillPacket } from "../packets/killPacket";

export class Game {

/***
* The game ID. 16 hex characters, same as MD5
*/
id: string;

map: Map;

/***
* All players, including dead and disconnected players.
*/
players: Player[] = [];

/***
* All connected players. May be dead.
*/
connectedPlayers: Player[] = [];

/***
* All connected and living players.
*/
activePlayers: Player[] = [];

dirtyPlayers: Player[] = [];
aliveCount: number = 0;
aliveCountDirty: boolean = false;
Expand All @@ -44,8 +64,8 @@ export class Game {
initialGasDuration: number;
oldGasPosition: Vector;
newGasPosition: Vector;
oldGasRad: number;
newGasRad: number;
oldGasRadius: number;
newGasRadius: number;

constructor() {
this.id = crypto.createHash('md5').update(crypto.randomBytes(512)).digest('hex');
Expand All @@ -54,153 +74,154 @@ export class Game {
this.initialGasDuration = 0;
this.oldGasPosition = Vector.create(360, 360);
this.newGasPosition = Vector.create(360, 360);
this.oldGasRad = 2048;
this.newGasRad = 2048;
this.oldGasRadius = 2048;
this.newGasRadius = 2048;

this.timer = setInterval(() => this.tick(), GameOptions.tickDelta);
this.engine = Engine.create();
this.engine.gravity.scale = 0;
this.engine.gravity.scale = 0; // Disable gravity

this.map = new Map(this, "main");
}

private tick(): void {

// Update physics engine
Engine.update(this.engine, GameOptions.tickDelta);

// First loop: Calculate movement & animations.
for(const p of this.players) {
if(p.dead || p.quit) continue;

// TODO: Only check objects when player moves 1 unit. No reason to check every 0.2 units.

// Movement
p.notMoving = false;
const s = GameOptions.movementSpeed, ds = GameOptions.diagonalSpeed;
if(p.movingUp && p.movingLeft) p.setVelocity(-ds, ds);
else if(p.movingUp && p.movingRight) p.setVelocity(ds, ds);
else if(p.movingDown && p.movingLeft) p.setVelocity(-ds, -ds);
else if(p.movingDown && p.movingRight) p.setVelocity(ds, -ds);
else if(p.movingUp) p.setVelocity(0, s);
else if(p.movingDown) p.setVelocity(0, -s);
else if(p.movingLeft) p.setVelocity(-s, 0);
else if(p.movingRight) p.setVelocity(s, 0);
else {
p.setVelocity(0, 0);
if(!p.notMoving) p.setVelocity(0, 0);
p.notMoving = true;
}
this.timer = setInterval(() => {

// Update physics engine
Engine.update(this.engine, GameOptions.tickDelta);

// First loop: Calculate movement & animations.
for(const p of this.activePlayers) {

// TODO: Only check objects when player moves 1 unit. No reason to check every 0.2 units.

// Movement
p.notMoving = false;
const s = GameOptions.movementSpeed, ds = GameOptions.diagonalSpeed;
if(p.movingUp && p.movingLeft) p.setVelocity(-ds, ds);
else if(p.movingUp && p.movingRight) p.setVelocity(ds, ds);
else if(p.movingDown && p.movingLeft) p.setVelocity(-ds, -ds);
else if(p.movingDown && p.movingRight) p.setVelocity(ds, -ds);
else if(p.movingUp) p.setVelocity(0, s);
else if(p.movingDown) p.setVelocity(0, -s);
else if(p.movingLeft) p.setVelocity(-s, 0);
else if(p.movingRight) p.setVelocity(s, 0);
else {
p.setVelocity(0, 0);
if(!p.notMoving) p.setVelocity(0, 0);
p.notMoving = true;
}

// p.updateVisibleObjects();
// p.updateVisibleObjects();

if(p.shootStart) {
p.shootStart = false;
if(Date.now() - p.meleeCooldown >= 250) {
p.meleeCooldown = Date.now();
if(p.shootStart) {
p.shootStart = false;
if(Date.now() - p.meleeCooldown >= 250) {
p.meleeCooldown = Date.now();

// Start punching animation
if(!p.animActive) {
p.animActive = true;
p.animType = 1;
p.animTime = 0;
}
// Start punching animation
if(!p.animActive) {
p.animActive = true;
p.animType = 1;
p.animTime = 0;
}

// If the player is punching anything, damage the closest object
let maxDepth: number = -1, closestObject = null;
const weap = Weapons["fists"], // TODO Get player's melee, substitute here
angle = Utils.unitVecToRadians(p.direction),
offset = Vector.add(weap.attack.offset, Vector.mult(Vector.create(1, 0), p.scale - 1)),
position = Vector.add(p.position, Vector.rotate(offset, angle));
const body: Body = Bodies.circle(position.x, position.y, 0.9);
for(const object of this.map.objects) { // TODO This is very inefficient. Only check visible objects
if(!object.body || object.dead || object.id == p.id) continue;
if(((object instanceof Obstacle && object.destructible) || object instanceof Player)) {
const collision: Collision = Collision.collides(body, object.body);
if(collision && collision.depth > maxDepth) {
maxDepth = collision.depth;
closestObject = object;
// If the player is punching anything, damage the closest object
let maxDepth: number = -1, closestObject = null;
const weapon = Weapons[p.loadout.meleeType],
angle = Utils.unitVecToRadians(p.direction),
offset = Vector.add(weapon.attack.offset, Vector.mult(Vector.create(1, 0), p.scale - 1)),
position = Vector.add(p.position, Vector.rotate(offset, angle));
const body: Body = Bodies.circle(position.x, position.y, 0.9);
for(const object of this.map.objects) { // TODO This is very inefficient. Only check visible objects
if(!object.body || object.dead || object.id == p.id) continue;
if(((object instanceof Obstacle && object.destructible) || object instanceof Player)) {
const collision: Collision = Collision.collides(body, object.body);
if(collision && collision.depth > maxDepth) {
maxDepth = collision.depth;
closestObject = object;
}
}
}
}
if(closestObject) {
closestObject.damage(24, p);
if(closestObject.isDoor) closestObject.interact(p);
}
if(closestObject) {
closestObject.damage(24, p);
if(closestObject.isDoor) closestObject.interact(p);
}

/* This code is more efficient, but doesn't work:
for(const id of p.visibleObjects) {
const object = this.map.objects[id];
if(!object.body || object.dead || object.id == p.id) continue;
if(((object instanceof Obstacle && object.destructible) || object instanceof Player)) {
const collision: Collision = Collision.collides(body, object.body);
if(collision && collision.depth > maxDepth) {
maxDepth = collision.depth;
closestObject = object;
/* This code is more efficient, but doesn't work:
for(const id of p.visibleObjects) {
const object = this.map.objects[id];
if(!object.body || object.dead || object.id == p.id) continue;
if(((object instanceof Obstacle && object.destructible) || object instanceof Player)) {
const collision: Collision = Collision.collides(body, object.body);
if(collision && collision.depth > maxDepth) {
maxDepth = collision.depth;
closestObject = object;
}
}
}
*/
}
*/
}
}

if(p.animActive) {
this.fullDirtyObjects.push(p.id);
p.fullObjects.push(p.id);
p.animTime++;
p.animSeq = 1;
if(p.animTime > 8) {
p.animActive = false;
p.animType = p.animSeq = p.animTime = 0;
if(p.animActive) {
this.fullDirtyObjects.push(p.id);
p.fullObjects.push(p.id);
p.animTime++;
p.animSeq = 1;
if(p.animTime > 8) {
p.animActive = false;
p.animType = p.animSeq = p.animTime = 0;
}
} else {
this.partialDirtyObjects.push(p.id);
p.partialObjects.push(p.id); // TODO Check for movement first
}
} else {
this.partialDirtyObjects.push(p.id);
p.partialObjects.push(p.id); // TODO Check for movement first
}
}

// Second loop: calculate visible objects & send updates
for(const p of this.players) {
p.skipObjectCalculations = !this.fullDirtyObjects.length && !this.partialDirtyObjects.length && p.notMoving;
// Second loop: calculate visible objects & send packets
for(const p of this.connectedPlayers) {
p.skipObjectCalculations = !this.fullDirtyObjects.length && !this.partialDirtyObjects.length && p.notMoving;

if(this.emotes.length > 0) {
p.emotesDirty = true;
p.emotes = this.emotes;
}
if(this.emotes.length > 0) {
p.emotesDirty = true;
p.emotes = this.emotes;
}

if(this.explosions.length > 0) {
p.explosionsDirty = true;
p.explosions = this.explosions;
}
if(this.explosions.length > 0) {
p.explosionsDirty = true;
p.explosions = this.explosions;
}

if(this.fullDirtyObjects.length > 0) {
for(const id of this.fullDirtyObjects) {
if(p.visibleObjects.includes(id)) p.fullObjects.push(id);
if(this.fullDirtyObjects.length > 0) {
for(const id of this.fullDirtyObjects) {
if(p.visibleObjects.includes(id)) p.fullObjects.push(id);
}
}
}

if(this.partialDirtyObjects.length > 0) {
for(const id of this.partialDirtyObjects) {
if(p.visibleObjects.includes(id)) p.partialObjects.push(id);
if(this.partialDirtyObjects.length > 0) {
for(const id of this.partialDirtyObjects) {
if(p.visibleObjects.includes(id)) p.partialObjects.push(id);
}
}
}

p.sendPacket(new UpdatePacket(p));
if(this.aliveCountDirty) p.sendPacket(new AliveCountsPacket(p));
if(this.kills.length) {
for(const kill of this.kills) p.sendPacket(kill);
p.sendPacket(new UpdatePacket(p));
if(this.aliveCountDirty) p.sendPacket(new AliveCountsPacket(p));
if(this.kills.length) {
for(const kill of this.kills) p.sendPacket(kill);
}
}
}
this.emotes = [];
this.explosions = [];
this.kills = [];
this.fullDirtyObjects = [];
this.partialDirtyObjects = [];
this.dirtyPlayers = [];
this.deletedPlayerIds = [];
this.aliveCountDirty = false;

// Reset everything
this.emotes = [];
this.explosions = [];
this.kills = [];
this.fullDirtyObjects = [];
this.partialDirtyObjects = [];
this.dirtyPlayers = [];
this.deletedPlayerIds = [];
this.aliveCountDirty = false;
}, GameOptions.tickDelta);
}


onMessage(stream, p) {
try {
const msgType = stream.readUint8();
Expand All @@ -226,7 +247,7 @@ export class Game {
p.direction = direction;
p.skipObjectCalculations = false;
}
stream.readFloat(0, 64, 8); // Distance to mouse
stream.readFloat(0, 64, 8); // Distance to mouse


// Other inputs
Expand Down Expand Up @@ -277,6 +298,8 @@ export class Game {
p.id = this.map.objects.length;
this.map.objects.push(p);
this.players.push(p);
this.connectedPlayers.push(p);
this.activePlayers.push(p);
this.dirtyPlayers.push(p);
this.fullDirtyObjects.push(p.id);
this.aliveCount++;
Expand All @@ -299,8 +322,12 @@ export class Game {
p.quit = true;
this.deletedPlayerIds.push(p.id);
this.partialDirtyObjects.push(p.id);
this.aliveCount--;
this.aliveCountDirty = true;
removeFrom(this.activePlayers, p);
removeFrom(this.connectedPlayers, p);
if(!p.dead) {
this.aliveCount--;
this.aliveCountDirty = true;
}
}

addBody(body) {
Expand Down
1 change: 0 additions & 1 deletion src/game/objects/obstacle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ export class Obstacle {
} else {
}*/
this.body.isSensor = this.doorOpen;
}

}
Loading

0 comments on commit 7355fcd

Please sign in to comment.