diff --git a/src/scripts/game/Battle.ts b/src/scripts/game/Battle.ts index 643a551..fcba39f 100644 --- a/src/scripts/game/Battle.ts +++ b/src/scripts/game/Battle.ts @@ -14,30 +14,61 @@ module SpaceTac.Game { } // Create play order, performing an initiative throw - throwInitiative(gen: RandomGenerator) { + throwInitiative(gen: RandomGenerator = new RandomGenerator()): void { var play_order: Ship[] = []; // Throw each ship's initiative - this.fleets.forEach(function(fleet){ - fleet.ships.forEach(function(ship){ + this.fleets.forEach(function (fleet) { + fleet.ships.forEach(function (ship) { ship.throwInitiative(gen); play_order.push(ship); }); }); // Sort by throw result - play_order.sort(function(ship1: Ship, ship2: Ship) { + play_order.sort(function (ship1: Ship, ship2: Ship) { return (ship2.initative_throw - ship1.initative_throw); }); this.play_order = play_order; } + // Defines the initial ship positions for one fleet + // x and y are the center of the fleet placement + // facing_angle is the forward angle in radians + private placeFleetShips(fleet: Fleet, x: number, y: number, facing_angle: number): void { + var side_angle = facing_angle + Math.PI * 0.5; + var spacing = 50; + var total_length = spacing * (fleet.ships.length - 1); + var dx = Math.cos(side_angle); + var dy = Math.sin(side_angle); + x -= dx * total_length * 0.5; + y -= dy * total_length * 0.5; + for (var i = 0; i < fleet.ships.length; i++) { + fleet.ships[i].setArenaPosition(x + i * dx * spacing, y + i * dy * spacing); + fleet.ships[i].setArenaFacingAngle(facing_angle); + } + } + + // Defines the initial ship positions of all engaged fleets + placeShips(): void { + this.placeFleetShips(this.fleets[0], 100, 100, 0); + this.placeFleetShips(this.fleets[1], 300, 100, Math.PI); + } + + // Start the battle + // This will call all necessary initialization steps (initiative, placement...) + start(): void { + this.placeShips(); + this.throwInitiative(); + } + // Create a quick random battle, for testing purposes static newQuickRandom(): Battle { - var player1 = Player.newQuickRandom(); - var player2 = Player.newQuickRandom(); + var player1 = Player.newQuickRandom("John"); + var player2 = Player.newQuickRandom("Carl"); var result = new Battle(player1.fleet, player2.fleet); + result.start(); return result; } } diff --git a/src/scripts/game/Player.ts b/src/scripts/game/Player.ts index f0848ce..01f36d9 100644 --- a/src/scripts/game/Player.ts +++ b/src/scripts/game/Player.ts @@ -10,8 +10,14 @@ module SpaceTac.Game { } // Create a quick random player, with a fleet, for testing purposes - static newQuickRandom(): Player { + static newQuickRandom(name: String): Player { var player = new Player(); + + new Ship(player.fleet, name + "'s First"); + new Ship(player.fleet, name + "'s Second"); + new Ship(player.fleet, name + "'s Third"); + new Ship(player.fleet, name + "'s Fourth"); + return player; } } diff --git a/src/scripts/game/Ship.ts b/src/scripts/game/Ship.ts index 840bd0d..b0725e9 100644 --- a/src/scripts/game/Ship.ts +++ b/src/scripts/game/Ship.ts @@ -16,6 +16,13 @@ module SpaceTac.Game { // Number of hull points hull: number; + // Position in the arena + arena_x: number; + arena_y: number; + + // Facing direction in the arena + arena_angle: number; + // Current initiative level (high numbers will allow this ship to play sooner) initiative_level: number; @@ -31,6 +38,17 @@ module SpaceTac.Game { fleet.addShip(this); } + // Set position in the arena + setArenaPosition(x: number, y: number) { + this.arena_x = x; + this.arena_y = y; + } + + // Set facing angle in the arena + setArenaFacingAngle(angle: number) { + this.arena_angle = angle; + } + // String repr jasmineToString(): string { return "Ship " + this.name; @@ -40,5 +58,10 @@ module SpaceTac.Game { throwInitiative(gen: RandomGenerator): void { this.initative_throw = gen.throw(this.initiative_level); } + + // Return the player owning this ship + getPlayer(): Player { + return this.fleet.player; + } } } \ No newline at end of file diff --git a/src/scripts/specs/Battle.spec.ts b/src/scripts/specs/Battle.spec.ts index fdae0dd..bda0016 100644 --- a/src/scripts/specs/Battle.spec.ts +++ b/src/scripts/specs/Battle.spec.ts @@ -1,8 +1,8 @@ /// module SpaceTac.Specs { - describe("Battle", function(){ - it("defines play order by initiative throws", function(){ + describe("Battle", function () { + it("defines play order by initiative throws", function () { var fleet1 = new Game.Fleet(null); var fleet2 = new Game.Fleet(null); @@ -26,5 +26,39 @@ module SpaceTac.Specs { expect(battle.play_order.length).toBe(5); expect(battle.play_order).toEqual([ship1, ship4, ship5, ship3, ship2]); }); + + it("places ships on lines, facing the arena center", function(){ + var fleet1 = new Game.Fleet(null); + var fleet2 = new Game.Fleet(null); + + var ship1 = new Game.Ship(fleet1, "F1S1"); + var ship2 = new Game.Ship(fleet1, "F1S2"); + var ship3 = new Game.Ship(fleet1, "F1S3"); + var ship4 = new Game.Ship(fleet2, "F2S1"); + var ship5 = new Game.Ship(fleet2, "F2S2"); + + var battle = new Game.Battle(fleet1, fleet2); + battle.placeShips(); + + expect(ship1.arena_x).toBeCloseTo(100, 0.0001); + expect(ship1.arena_y).toBeCloseTo(50, 0.0001); + expect(ship1.arena_angle).toBeCloseTo(0, 0.0001); + + expect(ship2.arena_x).toBeCloseTo(100, 0.0001); + expect(ship2.arena_y).toBeCloseTo(100, 0.0001); + expect(ship2.arena_angle).toBeCloseTo(0, 0.0001); + + expect(ship3.arena_x).toBeCloseTo(100, 0.0001); + expect(ship3.arena_y).toBeCloseTo(150, 0.0001); + expect(ship3.arena_angle).toBeCloseTo(0, 0.0001); + + expect(ship4.arena_x).toBeCloseTo(300, 0.0001); + expect(ship4.arena_y).toBeCloseTo(125, 0.0001); + expect(ship4.arena_angle).toBeCloseTo(Math.PI, 0.0001); + + expect(ship5.arena_x).toBeCloseTo(300, 0.0001); + expect(ship5.arena_y).toBeCloseTo(75, 0.0001); + expect(ship5.arena_angle).toBeCloseTo(Math.PI, 0.0001); + }); }); } diff --git a/src/scripts/view/BattleView.ts b/src/scripts/view/BattleView.ts index 85e8d8c..1bb43dc 100644 --- a/src/scripts/view/BattleView.ts +++ b/src/scripts/view/BattleView.ts @@ -5,19 +5,56 @@ module SpaceTac.View { // Displayed battle battle: Game.Battle; + // Interacting player + player: Game.Player; + + // UI container + ui: UIGroup; + + // Battleground container + arena: Phaser.Group; + // Init the view, binding it to a specific battle - init(battle) { + init(player, battle) { + this.player = player; this.battle = battle; } // Create view graphics create() { - this.game.stage.backgroundColor = 0x000000; + var game = this.game; + var player = this.player; + + this.ui = new UIGroup(game); + game.add.existing(this.ui); + var ui = this.ui; + + this.arena = new Phaser.Group(game); + game.add.existing(this.arena); + var arena = this.arena; + + game.stage.backgroundColor = 0x000000; + + // Add ship buttons to UI + this.battle.play_order.forEach(function(ship: Game.Ship, rank: number){ + new Widgets.ShipListItem(ui, 0, rank * 50, ship.getPlayer() === player); + }); + + // Add ship sprites to arena + this.battle.play_order.forEach(function(ship: Game.Ship){ + new Arena.ShipArenaSprite(arena, ship); + }); } // Leaving the view, we unbind the battle shutdown() { this.battle = null; + + this.ui.destroy(); + this.ui = null; + + this.arena.destroy(); + this.arena = null; } } } diff --git a/src/scripts/view/Main.ts b/src/scripts/view/Main.ts index 6747dc3..ec75a0e 100644 --- a/src/scripts/view/Main.ts +++ b/src/scripts/view/Main.ts @@ -2,10 +2,9 @@ module SpaceTac.View { export class Main extends Phaser.State { create() { - this.add.text(10, 10, "Let's code !", {font: "65px Arial"}); - // Switch to a test battle - this.game.state.start("battle", true, false, Game.Battle.newQuickRandom()); + var battle = Game.Battle.newQuickRandom(); + this.game.state.start("battle", true, false, battle.fleets[0].player, battle); } } } diff --git a/src/scripts/view/Preload.ts b/src/scripts/view/Preload.ts index b26a9f1..2f07033 100644 --- a/src/scripts/view/Preload.ts +++ b/src/scripts/view/Preload.ts @@ -3,7 +3,14 @@ module SpaceTac.View { private preloadBar: Phaser.Sprite; preload() { + // Add preload sprite this.preloadBar = this.add.sprite(290, 290, 'preload-bar'); + this.load.setPreloadSprite(this.preloadBar); + + // Load assets + this.load.image("ui-shiplist-own", "assets/images/ui/shiplist-own.png"); + this.load.image("ui-shiplist-enemy", "assets/images/ui/shiplist-enemy.png"); + this.load.image("arena-ship", "assets/images/arena/ship01.png"); } create() { diff --git a/src/scripts/view/UIGroup.ts b/src/scripts/view/UIGroup.ts new file mode 100644 index 0000000..a1b5bd2 --- /dev/null +++ b/src/scripts/view/UIGroup.ts @@ -0,0 +1,6 @@ +module SpaceTac.View { + // Phaser Group to hold UI related objects + export class UIGroup extends Phaser.Group { + + } +} diff --git a/src/scripts/view/arena/ShipArenaSprite.ts b/src/scripts/view/arena/ShipArenaSprite.ts new file mode 100644 index 0000000..adc5f27 --- /dev/null +++ b/src/scripts/view/arena/ShipArenaSprite.ts @@ -0,0 +1,14 @@ +module SpaceTac.Arena { + // Ship sprite in the arena (BattleView) + export class ShipArenaSprite extends Phaser.Sprite { + constructor(arena: Phaser.Group, ship: Game.Ship) { + super(arena.game, ship.arena_x, ship.arena_y, "arena-ship"); + + this.scale.set(0.1, 0.1); + this.rotation = ship.arena_angle; + this.anchor.set(0.5, 0.5); + + arena.add(this); + } + } +} diff --git a/src/scripts/view/widgets/ShipListItem.ts b/src/scripts/view/widgets/ShipListItem.ts new file mode 100644 index 0000000..5d3f872 --- /dev/null +++ b/src/scripts/view/widgets/ShipListItem.ts @@ -0,0 +1,10 @@ +module SpaceTac.View.Widgets { + // One item in a ship list (used in BattleView) + export class ShipListItem extends Phaser.Button { + // Create a ship button for the battle ship list + constructor(ui: UIGroup, x: number, y: number, owned: boolean) { + super(ui.game, x, y, owned ? 'ui-shiplist-own' : 'ui-shiplist-enemy'); + ui.add(this); + } + } +} \ No newline at end of file