2017-02-09 00:00:35 +00:00
|
|
|
module TS.SpaceTac.UI {
|
2017-05-17 21:55:39 +00:00
|
|
|
/**
|
|
|
|
* Graphical representation of a battle
|
|
|
|
*
|
|
|
|
* This is the area in the BattleView that will display ships with their real positions
|
|
|
|
*/
|
2014-12-31 00:00:00 +00:00
|
|
|
export class Arena extends Phaser.Group {
|
2017-02-12 22:18:36 +00:00
|
|
|
// Link to battleview
|
2017-05-17 21:55:39 +00:00
|
|
|
battleview: BattleView
|
2017-02-12 22:18:36 +00:00
|
|
|
|
2017-05-17 21:55:39 +00:00
|
|
|
// Boundaries of the arena
|
|
|
|
boundaries: IBounded = { x: 112, y: 132, width: 1808, height: 948 }
|
2015-01-06 00:00:00 +00:00
|
|
|
|
2015-03-03 00:00:00 +00:00
|
|
|
// Hint for weapon or move range
|
2017-05-17 21:55:39 +00:00
|
|
|
range_hint: RangeHint
|
|
|
|
|
|
|
|
// Input capture
|
|
|
|
private mouse_capture: Phaser.Button
|
2015-03-03 00:00:00 +00:00
|
|
|
|
2015-01-06 00:00:00 +00:00
|
|
|
// Input callback to receive mouse move events
|
2017-05-17 21:55:39 +00:00
|
|
|
private input_callback: any = null
|
2014-12-31 00:00:00 +00:00
|
|
|
|
2015-01-06 00:00:00 +00:00
|
|
|
// List of ship sprites
|
2017-05-17 21:55:39 +00:00
|
|
|
private ship_sprites: ArenaShip[] = []
|
2017-02-08 18:54:02 +00:00
|
|
|
|
|
|
|
// List of drone sprites
|
2017-05-17 21:55:39 +00:00
|
|
|
private drone_sprites: ArenaDrone[] = []
|
2015-01-06 00:00:00 +00:00
|
|
|
|
2015-01-23 00:00:00 +00:00
|
|
|
// Currently hovered ship
|
2017-05-17 21:55:39 +00:00
|
|
|
private hovered: ArenaShip | null
|
2015-01-23 00:00:00 +00:00
|
|
|
// Currently playing ship
|
2017-05-17 21:55:39 +00:00
|
|
|
private playing: ArenaShip | null
|
2015-01-23 00:00:00 +00:00
|
|
|
|
2017-02-13 19:31:45 +00:00
|
|
|
// Layer for particles
|
2017-05-17 21:55:39 +00:00
|
|
|
layer_garbage: Phaser.Group
|
|
|
|
layer_hints: Phaser.Group
|
|
|
|
layer_drones: Phaser.Group
|
|
|
|
layer_ships: Phaser.Group
|
|
|
|
layer_weapon_effects: Phaser.Group
|
|
|
|
layer_targetting: Phaser.Group
|
2017-02-13 19:31:45 +00:00
|
|
|
|
2015-01-21 00:00:00 +00:00
|
|
|
// Create a graphical arena for ship sprites to fight in a 2D space
|
2014-12-31 00:00:00 +00:00
|
|
|
constructor(battleview: BattleView) {
|
2016-10-26 21:15:04 +00:00
|
|
|
super(battleview.game);
|
2017-01-08 22:04:07 +00:00
|
|
|
|
2015-01-06 00:00:00 +00:00
|
|
|
this.battleview = battleview;
|
2015-01-23 00:00:00 +00:00
|
|
|
this.playing = null;
|
2015-01-23 00:00:00 +00:00
|
|
|
this.hovered = null;
|
2017-03-09 17:11:00 +00:00
|
|
|
this.range_hint = new RangeHint(this);
|
2015-01-06 00:00:00 +00:00
|
|
|
|
2017-05-17 21:55:39 +00:00
|
|
|
this.position.set(this.boundaries.x, this.boundaries.y);
|
|
|
|
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup the mouse capture for targetting events
|
|
|
|
*/
|
|
|
|
setupMouseCapture() {
|
|
|
|
let battleview = this.battleview;
|
2015-04-26 19:34:55 +00:00
|
|
|
|
2015-01-23 00:00:00 +00:00
|
|
|
var background = new Phaser.Button(battleview.game, 0, 0, "battle-arena-background");
|
2017-05-17 21:55:39 +00:00
|
|
|
background.scale.set(this.boundaries.width / background.width, this.boundaries.height / background.height);
|
|
|
|
this.mouse_capture = background;
|
2014-12-31 00:00:00 +00:00
|
|
|
|
2015-01-02 00:00:00 +00:00
|
|
|
// Capture clicks on background
|
|
|
|
background.onInputUp.add(() => {
|
|
|
|
battleview.cursorClicked();
|
|
|
|
});
|
2017-06-21 23:32:18 +00:00
|
|
|
background.onInputOut.add(() => {
|
|
|
|
battleview.targetting.setTarget(null);
|
|
|
|
});
|
2015-01-02 00:00:00 +00:00
|
|
|
|
2014-12-31 00:00:00 +00:00
|
|
|
// Watch mouse move to capture hovering over background
|
2015-01-06 00:00:00 +00:00
|
|
|
this.input_callback = this.game.input.addMoveCallback((pointer: Phaser.Pointer) => {
|
2014-12-31 00:00:00 +00:00
|
|
|
var point = new Phaser.Point();
|
|
|
|
if (battleview.game.input.hitTest(background, pointer, point)) {
|
2015-01-06 00:00:00 +00:00
|
|
|
battleview.cursorInSpace(point.x * background.scale.x, point.y * background.scale.y);
|
2014-12-31 00:00:00 +00:00
|
|
|
}
|
|
|
|
}, null);
|
|
|
|
|
2017-05-17 21:55:39 +00:00
|
|
|
this.add(this.mouse_capture);
|
2014-12-31 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
destroy() {
|
2017-05-17 21:55:39 +00:00
|
|
|
if (this.input_callback) {
|
|
|
|
this.game.input.deleteMoveCallback(this.input_callback);
|
|
|
|
this.input_callback = null;
|
|
|
|
}
|
2015-03-06 00:00:00 +00:00
|
|
|
super.destroy();
|
2014-12-31 00:00:00 +00:00
|
|
|
}
|
2015-01-06 00:00:00 +00:00
|
|
|
|
2017-05-17 21:55:39 +00:00
|
|
|
/**
|
|
|
|
* Initialize state (create sprites)
|
|
|
|
*/
|
2015-01-06 00:00:00 +00:00
|
|
|
init(): void {
|
2017-05-17 21:55:39 +00:00
|
|
|
this.setupMouseCapture();
|
|
|
|
|
|
|
|
this.layer_garbage = this.add(new Phaser.Group(this.game));
|
|
|
|
this.layer_hints = this.add(new Phaser.Group(this.game));
|
|
|
|
this.layer_drones = this.add(new Phaser.Group(this.game));
|
|
|
|
this.layer_ships = this.add(new Phaser.Group(this.game));
|
|
|
|
this.layer_weapon_effects = this.add(new Phaser.Group(this.game));
|
|
|
|
this.layer_targetting = this.add(new Phaser.Group(this.game));
|
|
|
|
|
2017-05-30 22:40:28 +00:00
|
|
|
this.range_hint.setLayer(this.layer_hints);
|
2017-05-17 21:55:39 +00:00
|
|
|
this.addShipSprites();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add the sprites for all ships
|
|
|
|
*/
|
|
|
|
addShipSprites() {
|
|
|
|
iforeach(this.battleview.battle.iships(), ship => {
|
|
|
|
let sprite = new ArenaShip(this, ship);
|
|
|
|
this.layer_ships.add(sprite);
|
2015-03-06 00:00:00 +00:00
|
|
|
this.ship_sprites.push(sprite);
|
2015-01-06 00:00:00 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-06-22 22:37:38 +00:00
|
|
|
/**
|
|
|
|
* Get all ship sprites in a circle area
|
|
|
|
*/
|
|
|
|
getShipsInCircle(area: ArenaCircleArea, alive_only = true, border_inclusive = true): ArenaShip[] {
|
|
|
|
let base = this.ship_sprites;
|
|
|
|
if (alive_only) {
|
|
|
|
base = base.filter(ship => !ship.isDead());
|
|
|
|
}
|
|
|
|
return base.filter(ship => arenaInside(ship, area, border_inclusive));
|
|
|
|
}
|
|
|
|
|
2017-02-09 00:00:35 +00:00
|
|
|
// Get the current MainUI instance
|
|
|
|
getGame(): MainUI {
|
2015-04-22 21:53:13 +00:00
|
|
|
return this.battleview.gameui;
|
|
|
|
}
|
|
|
|
|
2017-05-09 20:41:35 +00:00
|
|
|
/**
|
|
|
|
* Get the current battle displayed
|
|
|
|
*/
|
|
|
|
getBattle(): Battle {
|
|
|
|
return this.battleview.battle;
|
|
|
|
}
|
|
|
|
|
2015-02-18 00:00:00 +00:00
|
|
|
// Remove a ship sprite
|
2017-02-09 00:00:35 +00:00
|
|
|
markAsDead(ship: Ship): void {
|
2015-02-18 00:00:00 +00:00
|
|
|
var sprite = this.findShipSprite(ship);
|
|
|
|
if (sprite) {
|
2017-02-15 22:34:27 +00:00
|
|
|
sprite.setDead(true);
|
2017-05-17 23:24:42 +00:00
|
|
|
this.layer_garbage.add(sprite);
|
2015-02-18 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-06 00:00:00 +00:00
|
|
|
// Find the sprite for a ship
|
2017-03-09 17:11:00 +00:00
|
|
|
findShipSprite(ship: Ship): ArenaShip | null {
|
|
|
|
var result: ArenaShip | null = null;
|
2015-01-21 00:00:00 +00:00
|
|
|
this.ship_sprites.forEach((sprite: ArenaShip) => {
|
2015-01-06 00:00:00 +00:00
|
|
|
if (sprite.ship === ship) {
|
|
|
|
result = sprite;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return result;
|
|
|
|
}
|
2015-01-21 00:00:00 +00:00
|
|
|
|
|
|
|
// Set the hovered state on a ship sprite
|
2017-03-09 17:11:00 +00:00
|
|
|
setShipHovered(ship: Ship | null): void {
|
2015-01-23 00:00:00 +00:00
|
|
|
if (this.hovered) {
|
2017-05-23 16:42:55 +00:00
|
|
|
this.hovered.setHovered(false, false);
|
2015-01-23 00:00:00 +00:00
|
|
|
}
|
2017-03-09 17:11:00 +00:00
|
|
|
|
|
|
|
if (ship) {
|
|
|
|
var arena_ship = this.findShipSprite(ship);
|
|
|
|
if (arena_ship) {
|
2017-05-23 16:42:55 +00:00
|
|
|
arena_ship.setHovered(true, false);
|
2017-05-17 21:55:39 +00:00
|
|
|
this.layer_ships.bringToTop(arena_ship);
|
2017-03-09 17:11:00 +00:00
|
|
|
}
|
|
|
|
this.hovered = arena_ship;
|
|
|
|
} else {
|
|
|
|
this.hovered = null;
|
2015-01-21 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-23 00:00:00 +00:00
|
|
|
|
|
|
|
// Set the playing state on a ship sprite
|
2017-03-09 17:11:00 +00:00
|
|
|
setShipPlaying(ship: Ship | null): void {
|
2015-01-23 00:00:00 +00:00
|
|
|
if (this.playing) {
|
|
|
|
this.playing.setPlaying(false);
|
2017-03-09 17:11:00 +00:00
|
|
|
this.playing = null;
|
2015-01-23 00:00:00 +00:00
|
|
|
}
|
2017-03-09 17:11:00 +00:00
|
|
|
|
|
|
|
if (ship) {
|
|
|
|
var arena_ship = this.findShipSprite(ship);
|
|
|
|
if (arena_ship) {
|
2017-05-17 21:55:39 +00:00
|
|
|
this.layer_ships.bringToTop(arena_ship);
|
2017-03-09 17:11:00 +00:00
|
|
|
arena_ship.setPlaying(true);
|
|
|
|
}
|
|
|
|
this.playing = arena_ship;
|
2015-01-23 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
2017-02-08 18:54:02 +00:00
|
|
|
|
2017-02-15 21:15:31 +00:00
|
|
|
/**
|
|
|
|
* Find an ArenaDrone displaying a Drone.
|
|
|
|
*/
|
|
|
|
findDrone(drone: Drone): ArenaDrone | null {
|
|
|
|
return first(this.drone_sprites, sprite => sprite.drone == drone);
|
|
|
|
}
|
|
|
|
|
2017-02-14 00:30:50 +00:00
|
|
|
/**
|
|
|
|
* Spawn a new drone
|
|
|
|
*
|
|
|
|
* Return the duration of deploy animation
|
|
|
|
*/
|
2017-02-15 21:15:31 +00:00
|
|
|
addDrone(drone: Drone, animate = true): number {
|
|
|
|
if (!this.findDrone(drone)) {
|
2017-02-08 18:54:02 +00:00
|
|
|
let sprite = new ArenaDrone(this.battleview, drone);
|
2017-02-15 21:15:31 +00:00
|
|
|
let angle = Math.atan2(drone.y - drone.owner.arena_y, drone.x - drone.owner.arena_x);
|
2017-05-17 21:55:39 +00:00
|
|
|
this.layer_drones.add(sprite);
|
2017-02-08 18:54:02 +00:00
|
|
|
this.drone_sprites.push(sprite);
|
|
|
|
|
2017-02-15 21:15:31 +00:00
|
|
|
if (animate) {
|
|
|
|
sprite.position.set(drone.owner.arena_x, drone.owner.arena_y);
|
2017-05-22 23:05:01 +00:00
|
|
|
sprite.sprite.rotation = drone.owner.arena_angle;
|
|
|
|
let move_duration = Animations.moveInSpace(sprite, drone.x, drone.y, angle, sprite.sprite);
|
2017-02-15 21:15:31 +00:00
|
|
|
this.game.tweens.create(sprite.radius).from({ alpha: 0 }, 500, Phaser.Easing.Cubic.In, true, move_duration);
|
|
|
|
|
|
|
|
return move_duration + 500;
|
|
|
|
} else {
|
|
|
|
sprite.position.set(drone.x, drone.y);
|
2017-05-22 23:05:01 +00:00
|
|
|
sprite.sprite.rotation = angle;
|
2017-02-15 21:15:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2017-02-14 00:30:50 +00:00
|
|
|
|
2017-02-08 18:54:02 +00:00
|
|
|
} else {
|
|
|
|
console.error("Drone added twice to arena", drone);
|
2017-02-14 00:30:50 +00:00
|
|
|
return 0;
|
2017-02-08 18:54:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-10 23:13:56 +00:00
|
|
|
/**
|
|
|
|
* Remove a destroyed drone
|
|
|
|
*/
|
2017-02-09 00:00:35 +00:00
|
|
|
removeDrone(drone: Drone): void {
|
2017-02-15 21:15:31 +00:00
|
|
|
let sprite = this.findDrone(drone);
|
2017-02-08 18:54:02 +00:00
|
|
|
if (sprite) {
|
|
|
|
remove(this.drone_sprites, sprite);
|
2017-05-10 23:13:56 +00:00
|
|
|
sprite.setDestroyed();
|
2017-05-17 21:55:39 +00:00
|
|
|
this.layer_garbage.add(sprite);
|
2017-02-08 18:54:02 +00:00
|
|
|
} else {
|
|
|
|
console.error("Drone not found in arena for removal", drone);
|
|
|
|
}
|
|
|
|
}
|
2017-05-09 18:17:49 +00:00
|
|
|
|
2017-05-15 18:30:44 +00:00
|
|
|
/**
|
2017-05-16 23:31:23 +00:00
|
|
|
* Switch the tactical mode (shows information on all ships, and fades background)
|
2017-05-15 18:30:44 +00:00
|
|
|
*/
|
2017-05-16 23:31:23 +00:00
|
|
|
setTacticalMode(active: boolean): void {
|
2017-05-23 16:42:55 +00:00
|
|
|
this.ship_sprites.forEach(sprite => sprite.setHovered(active, true));
|
2017-05-21 16:39:02 +00:00
|
|
|
this.drone_sprites.forEach(drone => drone.setTacticalMode(active));
|
2017-05-17 21:55:39 +00:00
|
|
|
this.battleview.animations.setVisible(this.layer_garbage, !active, 200);
|
2017-05-15 18:30:44 +00:00
|
|
|
if (this.battleview.background) {
|
|
|
|
this.battleview.animations.setVisible(this.battleview.background, !active, 200);
|
|
|
|
}
|
|
|
|
}
|
2017-05-16 23:12:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the boundaries of the arena on display
|
|
|
|
*/
|
|
|
|
getBoundaries(): IBounded {
|
2017-05-30 22:40:28 +00:00
|
|
|
return this.boundaries;
|
2017-05-16 23:12:05 +00:00
|
|
|
}
|
2014-12-31 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|