add tutorial

This commit is contained in:
koneko 2025-02-09 00:45:25 +01:00
parent 343d66597c
commit 52c67d9b1c
16 changed files with 127 additions and 47 deletions

View File

@ -17,6 +17,7 @@ List of things to implement following the "release" of the minimum viable produc
- [x] Tower info on click - [x] Tower info on click
- [x] Animate projectiles - [x] Animate projectiles
- [x] Better mouseover tracking when placing tower and showing radius - [x] Better mouseover tracking when placing tower and showing radius
- [ ] Sell tower button
## Gems ## Gems
@ -25,8 +26,8 @@ List of things to implement following the "release" of the minimum viable produc
## Other ## Other
- [ ] Create mission authoring tool - [ ] Disable player action during combat phase.
- [ ] Add sound effects - [ ] Add sound effects
- [ ] Tutorial image/mission - [x] Tutorial image/mission
- [ ] Pause menu - [ ] Pause menu
- [x] Score screen when winning/losing map - [x] Score screen when winning/losing map

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="30" height="17" tilewidth="64" tileheight="64" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" source="Tileset.tsx"/>
<layer id="1" name="Tile Layer 1" width="30" height="17">
<data encoding="csv">
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
4,4,4,4,4,4,4,4,4,4,4,4,4,5,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
18,18,18,18,18,18,18,18,18,18,18,18,18,19,15,15,15,15,15,3,4,4,4,4,4,4,4,4,4,4,
32,32,32,32,32,32,32,32,32,32,32,7,18,19,15,15,15,15,15,17,18,18,18,18,18,18,18,18,18,18,
15,15,15,15,15,15,15,15,15,15,15,17,18,19,15,15,15,15,15,17,18,6,32,32,32,32,32,32,32,32,
15,15,15,15,15,15,15,15,15,15,15,17,18,19,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,17,18,19,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15,
15,15,3,4,4,4,4,4,4,4,4,21,18,19,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15,
15,15,17,18,18,18,18,18,18,18,18,18,18,19,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15,
15,15,17,18,6,32,32,32,32,32,32,32,32,33,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15,
15,15,17,18,19,15,15,15,15,15,15,15,15,15,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15,
15,15,17,18,20,4,4,4,4,4,4,4,4,4,4,4,4,4,4,21,18,19,15,15,15,15,15,15,15,15,
15,15,17,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,19,15,15,15,15,15,15,15,15,
15,15,31,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,33,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15
</data>
</layer>
</map>

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 adds 50% extra fire damage. It can be merged with any gem and is common. This text shouldn't be long.", "description": "Forged from molten lava, the Fire Gem imbues your tower's attacks and adds 50% extra fire damage. It can be merged with any gem and is common.",
"color": "red", "color": "red",
"type": "Fire", "type": "Fire",
"totalLevels": 2, "totalLevels": 2,
@ -12,16 +12,16 @@
"genericImprovements": [ "genericImprovements": [
{ {
"damageUp": 2, "damageUp": 2,
"attackSpeedUp": 10, "attackSpeedUp": 0,
"rangeUp": 0.5, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 0 "gemValueUp": 0
}, },
{ {
"damageUp": 2, "damageUp": 2,
"attackSpeedUp": 10, "attackSpeedUp": 0,
"rangeUp": 0.5, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 10 "gemValueUp": 10
@ -58,7 +58,7 @@
{ {
"damageUp": 2, "damageUp": 2,
"attackSpeedUp": 10, "attackSpeedUp": 10,
"rangeUp": 0.5, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 0 "gemValueUp": 0
@ -66,7 +66,7 @@
{ {
"damageUp": 2, "damageUp": 2,
"attackSpeedUp": 10, "attackSpeedUp": 10,
"rangeUp": 0.5, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 10 "gemValueUp": 10
@ -103,7 +103,7 @@
{ {
"damageUp": 2, "damageUp": 2,
"attackSpeedUp": 10, "attackSpeedUp": 10,
"rangeUp": 0.5, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 0 "gemValueUp": 0
@ -163,7 +163,7 @@
{ {
"damageUp": 2, "damageUp": 2,
"attackSpeedUp": 10, "attackSpeedUp": 10,
"rangeUp": 0.5, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 0 "gemValueUp": 0
@ -171,7 +171,7 @@
{ {
"damageUp": 2, "damageUp": 2,
"attackSpeedUp": 10, "attackSpeedUp": 10,
"rangeUp": 0.5, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 10 "gemValueUp": 10

View File

@ -12,8 +12,8 @@
"cooldown": 120, "cooldown": 120,
"gemSlotsAmount": 2, "gemSlotsAmount": 2,
"cost": 100, "cost": 100,
"range": 3, "range": 4,
"timeToLive": 120, "timeToLive": 20,
"pierce": 1 "pierce": 1
} }
}, },
@ -30,8 +30,8 @@
"cooldown": 120, "cooldown": 120,
"gemSlotsAmount": 3, "gemSlotsAmount": 3,
"cost": 125, "cost": 125,
"range": 2, "range": 2.5,
"timeToLive": 8, "timeToLive": 12,
"pierce": 30 "pierce": 30
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -26,6 +26,12 @@ export default class GameAssets {
public static BannerGemsmith: PIXI.Texture; public static BannerGemsmith: PIXI.Texture;
public static EndScreenDialog: PIXI.Texture; public static EndScreenDialog: PIXI.Texture;
public static Tutorial01: PIXI.Texture;
public static Tutorial02: PIXI.Texture;
public static Tutorial03: PIXI.Texture;
public static Tutorial04: PIXI.Texture;
public static Tutorial05: PIXI.Texture;
public static PlayIconTexture: PIXI.Texture; public static PlayIconTexture: PIXI.Texture;
public static PauseIconTexture: PIXI.Texture; public static PauseIconTexture: PIXI.Texture;
public static ExclamationIconTexture: PIXI.Texture; public static ExclamationIconTexture: PIXI.Texture;
@ -98,6 +104,13 @@ export default class GameAssets {
this.Load('./assets/gui/frame_blue.png').then((texture) => (this.BlueBackground = texture)), this.Load('./assets/gui/frame_blue.png').then((texture) => (this.BlueBackground = texture)),
this.Load('./assets/gui/banner_01.png').then((texture) => (this.BannerGemsmith = texture)), this.Load('./assets/gui/banner_01.png').then((texture) => (this.BannerGemsmith = texture)),
this.Load('./assets/gui/note.png').then((texture) => (this.EndScreenDialog = texture)), this.Load('./assets/gui/note.png').then((texture) => (this.EndScreenDialog = texture)),
this.Load('./assets/tutorial/tutorial01.jpg').then((texture) => (this.Tutorial01 = texture)),
this.Load('./assets/tutorial/tutorial02.jpg').then((texture) => (this.Tutorial02 = texture)),
this.Load('./assets/tutorial/tutorial03.jpg').then((texture) => (this.Tutorial03 = texture)),
this.Load('./assets/tutorial/tutorial04.jpg').then((texture) => (this.Tutorial04 = texture)),
this.Load('./assets/tutorial/tutorial05.jpg').then((texture) => (this.Tutorial05 = texture)),
this.Load('./assets/gui/heart.png').then((texture) => (this.HealthTexture = texture)), this.Load('./assets/gui/heart.png').then((texture) => (this.HealthTexture = texture)),
this.Load('./assets/gui/money.png').then((texture) => (this.GoldTexture = texture)), this.Load('./assets/gui/money.png').then((texture) => (this.GoldTexture = texture)),
this.Load('./assets/gui/wave.png').then((texture) => (this.WaveTexture = texture)), this.Load('./assets/gui/wave.png').then((texture) => (this.WaveTexture = texture)),

View File

@ -16,6 +16,7 @@ function projectileCheck(tower: Tower, elapsedMS: number) {
proj.collidedCreepIDs.forEach(() => { proj.collidedCreepIDs.forEach(() => {
tower.damageDealt += tower.computedDamageToDeal; tower.damageDealt += tower.computedDamageToDeal;
}); });
proj.collidedCreepIDs = [];
tower.projectiles.splice(tower.projectiles.indexOf(proj), 1); tower.projectiles.splice(tower.projectiles.indexOf(proj), 1);
proj = null; proj = null;
} else proj.update(elapsedMS); } else proj.update(elapsedMS);

View File

@ -179,9 +179,14 @@ export default class Tooltip extends GuiObject {
this.gemDescriptionText.alpha = 1; this.gemDescriptionText.alpha = 1;
this.titleText.text = `Lv. ${gem.level} ` + gem.definition.name; this.titleText.text = `Lv. ${gem.level} ` + gem.definition.name;
let costToLevelUp;
if (!gem.isMaxLevel())
costToLevelUp = `Costs ${gem.definition.genericImprovements[gem.level].gemValueUp} gold to level up.`;
else costToLevelUp = 'Max level.';
this.gemDescriptionText.text = this.gemDescriptionText.text =
`Valued at ${gem.definition.initialGemValue + gem.currentGemImprovement().gemValueUp} gold. ` + `${costToLevelUp} Valued at ${
gem.definition.description; gem.definition.initialGemValue + gem.currentGemImprovement().gemValueUp
} gold. ` + gem.definition.description;
} }
public Show(x, y) { public Show(x, y) {
this.container.alpha = 1; this.container.alpha = 1;

View File

@ -73,7 +73,7 @@ export class VisualGemSlot extends GuiObject {
this.container.addChild(this.background); this.container.addChild(this.background);
this.container.addChild(this.iconSprite); this.container.addChild(this.iconSprite);
this.container.addChild(this.frame); this.container.addChild(this.frame);
let txt = gem ? gem.id : ''; let txt = gem ? gem.level : '';
let dbgText = new PIXI.Text({ let dbgText = new PIXI.Text({
text: txt, text: txt,
zIndex: 11, zIndex: 11,
@ -156,6 +156,7 @@ export default class TowerPanel extends GuiObject {
zIndex: 5, zIndex: 5,
style: new PIXI.TextStyle({ style: new PIXI.TextStyle({
fill: 0xffffff, fill: 0xffffff,
fontSize: 25,
stroke: { stroke: {
color: 0x000000, color: 0x000000,
width: 2, width: 2,

67
src/scenes/HowToPlay.ts Normal file
View File

@ -0,0 +1,67 @@
import GameAssets from '../classes/Assets';
import Assets from '../classes/Assets';
import { Engine } from '../classes/Bastion';
import Button, { ButtonTexture } from '../classes/gui/Button';
import { GameScene } from './Game';
import { MainScene } from './Main';
import Scene from './Scene';
import * as PIXI from 'pixi.js';
export class HowToPlay extends Scene {
public currentImg = 1;
public sprite;
public init() {
let sprites = [
null,
GameAssets.Tutorial01,
GameAssets.Tutorial02,
GameAssets.Tutorial03,
GameAssets.Tutorial04,
GameAssets.Tutorial05,
];
this.sprite = new PIXI.Sprite({
texture: GameAssets.Tutorial01,
scale: 0.6,
x: 250,
y: 150,
});
this.stage.addChild(this.sprite);
let leftButton = new Button(
new PIXI.Rectangle(250, this.sprite.height + 160, 120, 60),
'Back',
ButtonTexture.Button01
);
leftButton.container.alpha = 0;
leftButton.onClick = () => {
if (leftButton.container.alpha == 0 || this.currentImg == 1) return;
this.currentImg--;
if (this.currentImg == 3) this.sprite.scale = 1.1;
else this.sprite.scale = 0.6;
this.sprite.texture = sprites[this.currentImg];
if (this.currentImg == 1) leftButton.container.alpha = 0;
};
let right = new Button(
new PIXI.Rectangle(this.sprite.width + 130, this.sprite.height + 160, 120, 60),
'Next',
ButtonTexture.Button01
);
right.onClick = () => {
if (right.container.alpha == 0) return;
this.currentImg++;
if (this.currentImg == 3) this.sprite.scale = 1.1;
else this.sprite.scale = 0.6;
if (this.currentImg != 1) leftButton.container.alpha = 1;
this.sprite.texture = sprites[this.currentImg];
if (this.currentImg == 5) right.container.alpha = 0;
};
const button = new Button(
new PIXI.Rectangle(this.sprite.width - 540, this.sprite.height + 160, 200, 60),
'Main menu',
ButtonTexture.Button01
);
button.onClick = (e) => {
Engine.GameMaster.changeScene(new MainScene());
};
}
}

View File

@ -1,6 +1,7 @@
import { Engine } from '../classes/Bastion'; import { Engine } from '../classes/Bastion';
import { FadeInOut, Tween } from '../classes/game/AnimationManager'; import { FadeInOut, Tween } from '../classes/game/AnimationManager';
import Button, { ButtonTexture } from '../classes/gui/Button'; import Button, { ButtonTexture } from '../classes/gui/Button';
import { HowToPlay } from './HowToPlay';
import { MissionPickerScene } from './MissionPicker'; import { MissionPickerScene } from './MissionPicker';
import Scene from './Scene'; import Scene from './Scene';
import * as PIXI from 'pixi.js'; import * as PIXI from 'pixi.js';
@ -11,10 +12,11 @@ export class MainScene extends Scene {
caption: 'New Game', caption: 'New Game',
rect: new PIXI.Rectangle( rect: new PIXI.Rectangle(
Engine.app.canvas.width / 2 - 300 / 2, Engine.app.canvas.width / 2 - 300 / 2,
Engine.app.canvas.height / 5 + 3 * 80, Engine.app.canvas.height / 5 + 2 * 80,
300, 300,
60 60
), ),
texture: ButtonTexture.Button02, texture: ButtonTexture.Button02,
}; };
@ -28,9 +30,19 @@ export class MainScene extends Scene {
), ),
texture: ButtonTexture.Button02, texture: ButtonTexture.Button02,
}; };
const TutorialButton = {
caption: 'How to play',
rect: new PIXI.Rectangle(
Engine.app.canvas.width / 2 - 300 / 2,
Engine.app.canvas.height / 5 + 3 * 80,
300,
60
),
texture: ButtonTexture.Button02,
};
let text = new PIXI.Text({ let text = new PIXI.Text({
x: Engine.app.canvas.width / 2 - 300 / 2, x: Engine.app.canvas.width / 2 - 300 / 2,
y: Engine.app.canvas.height / 5 + 1 * 80, y: Engine.app.canvas.height / 5 + 20,
text: 'BASTION', text: 'BASTION',
style: { style: {
fill: 0xffaa00, fill: 0xffaa00,
@ -62,5 +74,11 @@ export class MainScene extends Scene {
b2.onClick = (e) => { b2.onClick = (e) => {
Engine.NotificationManager.Notify('Not finished.', 'info'); Engine.NotificationManager.Notify('Not finished.', 'info');
}; };
let b3 = new Button(TutorialButton.rect, TutorialButton.caption, TutorialButton.texture, true);
b3.onClick = (e) => {
Engine.GameMaster.currentScene.stage.removeChild(text);
Engine.GameMaster.currentScene.stage.removeChild(text2);
Engine.GameMaster.changeScene(new HowToPlay());
};
} }
} }