basic pausing

This commit is contained in:
koneko 2025-02-09 22:52:10 +01:00
parent 52c67d9b1c
commit 07db180b5d
13 changed files with 142 additions and 26 deletions

View File

@ -17,7 +17,7 @@ List of things to implement following the "release" of the minimum viable produc
- [x] Tower info on click
- [x] Animate projectiles
- [x] Better mouseover tracking when placing tower and showing radius
- [ ] Sell tower button
- [x] Sell tower button
## Gems

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -49,5 +49,56 @@
"frostfire": 0
}
}
},
{
"name": "cloaker",
"textures": [],
"textureArrayLength": 12,
"stats": {
"health": 12,
"speed": 2,
"special": null,
"resistance": {
"physical": 0,
"divine": 0,
"fire": 0,
"ice": 0,
"frostfire": 0
}
}
},
{
"name": "demon",
"textures": [],
"textureArrayLength": 8,
"stats": {
"health": 12,
"speed": 2,
"special": null,
"resistance": {
"physical": 0,
"divine": 0,
"fire": 0,
"ice": 0,
"frostfire": 0
}
}
},
{
"name": "maker",
"textures": [],
"textureArrayLength": 11,
"stats": {
"health": 11,
"speed": 2,
"special": null,
"resistance": {
"physical": 0,
"divine": 0,
"fire": 0,
"ice": 0,
"frostfire": 0
}
}
}
]

View File

@ -108,6 +108,9 @@ export enum CreepType {
Basic = 0,
Quick = 1,
Tank = 2,
Cloaker = 3,
Demon = 4,
Maker = 5,
}
export enum GemType {

View File

@ -67,6 +67,7 @@ export class Cell extends GameObject {
Engine.GameScene.events.on(TowerEvents.TowerSoldEvent, (_, row, col) => {
if (row == this.row && col == this.column) {
this.hasTowerPlaced = false;
Engine.Grid.rangePreview.clear();
}
});

View File

@ -1,7 +1,7 @@
/**
* Handles keyboard events.
*/
class KeyboardManager {
export default class KeyboardManager {
private static listeners: ((event: KeyboardEvent) => void)[] = [];
public static init() {
@ -35,7 +35,7 @@ class KeyboardManager {
private static handleKeyDown(event: KeyboardEvent) {
if (KeyboardManager.listeners.length > 0) {
console.log(`Key down: ${event.key}`);
// console.log(`Key down: ${event.key}`);
for (let i = KeyboardManager.listeners.length - 1; i >= 0; i--) {
KeyboardManager.listeners[i](event);
if (event.defaultPrevented) {
@ -45,5 +45,3 @@ class KeyboardManager {
}
}
}
export default KeyboardManager;

View File

@ -16,6 +16,8 @@ export function distance(x1, y1, x2, y2) {
export class Tower extends GameObject {
public row: number;
public column: number;
public setAsSold: boolean = false;
public sold: boolean = false;
public definition: TowerDefinition;
public slottedGems: Array<Gem> = [];
public damageDealt: number = 0;
@ -74,6 +76,7 @@ export class Tower extends GameObject {
}
public UnslotGem(index) {
const gem = this.slottedGems.splice(index, 1)[0];
if (gem == null || !gem) return console.warn('UnslotGem: Gem is null.');
Engine.GameScene.MissionStats.giveGem(gem, true);
for (let i = index; i < this.slottedGems.length - 1; i++) {
if (this.slottedGems[i] == null) {
@ -113,14 +116,6 @@ export class Tower extends GameObject {
}
combinedTint = color;
}
// this.slottedGems.forEach((gem) => {
// let rgb = new PIXI.Color(gem.definition.color).toRgb();
// combinedTint =
// ((combinedTint & 0xff0000) + (rgb.r << 16)) |
// ((combinedTint & 0x00ff00) + (rgb.g << 8)) |
// ((combinedTint & 0x0000ff) + rgb.b);
// });
// combinedTint = new PIXI.Color(this.slottedGems[0].definition.color).
let proj = new Projectile(
x,
y,
@ -135,7 +130,15 @@ export class Tower extends GameObject {
this.projectiles.push(proj);
return proj;
}
public Sell() {
this.setAsSold = true;
// Selling logic is handled in TowerManager.update()
}
public update(elapsedMS: any): void {
if (this.sold) return;
if (this.setAsSold) {
this.sold = true;
}
if (this.behaviour == TowerBehaviours.BasicTowerBehaviour) BasicTowerBehaviour(this, elapsedMS);
if (this.behaviour == TowerBehaviours.CircleTowerBehaviour) CircleTowerBehaviour(this, elapsedMS);
}

View File

@ -12,12 +12,13 @@ import { Tower } from './Tower';
*/
function projectileCheck(tower: Tower, elapsedMS: number) {
tower.projectiles.forEach((proj) => {
if (proj.deleteMe) {
if (proj.deleteMe || tower.sold) {
proj.collidedCreepIDs.forEach(() => {
tower.damageDealt += tower.computedDamageToDeal;
});
proj.collidedCreepIDs = [];
tower.projectiles.splice(tower.projectiles.indexOf(proj), 1);
proj.destroy();
proj = null;
} else proj.update(elapsedMS);
});

View File

@ -114,8 +114,17 @@ export default class TowerManager {
}
}
public update(elapsedMS) {
this.towers.forEach((twr) => {
twr.update(elapsedMS);
this.towers.forEach((twr, idx) => {
if (twr.sold) {
twr.slottedGems = twr.slottedGems.filter((gem) => gem != null);
while (twr.slottedGems.length > 0) {
twr.UnslotGem(0);
}
Engine.GameScene.MissionStats.earnGold(twr.definition.stats.cost);
twr.destroy();
this.towers.splice(idx, 1);
Engine.GameScene.events.emit(TowerEvents.TowerSoldEvent, twr.name, twr.row, twr.column);
} else twr.update(elapsedMS);
});
}
}

View File

@ -1,6 +1,5 @@
import * as PIXI from 'pixi.js';
import ModalDialogBase from './ModalDialog';
import GuiObject from '../GuiObject';
export default class MessageBox extends ModalDialogBase {
private caption: string;

View File

@ -1,6 +1,5 @@
import * as PIXI from 'pixi.js';
import GuiObject from '../GuiObject';
import Assets from '../Assets';
import { Engine } from '../Bastion';
import GameAssets from '../Assets';
import Button, { ButtonTexture } from './Button';
@ -46,9 +45,9 @@ export default abstract class ModalDialogBase extends GuiObject {
const contentBounds = `x: ${Math.round(this.dialogContent.x)}, y: ${Math.round(
this.dialogContent.y
)}, width: ${Math.round(this.dialogContent.width)}, height: ${Math.round(this.dialogContent.height)}`;
console.debug(
`ModalDialogBase.show(dialog: ${dialogBounds}, content: ${contentBounds}, buttons: ${this.buttonCaptions})`
);
// console.debug(
// `ModalDialogBase.show(dialog: ${dialogBounds}, content: ${contentBounds}, buttons: ${this.buttonCaptions})`
// );
return new Promise((resolve, reject) => {
Engine.app.stage.addChild(this.container);
this.onClosed = (button) => {

View File

@ -114,6 +114,7 @@ export default class TowerPanel extends GuiObject {
public frostFireResDamage: PIXI.Text;
public divineResDamage: PIXI.Text;
public physicalResDamage: PIXI.Text;
private sellButton: Button;
constructor(bounds: PIXI.Rectangle) {
super(false);
@ -281,6 +282,14 @@ export default class TowerPanel extends GuiObject {
}),
});
this.container.addChild(this.physicalResDamage);
this.sellButton = new Button(
new PIXI.Rectangle(5, this.towerPanel.height - 70, this.towerPanel.width - 115, 60),
'Sell',
ButtonTexture.Button02,
true
);
this.sellButton.container.removeFromParent();
this.container.addChild(this.sellButton.container);
}
private MakeSlots(tower: Tower) {
this.vGems.forEach((vGem) => {
@ -320,7 +329,7 @@ export default class TowerPanel extends GuiObject {
this.MakeSlots(tower);
this.showingTower = tower;
Engine.GameScene.sidebar.gemTab.selectingGemTowerObject = tower;
if (tower.container.parent.x < 900) {
if (tower.container.parent.x < 1270) {
this.ShowRight();
} else {
this.ShowLeft();
@ -339,6 +348,11 @@ export default class TowerPanel extends GuiObject {
this.frostFireResDamage.text = `+${tower.totalGemResistanceModifications.frostfire * 100}% FrostFire damage`;
this.divineResDamage.text = `+${tower.totalGemResistanceModifications.divine * 100}% Divine damage`;
this.physicalResDamage.text = `+${tower.totalGemResistanceModifications.physical * 100}% Physical damage`;
this.sellButton.setCaption('Sell for ' + tower.definition.stats.cost + ' gold');
this.sellButton.onClick = () => {
tower.Sell();
this.Hide();
};
}
private ShowLeft() {
this.towerPanel.x = -100;

View File

@ -22,7 +22,7 @@ import HighScoreDialog, { HighScoreDialogButtons } from '../classes/gui/HighScor
enum RoundMode {
Purchase = 0,
Combat = 1,
OfferingGems = 2,
Misc = 2,
}
export class GameScene extends Scene {
@ -36,6 +36,8 @@ export class GameScene extends Scene {
public sidebar: Sidebar;
public tooltip: Tooltip;
public towerPanel: TowerPanel;
public isPaused: boolean = false;
private pauseButton: Button;
private visualGems: VisualGemSlot[] = [];
private currentRound: number = 0;
private isWaveManagerFinished: boolean = false;
@ -104,12 +106,12 @@ export class GameScene extends Scene {
if (this.roundMode == RoundMode.Combat)
return Engine.NotificationManager.Notify('Wave is already in progress.', 'warn');
if (this.isGameOver) return Engine.NotificationManager.Notify('No more waves.', 'danger');
if (this.roundMode == RoundMode.OfferingGems) return;
if (this.roundMode == RoundMode.Misc) return;
this.setRoundMode(RoundMode.Combat);
this.changeRoundButton.buttonIcon.texture = GameAssets.ExclamationIconTexture;
this.events.emit(WaveManagerEvents.NewWave, `${this.currentRound + 1}`);
};
this.MissionStats = new MissionStats(100, 200);
this.MissionStats = new MissionStats(125, 450);
this.events.on(GemEvents.TowerPanelSelectGem, (gem, index, tower) => {
if (gem == null) {
if (!this.MissionStats.checkIfPlayerHasAnyGems())
@ -120,6 +122,30 @@ export class GameScene extends Scene {
}
this.sidebar.gemTab.TowerPanelSelectingGem(gem, index, tower);
});
this.pauseButton = new Button(new PIXI.Rectangle(5, 5, 120, 80), '', ButtonTexture.Button01, true);
this.pauseButton.container.removeFromParent();
this.stage.addChild(this.pauseButton.container);
this.pauseButton.CustomButtonLogic = () => {
this.pauseButton.buttonIcon = new PIXI.Sprite({
texture: GameAssets.PauseIconTexture,
x: this.pauseButton.container.width / 2,
y: this.pauseButton.container.height / 2,
scale: 0.2,
});
this.pauseButton.buttonIcon.anchor.set(0.5, 0.5);
this.pauseButton.container.addChild(this.pauseButton.buttonIcon);
};
this.pauseButton.CustomButtonLogic();
this.pauseButton.onClick = () => {
if (this.isPaused) {
this.UnpauseGame();
} else {
this.ShowPauseDialog();
this.PauseGame();
}
};
this.ticker = new PIXI.Ticker();
this.ticker.maxFPS = 60;
this.ticker.minFPS = 30;
@ -183,7 +209,7 @@ export class GameScene extends Scene {
Engine.Grid.gridInteractionEnabled = false;
Engine.GameScene.sidebar.towerTab.resetTint();
Engine.TowerManager.ResetChooseTower();
this.setRoundMode(RoundMode.OfferingGems);
this.setRoundMode(RoundMode.Misc);
let gemsToOffer = this.mission.rounds[this.currentRound].offeredGems;
this.DarkenScreen();
this.offerGemsSprite = new PIXI.NineSliceSprite({
@ -245,6 +271,18 @@ export class GameScene extends Scene {
this.setRoundMode(RoundMode.Purchase);
}
public PauseGame() {
this.isPaused = true;
this.ticker.stop();
}
public UnpauseGame() {
this.isPaused = false;
this.ticker.start();
}
public ShowPauseDialog() {
console.warn("Pause dialog doesn't exist.");
}
private async ShowEndgameDialog(lost) {
const endGameDialog = new EndGameDialog(this.mission.name, this.MissionStats, lost);
await endGameDialog.show();