more optimizations

This commit is contained in:
koneko 2025-02-27 15:43:13 +01:00
parent 4943c6ba7f
commit 547cccd071
47 changed files with 102 additions and 63 deletions

View File

@ -6,6 +6,18 @@
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
<link href="https://fonts.googleapis.com/css?family=Aclonica" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css?family=Aclonica" rel="stylesheet" />
<title>Bastion: The Watcher's Lament</title> <title>Bastion: The Watcher's Lament</title>
<meta property="og:title" content="Bastion: The Watcher's Lament" />
<meta
property="og:description"
content="A free, open source, browser based, tower defense game inspired by GemCraft: Frostborn Wrath. Playable NOW on PC!"
/>
<meta property="og:image" content="https://bastion.overflow.fun/faivcon.png" />
<meta property="og:url" content="https://bastion.overflow.fun" />
<meta name="twitter:title" content="Bastion: The Watcher's Lament" />
<meta
name="twitter:description"
content="A free, open source, browser based, tower defense game inspired by GemCraft: Frostborn Wrath. Playable NOW on PC!"
/>
</head> </head>
<body> <body>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -1,7 +1,7 @@
[ [
{ {
"name": "Fire Gem", "name": "Fire Gem",
"description": "Forged from molten lava, the Fire Gem imbues your tower's attacks and add extra fire damage. It can be merged with any gem and is common.", "description": "Forged from molten lava, the Fire Gem imbues your tower's attacks and add extra fire damage. Well researched and common.",
"color": "red", "color": "red",
"type": "Fire", "type": "Fire",
"totalLevels": 9, "totalLevels": 9,
@ -16,14 +16,6 @@
"rangeUp": 0, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 0, "pierceUp": 0,
"gemValueUp": 50
},
{
"damageUp": 2,
"attackSpeedUp": 0,
"rangeUp": 0,
"timeToLiveUp": 0,
"pierceUp": 1,
"gemValueUp": 100 "gemValueUp": 100
}, },
{ {
@ -32,7 +24,7 @@
"rangeUp": 0, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 100 "gemValueUp": 150
}, },
{ {
"damageUp": 2, "damageUp": 2,
@ -40,7 +32,7 @@
"rangeUp": 0, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 100 "gemValueUp": 250
}, },
{ {
"damageUp": 2, "damageUp": 2,
@ -48,7 +40,7 @@
"rangeUp": 0, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 100 "gemValueUp": 400
}, },
{ {
"damageUp": 2, "damageUp": 2,
@ -56,7 +48,7 @@
"rangeUp": 0, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 100 "gemValueUp": 650
}, },
{ {
"damageUp": 2, "damageUp": 2,
@ -64,7 +56,7 @@
"rangeUp": 0, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 100 "gemValueUp": 750
}, },
{ {
"damageUp": 2, "damageUp": 2,
@ -72,7 +64,7 @@
"rangeUp": 0, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 100 "gemValueUp": 900
}, },
{ {
"damageUp": 2, "damageUp": 2,
@ -80,10 +72,25 @@
"rangeUp": 0, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 100 "gemValueUp": 1000
},
{
"damageUp": 2,
"attackSpeedUp": 0,
"rangeUp": 0,
"timeToLiveUp": 0,
"pierceUp": 1,
"gemValueUp": 1200
} }
], ],
"gemResistanceModifications": [ "gemResistanceModifications": [
{
"physical": 0,
"divine": 0,
"fire": 0.05,
"ice": 0,
"frostfire": 0
},
{ {
"physical": 0, "physical": 0,
"divine": 0, "divine": 0,
@ -94,7 +101,14 @@
{ {
"physical": 0, "physical": 0,
"divine": 0, "divine": 0,
"fire": 0.25, "fire": 0.15,
"ice": 0,
"frostfire": 0
},
{
"physical": 0,
"divine": 0,
"fire": 0.2,
"ice": 0, "ice": 0,
"frostfire": 0 "frostfire": 0
}, },
@ -115,14 +129,7 @@
{ {
"physical": 0, "physical": 0,
"divine": 0, "divine": 0,
"fire": 0.3, "fire": 0.35,
"ice": 0,
"frostfire": 0
},
{
"physical": 0,
"divine": 0,
"fire": 0.3,
"ice": 0, "ice": 0,
"frostfire": 0 "frostfire": 0
}, },
@ -139,19 +146,12 @@
"fire": 0.45, "fire": 0.45,
"ice": 0, "ice": 0,
"frostfire": 0 "frostfire": 0
},
{
"physical": 0,
"divine": 0,
"fire": 0.5,
"ice": 0,
"frostfire": 0
} }
] ]
}, },
{ {
"name": "Yeti Gem", "name": "Yeti Gem",
"description": "Yeti gem description. Something something, write this while drunk or something.", "description": "Crafted from the essence of the frozen bears, the Yeti Gem enhances your tower's attacks with the chilling power of ice. It gives ice damage and is known for its rarity.",
"color": "#32e4fc", "color": "#32e4fc",
"type": "Yeti", "type": "Yeti",
"totalLevels": 8, "totalLevels": 8,
@ -286,7 +286,7 @@
}, },
{ {
"name": "Titalium Gem", "name": "Titalium Gem",
"description": "Titalium gem description. Something something zombie creeps working for you something something.", "description": "Created from distilled creep eyes, the Titalium gem is known for boosting tower range, at the sacrifice for other stats.",
"color": "pink", "color": "pink",
"type": "Titalium", "type": "Titalium",
"totalLevels": 7, "totalLevels": 7,
@ -406,7 +406,7 @@
}, },
{ {
"name": "Soulforge Gem", "name": "Soulforge Gem",
"description": "Soulforge gem description, have to write later.", "description": "Made from the wandering souls of the damned, the Soulforge gem accelerates your towers cooldowns and acts as a repellant for all things unholy.",
"color": "gray", "color": "gray",
"type": "Soulforge", "type": "Soulforge",
"totalLevels": 2, "totalLevels": 2,
@ -541,7 +541,7 @@
}, },
{ {
"name": "Golden Gem", "name": "Golden Gem",
"description": "An inherently useless gem, but high monetary value. Perhaps someone would pay a lot for this.", "description": "An inherently useless gem, providing no tower buffs, but high in monetary value. Highly sought after by all rich people.",
"color": "gold", "color": "gold",
"type": "Gold", "type": "Gold",
"totalLevels": 1, "totalLevels": 1,
@ -571,14 +571,14 @@
}, },
{ {
"name": "Artifact", "name": "Artifact",
"description": "A wildly rare gem, packed with power. No monetary value, yet your towers oddly resonate stronger with it.", "description": "An insanely rare gem of unknown origin, packed with power. No one knows how it works, yet your towers oddly resonate stronger with it.",
"color": "blue", "color": "blue",
"type": "Artifact", "type": "Artifact",
"totalLevels": 1, "totalLevels": 1,
"textures": [], "textures": [],
"cantCombineWith": [], "cantCombineWith": [],
"specialCombine": [], "specialCombine": [],
"initialGemValue": 0, "initialGemValue": 1000,
"genericImprovements": [ "genericImprovements": [
{ {
"damageUp": 10, "damageUp": 10,

View File

@ -26,7 +26,7 @@
"projectile": "blue", "projectile": "blue",
"projectileTextures": [], "projectileTextures": [],
"projectileTexturesArrayLength": 4, "projectileTexturesArrayLength": 4,
"description": "If you feel a little circular.", "description": "If you feel like shooting in a circle around you, projectiles may miss.",
"stats": { "stats": {
"damage": 3, "damage": 3,
"cooldown": 4000, "cooldown": 4000,
@ -45,7 +45,7 @@
"projectile": "yellow", "projectile": "yellow",
"projectileTextures": [], "projectileTextures": [],
"projectileTexturesArrayLength": 4, "projectileTexturesArrayLength": 4,
"description": "Zap zap zap!", "description": "Zap zap zap! This towers shots connect to other enemies!",
"stats": { "stats": {
"damage": 3, "damage": 3,
"cooldown": 3500, "cooldown": 3500,

View File

@ -49,9 +49,8 @@ export default class GameAssets {
private static text; private static text;
private static counter = 0; private static counter = 0;
private static async Load(src) { private static async Load(src) {
this.text.text = 'Loading asset: ' + src; this.text.text = `Loading asset: ${src} (${this.counter}/99)`;
this.counter++; this.counter++;
console.log(this.counter);
return await PIXI.Assets.load({ return await PIXI.Assets.load({
src: src, src: src,
}); });
@ -88,7 +87,6 @@ export default class GameAssets {
Engine.app.stage.addChild(this.text); Engine.app.stage.addChild(this.text);
await Promise.all([ await Promise.all([
this.Load('./aclonica.woff2'),
this.Load('./assets/gui/button_01.png').then((texture) => (this.Button01Texture = texture)), this.Load('./assets/gui/button_01.png').then((texture) => (this.Button01Texture = texture)),
this.Load('./assets/gui/button_02.png').then((texture) => (this.Button02Texture = texture)), this.Load('./assets/gui/button_02.png').then((texture) => (this.Button02Texture = texture)),
this.Load('./assets/gui/frame_01.png').then((texture) => (this.Frame01Texture = texture)), this.Load('./assets/gui/frame_01.png').then((texture) => (this.Frame01Texture = texture)),
@ -138,9 +136,27 @@ export default class GameAssets {
for (let idx = 0; idx < gems.length; idx++) { for (let idx = 0; idx < gems.length; idx++) {
const gem = this.Gems[idx]; const gem = this.Gems[idx];
const texture = await this.Load(`./assets/gems/${gem.type}_spritesheet.png`);
for (let i = 1; i <= gem.totalLevels; i++) { for (let i = 1; i <= gem.totalLevels; i++) {
const texture = await this.Load(`./assets/gems/${gem.type}/${i}.png`); const spritesheet = new PIXI.Spritesheet(texture, {
gem.textures[i - 1] = texture; frames: {
[`${gem.type}_${i}.png`]: {
frame: { x: (i - 1) * 64, y: 0, w: 64, h: 64 },
rotated: false,
trimmed: false,
spriteSourceSize: { x: 0, y: 0, w: 64, h: 64 },
sourceSize: { w: 64, h: 64 },
},
},
meta: {
image: `./assets/gems/${gem.type}_spritesheet.png`,
format: 'RGBA8888',
size: { w: 64 * gem.totalLevels, h: 64 },
scale: '1',
},
});
await spritesheet.parse();
gem.textures[i - 1] = spritesheet.textures[`${gem.type}_${i}.png`];
} }
} }
for (let i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
@ -154,8 +170,8 @@ export default class GameAssets {
this.Creeps = creeps; this.Creeps = creeps;
for (let idx = 0; idx < this.Creeps.length; idx++) { for (let idx = 0; idx < this.Creeps.length; idx++) {
const creep = this.Creeps[idx]; const creep = this.Creeps[idx];
for (let i = 0; i < creep.textureArrayLength; i++) {
const texture = await this.Load(`./assets/creeps/${creep.sprite}_spritesheet.png`); const texture = await this.Load(`./assets/creeps/${creep.sprite}_spritesheet.png`);
for (let i = 0; i < creep.textureArrayLength; i++) {
const spritesheet = new PIXI.Spritesheet(texture, { const spritesheet = new PIXI.Spritesheet(texture, {
frames: { frames: {
[`${creep.sprite}_${i}.png`]: { [`${creep.sprite}_${i}.png`]: {
@ -197,6 +213,8 @@ export default class GameAssets {
for (let idx = 0; idx < this.Towers.length; idx++) { for (let idx = 0; idx < this.Towers.length; idx++) {
const tower = this.Towers[idx]; const tower = this.Towers[idx];
for (let i = 0; i < tower.projectileTexturesArrayLength; i++) { for (let i = 0; i < tower.projectileTexturesArrayLength; i++) {
// My only grievance is that projectiles have to load like this, not like a spritesheet
// due to them not being a fixed w/h.
const projTexture = await this.Load(`./assets/projectiles/${tower.projectile}/${i}.png`); const projTexture = await this.Load(`./assets/projectiles/${tower.projectile}/${i}.png`);
tower.projectileTextures[i] = projTexture; tower.projectileTextures[i] = projTexture;
} }
@ -210,7 +228,7 @@ export default class GameAssets {
private static async LoadMission(missionUrl: string) { private static async LoadMission(missionUrl: string) {
const res = await fetch(missionUrl); const res = await fetch(missionUrl);
const mission = await res.json(); const mission = await res.json();
console.log(`Loading mission: ${missionUrl} [${mission.name} / ${mission.mapImage.url}]`); // console.log(`Loading mission: ${missionUrl} [${mission.name} / ${mission.mapImage.url}]`);
GameAssets.Missions.push(mission); GameAssets.Missions.push(mission);
GameAssets.MissionBackgrounds.push(await this.Load(mission.mapImage.url)); GameAssets.MissionBackgrounds.push(await this.Load(mission.mapImage.url));
} }

View File

@ -39,7 +39,7 @@ export class Engine {
Engine.TowerManager.ToggleChoosingTowerLocation('RESET'); Engine.TowerManager.ToggleChoosingTowerLocation('RESET');
Engine.TowerManager.PlaceTower(tower, 6, 10, tower.behaviour, true); Engine.TowerManager.PlaceTower(tower, 6, 10, tower.behaviour, true);
for (let i = 0; i < 29; i++) { for (let i = 0; i < 29; i++) {
this.GameScene.MissionStats.giveGem(new Gem(i % 4), true); this.GameScene.MissionStats.giveGem(new Gem(i % 6), true);
} }
} }
} }

View File

@ -62,11 +62,11 @@ export function computeGemImprovements(tower: Tower) {
gemPierceUp += improvements.pierceUp; gemPierceUp += improvements.pierceUp;
let resistances = gem.currentGemResistanceModifications(); let resistances = gem.currentGemResistanceModifications();
tower.totalGemResistanceModifications.physical += resistances.physical; tower.totalGemResistanceModifications.physical += Number(resistances.physical.toFixed(2));
tower.totalGemResistanceModifications.ice += resistances.ice; tower.totalGemResistanceModifications.ice += Number(resistances.ice.toFixed(2));
tower.totalGemResistanceModifications.fire += resistances.fire; tower.totalGemResistanceModifications.fire += Number(resistances.fire.toFixed(2));
tower.totalGemResistanceModifications.divine += resistances.divine; tower.totalGemResistanceModifications.divine += Number(resistances.divine.toFixed(2));
tower.totalGemResistanceModifications.frostfire += resistances.frostfire; tower.totalGemResistanceModifications.frostfire += Number(resistances.frostfire.toFixed(2));
}); });
tower.computedDamageToDeal = tower.definition.stats.damage + gemDamage; tower.computedDamageToDeal = tower.definition.stats.damage + gemDamage;
@ -84,14 +84,21 @@ export function computeGemImprovements(tower: Tower) {
tower.computedTimeToLive += Number((buffedBy.computedTimeToLive / 5).toFixed(1)); tower.computedTimeToLive += Number((buffedBy.computedTimeToLive / 5).toFixed(1));
tower.computedPierce += Number((buffedBy.computedPierce / 4).toFixed(1)); tower.computedPierce += Number((buffedBy.computedPierce / 4).toFixed(1));
tower.totalGemResistanceModifications.physical += tower.totalGemResistanceModifications.physical += Number(
(buffedBy.totalGemResistanceModifications.physical * 100) / 2 / 100; (buffedBy.totalGemResistanceModifications.physical / 2).toFixed(2)
tower.totalGemResistanceModifications.ice += (buffedBy.totalGemResistanceModifications.ice * 100) / 2 / 100; );
tower.totalGemResistanceModifications.fire += (buffedBy.totalGemResistanceModifications.fire * 100) / 2 / 100; tower.totalGemResistanceModifications.ice += Number(
tower.totalGemResistanceModifications.divine += (buffedBy.totalGemResistanceModifications.ice / 2).toFixed(2)
(buffedBy.totalGemResistanceModifications.divine * 100) / 2 / 100; );
tower.totalGemResistanceModifications.frostfire += tower.totalGemResistanceModifications.fire += Number(
(buffedBy.totalGemResistanceModifications.frostfire * 100) / 2 / 100; (buffedBy.totalGemResistanceModifications.fire / 2).toFixed(2)
);
tower.totalGemResistanceModifications.divine += Number(
(buffedBy.totalGemResistanceModifications.divine / 2).toFixed(2)
);
tower.totalGemResistanceModifications.frostfire += Number(
(buffedBy.totalGemResistanceModifications.frostfire / 2).toFixed(2)
);
} }
} }

View File

@ -119,7 +119,9 @@ export default class EndGameDialog extends ModalDialogBase {
override close(button?: string): void { override close(button?: string): void {
if (button === EndGameDialogButtons.Confirm) { if (button === EndGameDialogButtons.Confirm) {
if (this.playerNameTextInput.getText().length == 0) { if (this.playerNameTextInput.getText().length == 0) {
MessageBox.show('Please enter your name.', ['OK']); MessageBox.show('Please enter your name.\n(Just start typing, input bar is automatically selected.)', [
'OK',
]);
} else { } else {
this.highScore.addScore({ this.highScore.addScore({
playerName: this.playerNameTextInput.getText(), playerName: this.playerNameTextInput.getText(),

View File

@ -14,7 +14,7 @@ export class MainScene extends Scene {
this.addMainBackground(); this.addMainBackground();
const NewGameButton = { const NewGameButton = {
caption: 'New Game', caption: 'Play',
rect: new PIXI.Rectangle(Engine.app.canvas.width / 2 - 300 / 2, 400 + 0 * 70, 300, 60), rect: new PIXI.Rectangle(Engine.app.canvas.width / 2 - 300 / 2, 400 + 0 * 70, 300, 60),
texture: ButtonTexture.Button01, texture: ButtonTexture.Button01,