add proper asset loading and use for towers + projectiles (also projectile animation) + add health bars
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@ -4,6 +4,8 @@
|
||||
"behaviour": "BasicTowerBehaviour",
|
||||
"sprite": "basic_tower",
|
||||
"texture": null,
|
||||
"projectileTextures": [],
|
||||
"projectileTexturesArrayLength": 5,
|
||||
"description": "The building block of society, nothing more basic exists.",
|
||||
"stats": {
|
||||
"damage": 2,
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
BIN
public/assets/projectiles/basic_tower/0.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
public/assets/projectiles/basic_tower/1.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
public/assets/projectiles/basic_tower/2.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
public/assets/projectiles/basic_tower/3.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
public/assets/projectiles/basic_tower/4.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
@ -1,14 +1,11 @@
|
||||
import * as PIXI from 'pixi.js';
|
||||
import { CreepDefinition, CreepStatsDefinition, MissionDefinition, TowerDefinition } from './Definitions';
|
||||
import { CreepDefinition, MissionDefinition, TowerDefinition } from './Definitions';
|
||||
import { Engine } from './Bastion';
|
||||
|
||||
export default class GameAssets {
|
||||
public static BasicTowerTexture: PIXI.Texture;
|
||||
|
||||
public static BasicProjectileTexture: PIXI.Texture;
|
||||
|
||||
public static Frame01Texture: PIXI.Texture;
|
||||
public static Frame02Texture: PIXI.Texture;
|
||||
public static Frame03Texture: PIXI.Texture;
|
||||
public static FrameBackground: PIXI.Texture;
|
||||
public static FrameTowerTab: PIXI.Texture;
|
||||
public static VioletBackground: PIXI.Texture;
|
||||
@ -29,6 +26,7 @@ export default class GameAssets {
|
||||
private static text;
|
||||
private static async Load(src) {
|
||||
this.text.text = 'Loading asset: ' + src;
|
||||
console.log('LOADING ' + src);
|
||||
return await PIXI.Assets.load({
|
||||
src: src,
|
||||
});
|
||||
@ -63,11 +61,12 @@ export default class GameAssets {
|
||||
this.text.y = Engine.app.canvas.height / 2 + 50;
|
||||
this.text.anchor.set(0.5, 0.5);
|
||||
Engine.app.stage.addChild(this.text);
|
||||
this.Load('/aclonica.woff2');
|
||||
await this.Load('/aclonica.woff2');
|
||||
this.Button01Texture = await this.Load('/assets/gui/button_01.png');
|
||||
this.Button02Texture = await this.Load('/assets/gui/button_02.png');
|
||||
this.Frame01Texture = await this.Load('/assets/gui/frame_01.png');
|
||||
this.Frame02Texture = await this.Load('/assets/gui/frame_02.png');
|
||||
this.Frame03Texture = await this.Load('/assets/gui/frame_03.png');
|
||||
this.FrameBackground = await this.Load('/assets/gui/background_01.png');
|
||||
this.FrameTowerTab = await this.Load('/assets/gui/background_02.png');
|
||||
this.VioletBackground = await this.Load('/assets/gui/frame_violet.png');
|
||||
@ -76,8 +75,6 @@ export default class GameAssets {
|
||||
this.HealthTexture = await this.Load('/assets/gui/heart.png');
|
||||
this.GoldTexture = await this.Load('/assets/gui/money.png');
|
||||
this.WaveTexture = await this.Load('/assets/gui/wave.png');
|
||||
this.BasicTowerTexture = await this.Load('/assets/towers/basic_tower.png');
|
||||
this.BasicProjectileTexture = await this.Load('/assets/projectiles/basic_tower.png');
|
||||
await this.LoadMissions();
|
||||
await this.LoadTowers();
|
||||
await this.LoadCreeps();
|
||||
@ -108,7 +105,17 @@ export default class GameAssets {
|
||||
private static async LoadTowers() {
|
||||
const res = await fetch('/assets/json/Towers.json');
|
||||
const towers = await res.json();
|
||||
GameAssets.Towers = towers;
|
||||
this.Towers = towers;
|
||||
console.log(this.Towers);
|
||||
for (let idx = 0; idx < this.Towers.length; idx++) {
|
||||
const tower = this.Towers[idx];
|
||||
for (let i = 0; i < tower.projectileTexturesArrayLength; i++) {
|
||||
console.log(`WANT TO LOAD /assets/projectiles/${tower.sprite}/${i}.png`);
|
||||
const texture = await this.Load(`/assets/projectiles/${tower.sprite}/${i}.png`);
|
||||
tower.projectileTextures[i] = texture;
|
||||
console.log(tower.projectileTextures);
|
||||
}
|
||||
}
|
||||
towers.forEach(async (tower) => {
|
||||
let index = this.TowerSprites.length - 1;
|
||||
if (index == -1) index = 0;
|
||||
|
@ -57,6 +57,8 @@ export type TowerDefinition = {
|
||||
sprite: string;
|
||||
description: string;
|
||||
texture: PIXI.Texture;
|
||||
projectileTextures: PIXI.Texture[];
|
||||
projectileTexturesArrayLength: number;
|
||||
stats: TowerStatsDefinition;
|
||||
};
|
||||
|
||||
@ -90,6 +92,6 @@ export enum GemType {
|
||||
}
|
||||
|
||||
export enum TowerType {
|
||||
Shooting = 0,
|
||||
Basic = 0,
|
||||
Circle = 1,
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ export default class Creep extends GameObject {
|
||||
private pathIndex: number = 0;
|
||||
private speed: number;
|
||||
private direction: number = 1;
|
||||
private healthBarGraphics: PIXI.Graphics = new PIXI.Graphics();
|
||||
private healthBarWidth = 50;
|
||||
public health: number;
|
||||
public maxHealth: number;
|
||||
public escaped: boolean = false;
|
||||
@ -37,6 +39,7 @@ export default class Creep extends GameObject {
|
||||
// Initially flip sprite to the right, since the asset is facing left.
|
||||
this.sprite.scale.x *= -1;
|
||||
this.sprite.anchor.set(0.5, 0.5);
|
||||
this.sprite.animationSpeed = 0.3;
|
||||
this.sprite.play();
|
||||
this.id = id;
|
||||
// Explanation: WaveManager spawns all creeps instantly, and since I don't want
|
||||
@ -46,6 +49,7 @@ export default class Creep extends GameObject {
|
||||
this.container.y = -50;
|
||||
this.sprite.width = Engine.GridCellSize;
|
||||
this.sprite.height = Engine.GridCellSize;
|
||||
this.bb.width = this.sprite.width;
|
||||
this.speed = this.stats.speed / 60;
|
||||
this.health = this.stats.health;
|
||||
this.maxHealth = this.stats.health;
|
||||
@ -56,9 +60,24 @@ export default class Creep extends GameObject {
|
||||
Engine.GameScene.events.on(CreepEvents.TakenDamage, (creepID, damage) => {
|
||||
if (creepID != this.id) return;
|
||||
this.health -= damage;
|
||||
this.UpdateHealthbar();
|
||||
});
|
||||
Engine.Grid.container.addChild(this.container);
|
||||
this.container.addChild(this.healthBarGraphics);
|
||||
this.container.addChild(this.sprite);
|
||||
this.UpdateHealthbar();
|
||||
}
|
||||
private UpdateHealthbar() {
|
||||
this.healthBarGraphics.clear();
|
||||
const hp = this.health;
|
||||
const maxHp = this.maxHealth;
|
||||
const percent = hp / maxHp;
|
||||
const width = this.healthBarWidth * percent;
|
||||
// ! TODO: MAKE THIS BETTER! It works like this now, but I don't like how its implemented.
|
||||
this.healthBarGraphics.rect(-this.healthBarWidth / 2 + 5, -30, this.healthBarWidth, 10);
|
||||
this.healthBarGraphics.fill({ color: 0x00ff00 });
|
||||
this.healthBarGraphics.rect(-this.healthBarWidth / 2 + 5, -30, width, 10);
|
||||
this.healthBarGraphics.fill({ color: 0xff0000 });
|
||||
}
|
||||
public update(elapsedMS: number) {
|
||||
if (this.dead) return;
|
||||
|
@ -37,20 +37,6 @@ export class Cell extends GameObject {
|
||||
this.clickDetector.onpointerdown = (e) => {
|
||||
Engine.Grid.onGridCellClicked(row, column);
|
||||
};
|
||||
|
||||
// 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.bb.width / 2;
|
||||
// text.y = this.bb.height / 2;
|
||||
// if (isPath) text.text += 'p';
|
||||
}
|
||||
public gDraw() {
|
||||
this.g = new PIXI.Graphics({
|
||||
@ -143,5 +129,6 @@ export class Grid extends GameObject {
|
||||
public getCellByRowAndCol(row, column) {
|
||||
return this.cells.filter((item) => item.row == row && item.column == column)[0];
|
||||
}
|
||||
// Not defined here, rather GameScene defines it. This is just for TS.
|
||||
public onGridCellClicked(row, column) {}
|
||||
}
|
||||
|
@ -11,21 +11,21 @@ export function calculateAngleToPoint(x, y, targetX, targetY) {
|
||||
|
||||
export default class Projectile extends GameObject {
|
||||
public deleteMe: boolean = false;
|
||||
public sprite: PIXI.Sprite;
|
||||
public sprite: PIXI.AnimatedSprite;
|
||||
public x: number;
|
||||
public y: number;
|
||||
public angle: number;
|
||||
public speed: number;
|
||||
public damage: number;
|
||||
public timeToLive: number = 1;
|
||||
constructor(x, y, spriteTexture, angle, damage) {
|
||||
constructor(x, y, textures, angle, damage) {
|
||||
super();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.damage = damage;
|
||||
|
||||
this.sprite = new PIXI.Sprite({ texture: spriteTexture, scale: 0.5, rotation: angle });
|
||||
this.sprite = new PIXI.AnimatedSprite({ textures: textures, scale: 0.25, rotation: angle });
|
||||
this.sprite.anchor.set(0.5);
|
||||
this.sprite.play();
|
||||
this.container.x = this.x;
|
||||
this.container.y = this.y;
|
||||
this.container.addChild(this.sprite);
|
||||
|
@ -57,17 +57,21 @@ export class Tower extends GameObject {
|
||||
this.container.addChild(this.sprite);
|
||||
parent.container.addChild(this.container);
|
||||
parent.clickDetector.onmouseenter = (e) => {
|
||||
this.graphics.circle(
|
||||
this.column * Engine.GridCellSize + Engine.GridCellSize / 2,
|
||||
this.row * Engine.GridCellSize + Engine.GridCellSize / 2,
|
||||
this.definition.stats.range * Engine.GridCellSize
|
||||
);
|
||||
this.graphics.fill({ color: 0xff0000, alpha: 0.5 });
|
||||
this.showRangeDisplay();
|
||||
};
|
||||
parent.clickDetector.onmouseleave = (e) => {
|
||||
this.graphics.clear();
|
||||
};
|
||||
Engine.GameMaster.currentScene.stage.addChild(this.graphics);
|
||||
this.showRangeDisplay();
|
||||
}
|
||||
public showRangeDisplay() {
|
||||
this.graphics.circle(
|
||||
this.column * Engine.GridCellSize + Engine.GridCellSize / 2,
|
||||
this.row * Engine.GridCellSize + Engine.GridCellSize / 2,
|
||||
this.definition.stats.range * Engine.GridCellSize
|
||||
);
|
||||
this.graphics.fill({ color: 0xff0000, alpha: 0.5 });
|
||||
}
|
||||
public GetCreepsInRange() {
|
||||
let creeps = Engine.Grid.creeps;
|
||||
@ -86,7 +90,7 @@ export class Tower extends GameObject {
|
||||
let y = this.row * Engine.GridCellSize + Engine.GridCellSize / 2;
|
||||
let angle = calculateAngleToPoint(x, y, creep.x, creep.y);
|
||||
this.projectiles.push(
|
||||
new Projectile(x, y, GameAssets.BasicProjectileTexture, angle, this.definition.stats.damage)
|
||||
new Projectile(x, y, this.definition.projectileTextures, angle, this.definition.stats.damage)
|
||||
);
|
||||
}
|
||||
public update(elapsedMS: any): void {
|
||||
|
@ -2,8 +2,8 @@ import * as PIXI from 'pixi.js';
|
||||
import { Engine } from '../Bastion';
|
||||
import { TerrainType, TowerDefinition } from '../Definitions';
|
||||
import GameAssets from '../Assets';
|
||||
import GameObject from '../GameObject';
|
||||
import { Tower, TowerEvents } from './Tower';
|
||||
import { Cell } from './Grid';
|
||||
|
||||
export enum TowerBehaviours {
|
||||
BasicTowerBehaviour = 'BasicTowerBehaviour',
|
||||
@ -34,8 +34,13 @@ export default class TowerManager {
|
||||
public PlayerClickOnGrid(row, column) {
|
||||
if (!this.canPlaceTowers) return;
|
||||
if (this.isPlacingTower) {
|
||||
if (!this.selectedTower)
|
||||
if (!this.selectedTower) {
|
||||
Engine.NotificationManager.Notify(
|
||||
'TowerManager.selectedTower is null when trying to place tower.',
|
||||
'danger'
|
||||
);
|
||||
throw console.warn('TowerManager.selectedTower is null when trying to place tower.');
|
||||
}
|
||||
this.PlaceTower(this.selectedTower, row, column, this.selectedTower.behaviour);
|
||||
}
|
||||
}
|
||||
@ -65,11 +70,13 @@ export default class TowerManager {
|
||||
let tower = new Tower(row, column, sprite, definition, behaviour);
|
||||
this.towers.push(tower);
|
||||
this.ToggleChoosingTowerLocation('RESET');
|
||||
console.log('SHOULDVE PLACED TOWER');
|
||||
console.log(this.selectedTower);
|
||||
this.selectedTower = null;
|
||||
Engine.GameScene.events.emit(TowerEvents.TowerPlacedEvent, definition.name);
|
||||
} else {
|
||||
Engine.NotificationManager.Notify(
|
||||
'Can not place tower on path or other tower, choose another spot.',
|
||||
'warn'
|
||||
);
|
||||
console.warn('Can not place tower on occupied spot or path. Try again.');
|
||||
}
|
||||
}
|
||||
|
32
src/classes/gui/SelectedTowerPanel.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import * as PIXI from 'pixi.js';
|
||||
import GuiObject from '../GuiObject';
|
||||
import GameAssets from '../Assets';
|
||||
import { Engine } from '../Bastion';
|
||||
|
||||
// ! TODO NEXT!
|
||||
|
||||
export default class SelectedTowerPanel extends GuiObject {
|
||||
private bounds: PIXI.Rectangle;
|
||||
private towerPanel: PIXI.NineSliceSprite;
|
||||
|
||||
constructor(bounds: PIXI.Rectangle) {
|
||||
super(false);
|
||||
this.bounds = bounds;
|
||||
this.container.x = this.bounds.x;
|
||||
this.container.y = this.bounds.y;
|
||||
this.towerPanel = new PIXI.NineSliceSprite({
|
||||
texture: GameAssets.FrameTowerTab,
|
||||
leftWidth: 1000,
|
||||
topHeight: 1000,
|
||||
rightWidth: 1000,
|
||||
bottomHeight: 1000,
|
||||
});
|
||||
this.towerPanel.x = -300;
|
||||
this.towerPanel.y = -300;
|
||||
this.towerPanel.width = this.bounds.width;
|
||||
this.towerPanel.height = this.bounds.height;
|
||||
|
||||
this.container.addChild(this.towerPanel);
|
||||
Engine.GameMaster.currentScene.stage.addChild(this.container);
|
||||
}
|
||||
}
|
30
src/classes/gui/Tooltip.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import * as PIXI from 'pixi.js';
|
||||
import GuiObject from '../GuiObject';
|
||||
import GameAssets from '../Assets';
|
||||
|
||||
// ! TODO NEXT!
|
||||
|
||||
export default class Tooltip extends GuiObject {
|
||||
private bounds: PIXI.Rectangle;
|
||||
private tooltipSprite: PIXI.NineSliceSprite;
|
||||
|
||||
constructor(bounds: PIXI.Rectangle) {
|
||||
super(false);
|
||||
this.bounds = bounds;
|
||||
this.container.x = this.bounds.x;
|
||||
this.container.y = this.bounds.y;
|
||||
this.tooltipSprite = new PIXI.NineSliceSprite({
|
||||
texture: GameAssets.FrameTowerTab,
|
||||
leftWidth: 1000,
|
||||
topHeight: 1000,
|
||||
rightWidth: 1000,
|
||||
bottomHeight: 1000,
|
||||
});
|
||||
this.tooltipSprite.x = 0;
|
||||
this.tooltipSprite.y = 0;
|
||||
this.tooltipSprite.width = this.bounds.width;
|
||||
this.tooltipSprite.height = this.bounds.height;
|
||||
|
||||
this.container.addChild(this.tooltipSprite);
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export function log(msg: any) {
|
||||
console.log(msg);
|
||||
}
|