changed creep to focus drawing itself rather than the grid rerendering fully every time something happens.

This commit is contained in:
koneko 2024-10-17 20:34:31 +02:00
parent 32f615f5a9
commit c2783c47d7
7 changed files with 88 additions and 48 deletions

View File

@ -1,6 +1,11 @@
{
"name": "Mission 1",
"description": "This is the first mission",
"mapImage": {
"url": "/assets/maps/mission_01.png",
"width": 1200,
"height": 800
},
"gameMap": {
"rows": 15,
"columns": 20,
@ -20,11 +25,6 @@
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
],
"paths": [
@ -41,7 +41,12 @@
[7, 3],
[7, 4],
[8, 4],
[9, 4]
[9, 4],
[10, 4],
[11, 4],
[12, 4],
[13, 4],
[14, 4]
]
]
},

View File

@ -1,11 +1,17 @@
export type MissionDefinition = {
name: string;
description: string;
mapImageUrl: string;
mapImage: MapImageDefinition;
gameMap: GameMapDefinition;
rounds: MissionRoundDefinition[];
};
export type MapImageDefinition = {
url: string;
width: number;
height: number;
};
export type GameMapDefinition = {
rows: number;
columns: number;

View File

@ -2,6 +2,8 @@ import Assets from '../base/Assets';
import { CreepType, PathDefinition } from '../base/Definitions';
import GameObject from '../base/GameObject';
import * as PIXI from 'pixi.js';
import GameScene from '../scenes/GameScene';
import { Grid } from './Grid';
export function CreepStats(ctype: CreepType): object {
switch (ctype) {
@ -48,17 +50,20 @@ export default class Creep extends GameObject {
private path: PathDefinition;
private pathIndex: number = 0;
private speed: number = 0.002;
private gameScene: GameScene;
public health: number = 2;
public escaped: boolean = false;
public died: boolean = false;
public x: number; // X and Y are local to the grid, not canvas
public y: number;
constructor(creepType: CreepType, path: PathDefinition, bounds?: PIXI.Rectangle) {
constructor(creepType: CreepType, path: PathDefinition, gameScene: GameScene, bounds?: PIXI.Rectangle) {
super(bounds);
this.creepType = creepType;
this.path = path;
this.gameScene = gameScene;
this.x = path[0][1] + 0.5; // centered
this.y = path[0][0] + 0.5;
this.gameScene.grid.container.addChild(this.container);
}
public update(elapsedMS: number) {
if (this.pathIndex + 1 == this.path.length) {
@ -101,7 +106,14 @@ export default class Creep extends GameObject {
this.x += deltaX;
this.y += deltaY;
if (increaseIndex) this.pathIndex++;
this.events.emit(CreepEvents.Moved, this);
this.setBounds(
new PIXI.Rectangle(
this.gameScene.grid.gridUnitsToPixels(this.x),
this.gameScene.grid.gridUnitsToPixels(this.y),
this.gameScene.grid.gridUnitsToPixels(0.5),
this.gameScene.grid.gridUnitsToPixels(0.6)
)
);
}
public takeDamage(amount: number) {
@ -112,6 +124,11 @@ export default class Creep extends GameObject {
}
}
public override destroy() {
super.destroy();
this.draw = null;
this.container.removeChildren();
}
protected draw() {
this.container.removeChildren();
const sprite = new PIXI.Sprite(Assets.BasicCreepTexture);

View File

@ -2,6 +2,7 @@ import * as PIXI from 'pixi.js';
import GameObject from '../base/GameObject';
import { GameMapDefinition, TerrainType } from '../base/Definitions';
import Creep, { CreepEvents } from './Creep';
import GameScene from '../scenes/GameScene';
export class Cell extends GameObject {
public type: TerrainType;
@ -31,6 +32,18 @@ export class Cell extends GameObject {
break;
}
this.container.addChild(g);
const text = new PIXI.Text({
text: `${this.row}|${this.column}`,
style: new PIXI.TextStyle({
fill: 0xffffff,
dropShadow: true,
fontSize: 16,
}),
});
this.container.addChild(text);
text.anchor.set(0.5, 0.5);
text.x = this.bounds.width / 2;
text.y = this.bounds.height / 2;
this.container.x = this.bounds.x;
this.container.y = this.bounds.y;
}
@ -39,15 +52,20 @@ export class Cell extends GameObject {
export class Grid extends GameObject {
private gameMap: GameMapDefinition;
private cells: Cell[] = [];
private creeps: Creep[] = [];
public creeps: Creep[] = [];
constructor(map: GameMapDefinition, bounds?: PIXI.Rectangle) {
constructor(map: GameMapDefinition, gameScene: GameScene, bounds?: PIXI.Rectangle) {
super(bounds);
this.gameMap = map;
console.log(this.gameMap.paths);
for (let y = 0; y < this.gameMap.rows; y++) {
for (let x = 0; x < this.gameMap.columns; x++) {
let type = this.gameMap.cells[x][y];
for (let y = 0; y < this.gameMap.columns; y++) {
for (let x = 0; x < this.gameMap.rows; x++) {
let type;
try {
type = this.gameMap.cells[x][y];
} catch (e) {
type = 1;
}
const isPath = this.gameMap.paths.some((path) => path.some((p) => p[0] === x && p[1] === y));
if (isPath) type = TerrainType.Restricted;
let cell = new Cell(type, x, y, isPath);
@ -59,37 +77,23 @@ export class Grid extends GameObject {
}
public addCreep(creep: Creep) {
this.creeps.push(creep);
creep.events.on(CreepEvents.Moved, (movedCreep) => {
this.onCreepMoved(movedCreep);
});
creep.events.on(CreepEvents.Died, (diedCreep) => {
this.onCreepDiedOrEscaped(diedCreep);
});
creep.events.on(CreepEvents.Escaped, (escapedCreep) => {
this.onCreepDiedOrEscaped(escapedCreep);
});
this.draw();
}
private onCreepMoved(movedCreep: Creep) {
movedCreep.setBounds(
new PIXI.Rectangle(
this.gridUnitsToPixels(movedCreep.x),
this.gridUnitsToPixels(movedCreep.y),
this.gridUnitsToPixels(0.5),
this.gridUnitsToPixels(0.6)
)
);
}
private onCreepDiedOrEscaped(creep: Creep) {
this.creeps.splice(this.creeps.indexOf(creep), 1);
this.draw();
creep.destroy();
}
protected draw() {
console.log('Drawing Grid', this.bounds);
this.container.removeChildren();
let g = new PIXI.Graphics();
g.rect(0, 0, this.bounds.width, this.bounds.height);
g.fill(0x00aa00);
g.rect(0, 0, this.bounds.width, this.bounds.height + 100);
g.fill(0x0000ff);
this.container.addChild(g);
for (let cell of this.cells) {
cell.setBounds(
@ -100,16 +104,6 @@ export class Grid extends GameObject {
);
this.container.addChild(cell.container);
}
for (const creep of this.creeps) {
creep.setBounds(
this.gridUnitsToPixels(creep.x),
this.gridUnitsToPixels(creep.y),
this.gridUnitsToPixels(0.5),
this.gridUnitsToPixels(0.6)
);
// console.log(creep.getBounds());
this.container.addChild(creep.container);
}
this.container.x = this.bounds.x;
this.container.y = this.bounds.y;
}

0
src/components/Tower.ts Normal file
View File

View File

@ -1,6 +1,7 @@
import { CreepType, MissionRoundDefinition, PathDefinition } from '../base/Definitions';
import * as PIXI from 'pixi.js';
import Creep, { CreepEvents } from './Creep';
import GameScene from '../scenes/GameScene';
export enum WaveManagerEvents {
CreepSpawned = 'creepSpawned',
@ -21,11 +22,13 @@ export default class WaveManager {
private paths: PathDefinition[];
private ticks: number = 0;
private started: boolean = false;
private gameScene: GameScene;
public finished: boolean = false;
public events = new PIXI.EventEmitter();
constructor(rounds: MissionRoundDefinition[], paths: PathDefinition[]) {
constructor(rounds: MissionRoundDefinition[], paths: PathDefinition[], gameScene) {
this.rounds = rounds;
this.paths = paths;
this.gameScene = gameScene;
}
public start(roundIndex) {
this.started = true;
@ -36,7 +39,7 @@ export default class WaveManager {
this.rounds[roundIndex].waves.forEach((wave) => {
tickToSpawnAt += wave.firstCreepSpawnTick;
wave.creeps.forEach((creep) => {
const creepObj = new Creep(creep, this.paths[0]);
const creepObj = new Creep(creep, this.paths[0], this.gameScene);
const creepInstance = {
creep: creepObj,
tickToSpawnAt,

View File

@ -13,17 +13,20 @@ enum RoundMode {
}
export default class GameScene extends SceneBase {
public grid: Grid;
private ticker: PIXI.Ticker;
private stats: MissionStats;
private grid: Grid;
private waveManager: WaveManager;
private roundMode = RoundMode.Purchase;
private changeRoundButton: Button;
private currentRound: number = 0;
private gridWidth: number;
private gridHeight: number;
constructor(mission: MissionDefinition, bounds: PIXI.Rectangle) {
super(bounds);
this.waveManager = new WaveManager(mission.rounds, mission.gameMap.paths);
this.waveManager = new WaveManager(mission.rounds, mission.gameMap.paths, this);
this.waveManager.events.on(WaveManagerEvents.CreepSpawned, (creep: Creep) => {
this.grid.addCreep(creep);
creep.events.on(CreepEvents.Escaped, () => {
@ -31,7 +34,9 @@ export default class GameScene extends SceneBase {
});
});
this.stats = new MissionStats(100, 200);
this.grid = new Grid(mission.gameMap);
this.grid = new Grid(mission.gameMap, this);
this.gridWidth = mission.mapImage.width;
this.gridHeight = mission.mapImage.height;
this.ticker = new PIXI.Ticker();
this.ticker.maxFPS = 60;
this.ticker.minFPS = 30;
@ -56,6 +61,7 @@ export default class GameScene extends SceneBase {
public update(elapsedMS: number) {
if (this.checkGameOver()) return;
this.waveManager.update(elapsedMS);
this.grid.creeps.forEach((creep) => creep.update(elapsedMS));
this.checkToEndCombat();
}
@ -115,10 +121,19 @@ export default class GameScene extends SceneBase {
private getGridBounds(): PIXI.Rectangle {
// Center / Center
return new PIXI.Rectangle(this.bounds.width / 2 - 600 / 2, this.bounds.height / 2 - 600 / 2, 600, 600);
let width = 600;
let height = 600;
return new PIXI.Rectangle(
this.bounds.width / 2 - this.gridWidth / 2,
this.bounds.height / 2 - this.gridHeight / 2,
this.gridWidth,
this.gridHeight
);
}
private getChangeRoundButtonBounds(): PIXI.Rectangle {
// Center / Center
return new PIXI.Rectangle(this.bounds.width - 300, this.bounds.height - 150, 300, 150);
let width = 300;
let height = 150;
return new PIXI.Rectangle(this.bounds.width - width, this.bounds.height - height, width, height);
}
}