diff --git a/docs/assets.md b/docs/assets.md index 8050bb1..3af6d02 100644 --- a/docs/assets.md +++ b/docs/assets.md @@ -1,4 +1,5 @@ # Assets List of assets used in the project, all purchased. -https://assetstore.unity.com/packages/2d/gui/icons/gui-megapack-101517 +https://assetstore.unity.com/packages/2d/gui/icons/gui-megapack-101517 +https://magory.itch.io/ultimate-gem-collections diff --git a/public/assets/gui/frame_04.png b/public/assets/gui/frame_04.png new file mode 100755 index 0000000..7828160 Binary files /dev/null and b/public/assets/gui/frame_04.png differ diff --git a/public/assets/gui/slot_02.PNG b/public/assets/gui/frame_inv.png similarity index 100% rename from public/assets/gui/slot_02.PNG rename to public/assets/gui/frame_inv.png diff --git a/public/assets/gui/gem_amount.png b/public/assets/gui/gem_amount.png new file mode 100644 index 0000000..ba83d43 Binary files /dev/null and b/public/assets/gui/gem_amount.png differ diff --git a/public/assets/gui/gem_amount_0.png b/public/assets/gui/gem_amount_0.png new file mode 100644 index 0000000..b173ce8 Binary files /dev/null and b/public/assets/gui/gem_amount_0.png differ diff --git a/public/assets/gui/gem_amount_1.png b/public/assets/gui/gem_amount_1.png new file mode 100644 index 0000000..936deb9 Binary files /dev/null and b/public/assets/gui/gem_amount_1.png differ diff --git a/public/assets/gui/gem_amount_2.png b/public/assets/gui/gem_amount_2.png new file mode 100644 index 0000000..a98bb3e Binary files /dev/null and b/public/assets/gui/gem_amount_2.png differ diff --git a/public/assets/gui/gem_amount_3.png b/public/assets/gui/gem_amount_3.png new file mode 100644 index 0000000..d1cbf01 Binary files /dev/null and b/public/assets/gui/gem_amount_3.png differ diff --git a/public/assets/gui/gem_amount_4.png b/public/assets/gui/gem_amount_4.png new file mode 100644 index 0000000..96363d5 Binary files /dev/null and b/public/assets/gui/gem_amount_4.png differ diff --git a/public/assets/gui/gem_amount_5.png b/public/assets/gui/gem_amount_5.png new file mode 100644 index 0000000..a6c3d81 Binary files /dev/null and b/public/assets/gui/gem_amount_5.png differ diff --git a/public/assets/gui/gem_amount_6.png b/public/assets/gui/gem_amount_6.png new file mode 100644 index 0000000..de65e05 Binary files /dev/null and b/public/assets/gui/gem_amount_6.png differ diff --git a/src/classes/Assets.ts b/src/classes/Assets.ts index 9d25712..85ff4cb 100644 --- a/src/classes/Assets.ts +++ b/src/classes/Assets.ts @@ -6,23 +6,29 @@ export default class GameAssets { public static Frame01Texture: PIXI.Texture; public static Frame02Texture: PIXI.Texture; public static Frame03Texture: PIXI.Texture; + public static Frame04Texture: PIXI.Texture; + public static FrameInventory: PIXI.Texture; public static FrameBackground: PIXI.Texture; public static FrameTowerTab: PIXI.Texture; public static VioletBackground: PIXI.Texture; public static RedBackground: PIXI.Texture; public static GreenBackground: PIXI.Texture; + public static BlueBackground: PIXI.Texture; public static Button01Texture: PIXI.Texture; public static Button02Texture: PIXI.Texture; public static ButtonSmallTexture: PIXI.Texture; public static HealthTexture: PIXI.Texture; public static GoldTexture: PIXI.Texture; public static WaveTexture: PIXI.Texture; + public static SwordsTexture: PIXI.Texture; + public static TitleTexture: PIXI.Texture; public static PlayIconTexture: PIXI.Texture; public static PauseIconTexture: PIXI.Texture; public static ExclamationIconTexture: PIXI.Texture; public static HomeIconTexture: PIXI.Texture; public static HammerIconTexture: PIXI.Texture; + public static GemAmountIcons: PIXI.Texture[] = []; public static Missions: MissionDefinition[]; public static MissionBackgrounds: PIXI.Texture[] = []; @@ -75,14 +81,19 @@ export default class GameAssets { this.Load('/assets/gui/frame_01.png').then((texture) => (this.Frame01Texture = texture)), this.Load('/assets/gui/frame_02.png').then((texture) => (this.Frame02Texture = texture)), this.Load('/assets/gui/frame_03.png').then((texture) => (this.Frame03Texture = texture)), + this.Load('/assets/gui/frame_04.png').then((texture) => (this.Frame04Texture = texture)), + this.Load('/assets/gui/frame_inv.png').then((texture) => (this.FrameInventory = texture)), this.Load('/assets/gui/background_01.png').then((texture) => (this.FrameBackground = texture)), this.Load('/assets/gui/background_02.png').then((texture) => (this.FrameTowerTab = texture)), this.Load('/assets/gui/frame_violet.png').then((texture) => (this.VioletBackground = texture)), this.Load('/assets/gui/frame_red.png').then((texture) => (this.RedBackground = texture)), this.Load('/assets/gui/frame_green.png').then((texture) => (this.GreenBackground = texture)), + this.Load('/assets/gui/frame_blue.png').then((texture) => (this.BlueBackground = 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/wave.png').then((texture) => (this.WaveTexture = texture)), + this.Load('/assets/gui/sword_02.png').then((texture) => (this.SwordsTexture = texture)), + this.Load('/assets/gui/title01.png').then((texture) => (this.TitleTexture = texture)), this.Load('/assets/gui/icons/play.png').then((texture) => (this.PlayIconTexture = texture)), this.Load('/assets/gui/icons/pause.png').then((texture) => (this.PauseIconTexture = texture)), this.Load('/assets/gui/icons/exclamation.png').then((texture) => (this.ExclamationIconTexture = texture)), @@ -91,13 +102,18 @@ export default class GameAssets { this.LoadMissions(), this.LoadTowers(), this.LoadCreeps(), + this.LoadGemIcons(), ]); - t.destroy(); this.text.destroy(); // Set this.text = true to disallow calling GameAssets.LoadAssets() again this.text = true; } + private static async LoadGemIcons() { + for (let i = 0; i < 7; i++) { + this.GemAmountIcons[i] = await this.Load(`/assets/gui/gem_amount_${i}.png`); + } + } private static async LoadCreeps() { const res = await fetch('/assets/json/Creeps.json'); diff --git a/src/classes/Bastion.ts b/src/classes/Bastion.ts index bfad197..508e463 100644 --- a/src/classes/Bastion.ts +++ b/src/classes/Bastion.ts @@ -23,6 +23,8 @@ export class Engine { public static GridCellSize: number = 64; public static GridColumns: number = 25; public static GridRows: number = 17; + public static MouseX: number = 0; + public static MouseY: number = 0; } export default class GameMaster { diff --git a/src/classes/game/Grid.ts b/src/classes/game/Grid.ts index 5b3da79..81a09d9 100644 --- a/src/classes/game/Grid.ts +++ b/src/classes/game/Grid.ts @@ -8,6 +8,7 @@ import { TowerEvents } from './Tower'; export enum GridEvents { CellMouseOver = 'cellmouseover', + CellMouseLeave = 'cellmouseleave', } export class Cell extends GameObject { @@ -18,7 +19,6 @@ export class Cell extends GameObject { public g: PIXI.Graphics; public hasTowerPlaced: boolean = false; public clickDetector: PIXI.Graphics; - public rangePreview: PIXI.Graphics; constructor(type: TerrainType, row: number, column: number, isPath: boolean) { super(); @@ -39,9 +39,7 @@ export class Cell extends GameObject { interactive: true, }); // ? TODO: make range preview 1 global graphics obj, child. fix - this.rangePreview = new PIXI.Graphics({ - zIndex: 10, - }); + this.g = new PIXI.Graphics({ zIndex: 5, }); @@ -49,20 +47,21 @@ export class Cell extends GameObject { this.clickDetector.fill({ color: 0xff0000, alpha: 0 }); this.container.addChild(this.clickDetector); this.container.addChild(this.g); - this.container.addChild(this.rangePreview); this.clickDetector.on('pointerup', (e) => { - Engine.Grid.onGridCellClicked(row, column); + if (Engine.TowerManager.isPlacingTower) Engine.Grid.onGridCellClicked(row, column); + else this.OpenSelectedTowerPanel(); }); this.clickDetector.on('pointerenter', (e) => { Engine.GameScene.events.emit(GridEvents.CellMouseOver, this); }); this.clickDetector.on('pointerleave', (e) => { - this.rangePreview.clear(); + Engine.GameScene.events.emit(GridEvents.CellMouseLeave, this); + Engine.Grid.rangePreview.clear(); }); Engine.GameScene.events.on(TowerEvents.TowerPlacedEvent, (_, row, col) => { if (row == this.row && col == this.column) { this.hasTowerPlaced = true; - this.rangePreview.clear(); + Engine.Grid.rangePreview.clear(); } }); Engine.GameScene.events.on(TowerEvents.TowerSoldEvent, (_, row, col) => { @@ -74,9 +73,17 @@ export class Cell extends GameObject { public showRangePreview(invalid, range) { let color = 0xffffff; if (invalid) color = 0xff0000; - this.rangePreview.clear(); - this.rangePreview.circle(Engine.GridCellSize / 2, Engine.GridCellSize / 2, range * Engine.GridCellSize); - this.rangePreview.fill({ color: color, alpha: 0.3 }); + Engine.Grid.rangePreview.clear(); + Engine.Grid.rangePreview.circle( + this.column * Engine.GridCellSize + Engine.GridCellSize / 2, + this.row * Engine.GridCellSize + Engine.GridCellSize / 2, + range * Engine.GridCellSize + ); + Engine.Grid.rangePreview.fill({ color: color, alpha: 0.3 }); + } + public OpenSelectedTowerPanel() { + if (this.hasTowerPlaced) { + } } public checkIfCantPlace() { return ( @@ -104,6 +111,7 @@ export class Cell extends GameObject { export class Grid extends GameObject { private gameMap: GameMapDefinition; private cells: Cell[] = []; + public rangePreview: PIXI.Graphics; public creeps: Creep[] = []; public gridShown: boolean = false; @@ -115,6 +123,7 @@ export class Grid extends GameObject { this.bb.y = 0; this.bb.width = Engine.GridCellSize * Engine.GridColumns; this.bb.height = Engine.GridCellSize * Engine.GridRows; + Engine.GameMaster.currentScene.stage.addChild(this.container); let background = new PIXI.Sprite(GameAssets.MissionBackgrounds[missionIndex]); @@ -130,6 +139,10 @@ export class Grid extends GameObject { this.cells.push(cell); } } + this.rangePreview = new PIXI.Graphics({ + zIndex: 10, + }); + this.container.addChild(this.rangePreview); } public toggleGrid(force?: 'hide' | 'show') { this.cells.forEach((cell) => { diff --git a/src/classes/game/TowerManager.ts b/src/classes/game/TowerManager.ts index ea19e29..7267015 100644 --- a/src/classes/game/TowerManager.ts +++ b/src/classes/game/TowerManager.ts @@ -27,7 +27,6 @@ export default class TowerManager { if (this.isPlacingTower) { let cantPlace = cell.checkIfCantPlace(); if (cantPlace) { - cell.rangePreview.clear(); cell.showRangePreview(true, this.selectedTower.stats.range); this.previewSprite.tint = 0xff0000; } else { @@ -39,6 +38,9 @@ export default class TowerManager { this.previewSprite.texture = this.selectedTower.texture; } }); + Engine.GameScene.events.on(GridEvents.CellMouseLeave, (cell: Cell) => { + this.previewSprite.texture = null; + }); } public ResetChooseTower() { this.selectedTower = null; diff --git a/src/classes/gui/Tooltip.ts b/src/classes/gui/Tooltip.ts index 28cdb15..763176a 100644 --- a/src/classes/gui/Tooltip.ts +++ b/src/classes/gui/Tooltip.ts @@ -1,6 +1,7 @@ import * as PIXI from 'pixi.js'; import GuiObject from '../GuiObject'; import GameAssets from '../Assets'; +import { Engine } from '../Bastion'; // ! TODO NEXT! @@ -8,23 +9,146 @@ export default class Tooltip extends GuiObject { private bounds: PIXI.Rectangle; private tooltipSprite: PIXI.NineSliceSprite; + private titleText: PIXI.Text; + private costText: PIXI.Text; + private damageText: PIXI.Text; + private gemAmount: PIXI.Text; + private gemAmountSprite: PIXI.Sprite; + constructor(bounds: PIXI.Rectangle) { super(false); this.bounds = bounds; - this.container.x = this.bounds.x; - this.container.y = this.bounds.y; + this.container.x = -500; + this.container.y = -500; this.tooltipSprite = new PIXI.NineSliceSprite({ - texture: GameAssets.FrameTowerTab, - leftWidth: 1000, - topHeight: 1000, - rightWidth: 1000, - bottomHeight: 1000, + texture: GameAssets.Frame04Texture, + leftWidth: 200, + topHeight: 200, + rightWidth: 200, + bottomHeight: 200, }); - this.tooltipSprite.x = 0; - this.tooltipSprite.y = 0; this.tooltipSprite.width = this.bounds.width; this.tooltipSprite.height = this.bounds.height; + this.titleText = new PIXI.Text({ + x: this.tooltipSprite.width / 2, + y: -20, + zIndex: 5, + style: new PIXI.TextStyle({ + fill: 0xffffff, + stroke: { + color: 0x000000, + width: 2, + }, + }), + }); + this.titleText.anchor.set(0.5, 0); + let title = new PIXI.Sprite({ + x: this.tooltipSprite.width / 2, + y: -20, + width: 250, + height: 40, + texture: GameAssets.TitleTexture, + }); + title.anchor.set(0.5, 0); + + const costSprite = new PIXI.Sprite({ + texture: GameAssets.GoldTexture, + x: 10, + y: 20, + width: 56, + height: 50, + }); + this.costText = new PIXI.Text({ + x: 54, + y: 26, + zIndex: 5, + text: 'Something went wrong if you see this.', + style: { + fill: 'gold', + fontWeight: 'bold', + stroke: { + color: 0x000000, + width: 5, + }, + }, + }); + + this.damageText = new PIXI.Text({ + x: 54, + y: 65, + zIndex: 5, + text: 'Something went wrong if you see this.', + style: { + fill: 'red', + fontWeight: 'bold', + stroke: { + color: 0x000000, + width: 5, + }, + }, + }); + const damageSprite = new PIXI.Sprite({ + texture: GameAssets.SwordsTexture, + x: 22, + y: 70, + width: 32, + height: 32, + }); + + this.gemAmountSprite = new PIXI.Sprite({ + texture: GameAssets.GemAmountIcons[0], + x: 22, + y: 110, + width: 32, + height: 32, + }); + this.gemAmount = new PIXI.Text({ + x: 54, + y: 108, + zIndex: 5, + text: 'Something went wrong if you see this.', + style: { + fill: 'white', + fontWeight: 'bold', + stroke: { + color: 0x000000, + width: 5, + }, + }, + }); + this.container.addChild(this.tooltipSprite); + this.container.addChild(title); + this.container.addChild(costSprite); + this.container.addChild(damageSprite); + this.container.addChild(this.gemAmountSprite); + this.container.addChild(this.costText); + this.container.addChild(this.titleText); + this.container.addChild(this.damageText); + this.container.addChild(this.gemAmount); + + Engine.GameMaster.currentScene.stage.addChild(this.container); + } + public SetContent(title, damage: number, cost: number, gemSlotsAmount: number) { + this.titleText.text = title; + this.gemAmount.text = `Has ${gemSlotsAmount} Gem slots.`; + this.gemAmountSprite.texture = GameAssets.GemAmountIcons[gemSlotsAmount]; + this.costText.text = `Costs ${cost} gold.`; + this.damageText.text = `Deals ${damage} base damage.`; + } + public Show(x, y) { + this.container.alpha = 1; + if (x + this.container.width > Engine.app.canvas.width) { + this.container.x = x - this.container.width; + } else { + this.container.x = x; + } + this.container.y = y; + } + public Hide() { + this.container.alpha = 0; + this.container.x = -500; + this.container.y = -500; } } diff --git a/src/classes/gui/TowerTab.ts b/src/classes/gui/TowerTab.ts index e412796..e5b2901 100644 --- a/src/classes/gui/TowerTab.ts +++ b/src/classes/gui/TowerTab.ts @@ -3,6 +3,7 @@ import GuiObject from '../GuiObject'; import GameAssets from '../Assets'; import { Engine } from '../Bastion'; import { TowerEvents } from '../game/Tower'; +import { TowerDefinition } from '../Definitions'; class TowerButton extends GuiObject { private frameSprite: PIXI.NineSliceSprite; @@ -46,19 +47,41 @@ class TowerButton extends GuiObject { Engine.GameScene.events.on(TowerEvents.TowerPlacedEvent, (name) => { this.resetTint(); }); - this.container.onpointerenter = (e) => { - // add on mouse over info (banner next to sidebar) + this.container.onmousemove = (e) => { + if (Engine.TowerManager.isPlacingTower) return; + this.ShowTooltip(); }; - this.container.onpointerleave = (e) => {}; + this.container.onpointerleave = (e) => { + Engine.GameScene.tooltip.Hide(); + }; + } + private ShowTooltip() { + let definition: TowerDefinition; + GameAssets.Towers.forEach((item) => { + if (item.name == this.towerName) { + definition = item; + } + }); + Engine.GameScene.tooltip.SetContent( + this.towerName, + definition.stats.damage, + definition.stats.cost, + definition.stats.gemSlotsAmount + ); + Engine.GameScene.tooltip.Show(Engine.MouseX, Engine.MouseY); } public onClick(e: PIXI.FederatedPointerEvent): void { if (Engine.TowerManager.isPlacingTower && Engine.TowerManager.selectedTower.name != this.towerName) { Engine.GameScene.sidebar.towerTab.resetTint(); Engine.TowerManager.ResetChooseTower(); } - if (this.frameSprite.tint == 0x00ff00) this.frameSprite.tint = 0xffffff; - else this.frameSprite.tint = 0x00ff00; + Engine.GameScene.tooltip.Hide(); + if (this.frameSprite.tint == 0x00ff00) { + this.frameSprite.tint = 0xffffff; + this.ShowTooltip(); + } else this.frameSprite.tint = 0x00ff00; + Engine.TowerManager.ToggleChoosingTowerLocation(this.towerName); } public resetTint() { @@ -97,19 +120,19 @@ export default class TowerTab extends GuiObject { this.container, GameAssets.RedBackground, 'Basic Tower', - GameAssets.HammerIconTexture + GameAssets.Towers[0].texture ) ); this.towerButtons.push( new TowerButton( - 0, + 3, 1, 70, 70, this.container, GameAssets.GreenBackground, 'Circle Tower', - GameAssets.HomeIconTexture + GameAssets.Towers[1].texture ) ); } diff --git a/src/main.ts b/src/main.ts index 3b70666..fac0057 100644 --- a/src/main.ts +++ b/src/main.ts @@ -55,6 +55,10 @@ import GameUIConstants from './classes/GameUIConstants'; Engine.NotificationManager.update(ticker.elapsedMS); Engine.AnimationManager.update(ticker.elapsedMS); }); + app.canvas.addEventListener('pointermove', function (event) { + Engine.MouseX = ((event.clientX - app.canvas.offsetLeft) / app.canvas.offsetWidth) * 1920; + Engine.MouseY = ((event.clientY - app.canvas.offsetTop) / app.canvas.offsetHeight) * 1080; + }); Engine.GameMaster.changeScene(new MainScene()); let params = new URLSearchParams(location.href); if (params.entries().next().value[1] == 'game') Engine.GameMaster.changeScene(new GameScene('Mission 1')); diff --git a/src/scenes/Game.ts b/src/scenes/Game.ts index be16af2..e313420 100644 --- a/src/scenes/Game.ts +++ b/src/scenes/Game.ts @@ -12,6 +12,7 @@ import MissionStats from '../classes/game/MissionStats'; import TowerManager from '../classes/game/TowerManager'; import { MissionPickerScene } from './MissionPicker'; import GameUIConstants from '../classes/GameUIConstants'; +import Tooltip from '../classes/gui/Tooltip'; enum RoundMode { Purchase = 0, @@ -27,6 +28,7 @@ export class GameScene extends Scene { public ticker: PIXI.Ticker; public changeRoundButton: Button; public sidebar: Sidebar; + public tooltip: Tooltip; private currentRound: number = 0; private isWaveManagerFinished: boolean = false; private playerWon: boolean = false; @@ -71,6 +73,7 @@ export class GameScene extends Scene { this.MissionStats.earnGold(playerAward); }); this.sidebar = new Sidebar(GameUIConstants.SidebarRect); + this.tooltip = new Tooltip(new PIXI.Rectangle(0, 0, 350, 160)); this.changeRoundButton = new Button(GameUIConstants.ChangeRoundButtonRect, '', ButtonTexture.Button01, true); this.changeRoundButton.container.removeFromParent(); this.sidebar.container.addChild(this.changeRoundButton.container);