1
0
Fork 0

Added some helpful tooltips

This commit is contained in:
Michaël Lemaire 2017-03-15 22:40:19 +01:00
parent a4506d76fa
commit 53a8772cbe
17 changed files with 254 additions and 64 deletions

View file

@ -3,7 +3,7 @@
module TS.SpaceTac.Equipments {
export class IronHull extends LootTemplate {
constructor() {
super(SlotType.Hull, "IronHull");
super(SlotType.Hull, "Iron Hull");
this.min_level = new IntegerRange(1, 3);

View file

@ -15,6 +15,12 @@ module TS.SpaceTac.UI {
// Timing
timer: Timer;
// Tooltip
tooltip: Tooltip;
// Layers
layers: Phaser.Group;
// Get the size of display
getWidth(): number {
return this.game.width || 1280;
@ -35,12 +41,20 @@ module TS.SpaceTac.UI {
}
create() {
this.game.stage.backgroundColor = 0x000000;
// View layers
this.layers = this.add.group();
// Notifications
this.messages = new Messages(this);
// Input manager
this.inputs = new InputManager(this);
// Tooltip
this.tooltip = new Tooltip(this);
// Browser console variable (for debugging purpose)
if (typeof window != "undefined") {
let session = this.gameui.session;
@ -60,5 +74,13 @@ module TS.SpaceTac.UI {
this.timer.cancelAll(true);
}
/**
* Add a new layer in the view
*/
addLayer(): Phaser.Group {
let layer = this.add.group(this.layers);
return layer;
}
}
}

View file

@ -8,16 +8,12 @@ module TS.SpaceTac.UI.Specs {
it("adds moving stars, a title and three buttons", function () {
let view = <MainMenu>testgame.ui.state.getCurrentState();
expect(view.world.children.length).toBe(301);
let group = <Phaser.Group>view.world.children[300];
expect(group instanceof Phaser.Group).toBe(true);
expect(group.children.length).toBe(4);
expect(group.children[0] instanceof Phaser.Button).toBe(true);
expect(group.children[1] instanceof Phaser.Button).toBe(true);
expect(group.children[2] instanceof Phaser.Button).toBe(true);
expect(group.children[3] instanceof Phaser.Image).toBe(true);
expect(view.layer_stars.children.length).toBe(300);
expect(view.layer_title.children.length).toBe(4);
expect(view.layer_title.children[0] instanceof Phaser.Button).toBe(true);
expect(view.layer_title.children[1] instanceof Phaser.Button).toBe(true);
expect(view.layer_title.children[2] instanceof Phaser.Button).toBe(true);
expect(view.layer_title.children[3] instanceof Phaser.Image).toBe(true);
});
});
}

View file

@ -2,42 +2,44 @@
module TS.SpaceTac.UI {
export class MainMenu extends BaseView {
group: Phaser.Group;
layer_stars: Phaser.Group;
layer_title: Phaser.Group;
button_new_game: Phaser.Button;
button_quick_battle: Phaser.Button;
button_load_game: Phaser.Button;
create() {
this.game.stage.backgroundColor = "#000000";
super.create();
this.layer_stars = this.addLayer();
this.layer_title = this.addLayer();
this.layer_title.x = 5000;
// Stars
for (let i = 0; i < 300; i++) {
let fade = Math.random() * 0.5 + 0.5;
let x = Math.random() * 0.998 + 0.001;
let star = this.add.image(1920 * x, Math.random() * 1080, "menu-star");
let star = this.add.image(1920 * x, Math.random() * 1080, "menu-star", 0, this.layer_stars);
star.anchor.set(0.5, 0.5);
star.alpha = 0.7 * fade;
star.scale.set(0.1 * fade, 0.1 * fade);
this.tweens.create(star).to({ x: -30 }, 30000 * x / fade).to({ x: 1950 }, 0.00001).to({ x: 1920 * x }, 30000 * (1 - x) / fade).loop().start();
}
this.group = this.add.group();
this.group.x = 5000;
// Menu buttons
this.button_new_game = this.addButton(322, 674, "New Game", this.onNewGame);
this.button_load_game = this.addButton(960, 674, "Load Game", this.onLoadGame);
this.button_quick_battle = this.addButton(1606, 674, "Quick Battle", this.onQuickBattle);
this.button_new_game = this.addButton(322, 674, "New Game", "Start a new campaign in a generated universe", this.onNewGame);
this.button_load_game = this.addButton(960, 674, "Load Game", "Load a saved campaign", this.onLoadGame);
this.button_quick_battle = this.addButton(1606, 674, "Quick Battle", "Play a single generated battle", this.onQuickBattle);
// Title
let title = this.add.image(960, 225, "menu-title", 0, this.group);
let title = this.add.image(960, 225, "menu-title", 0, this.layer_title);
title.anchor.set(0.5, 0);
this.tweens.create(this.group).to({ x: 0 }, 3000, Phaser.Easing.Circular.Out).start();
this.tweens.create(this.layer_title).to({ x: 0 }, 3000, Phaser.Easing.Circular.Out).start();
}
addButton(x: number, y: number, caption: string, callback: Function): Phaser.Button {
var button = this.add.button(x - 20, y + 20, "menu-button", callback, this, null, null, null, null, this.group);
addButton(x: number, y: number, caption: string, tooltip: string, callback: Function): Phaser.Button {
var button = this.add.button(x - 20, y + 20, "menu-button", callback, this, null, null, null, null, this.layer_title);
button.anchor.set(0.5, 0);
button.input.useHandCursor = true;
@ -55,6 +57,8 @@ module TS.SpaceTac.UI {
text.fill = "#529aee";
});
this.tooltip.bindStaticText(button, tooltip);
return button;
}

View file

@ -33,7 +33,7 @@ module TS.SpaceTac.UI {
this.action_icons = [];
this.ship = null;
battleview.ui.add(this);
battleview.layer_borders.add(this);
// Background
this.addChild(new Phaser.Image(this.game, 0, 0, "battle-actionbar", 0));

View file

@ -136,6 +136,7 @@ module TS.SpaceTac.UI {
if (ship) {
var arena_ship = this.findShipSprite(ship);
if (arena_ship) {
this.bringToTop(arena_ship);
arena_ship.setPlaying(true);
}
this.playing = arena_ship;

View file

@ -10,8 +10,13 @@ module TS.SpaceTac.UI {
// Interacting player
player: Player;
// UI container
ui: Phaser.Group;
// Layers
layer_background: Phaser.Group;
layer_arena: Phaser.Group;
layer_borders: Phaser.Group;
layer_overlay: Phaser.Group;
layer_dialogs: Phaser.Group;
layer_sheets: Phaser.Group;
// Battleground container
arena: Arena;
@ -67,28 +72,31 @@ module TS.SpaceTac.UI {
var game = this.game;
// Add layers
this.layer_background = this.addLayer();
this.layer_arena = this.addLayer();
this.layer_borders = this.addLayer();
this.layer_overlay = this.addLayer();
this.layer_dialogs = this.addLayer();
this.layer_sheets = this.addLayer();
// Background
game.stage.backgroundColor = 0x000000;
this.background = new Phaser.Image(game, 0, 0, "battle-background", 0);
game.add.existing(this.background);
this.layer_background.add(this.background);
// Add arena (local map)
this.arena = new Arena(this);
game.add.existing(this.arena);
// Add UI layer
this.ui = new Phaser.Group(game);
game.add.existing(this.ui);
this.layer_arena.add(this.arena);
// Add UI elements
this.action_bar = new ActionBar(this);
this.ship_list = new ShipList(this);
this.ship_tooltip = new ShipTooltip(this);
this.add.existing(this.ship_tooltip);
this.layer_overlay.add(this.ship_tooltip);
this.outcome_layer = new Phaser.Group(this.game);
this.add.existing(this.outcome_layer);
this.layer_dialogs.add(this.outcome_layer);
this.character_sheet = new CharacterSheet(this, -this.getWidth());
this.add.existing(this.character_sheet);
this.layer_sheets.add(this.character_sheet);
// "Battle" animation
this.displayFightMessage();
@ -129,8 +137,6 @@ module TS.SpaceTac.UI {
this.exitTargettingMode();
this.log_processor.destroy();
this.ui.destroy();
this.arena.destroy();
super.shutdown();
}

View file

@ -13,26 +13,36 @@ module TS.SpaceTac.UI {
this.addChild(title);
if (victory) {
this.addChild(new Phaser.Button(this.game, 344, 842, "battle-outcome-button-loot", () => {
let button = new Phaser.Button(this.game, 344, 842, "battle-outcome-button-loot", () => {
// Open loot screen
if (outcome.winner) {
parent.character_sheet.show(outcome.winner.ships[0]);
parent.character_sheet.setLoot(outcome.loot);
}
}));
this.addChild(new Phaser.Button(this.game, 766, 842, "battle-outcome-button-map", () => {
})
parent.tooltip.bindStaticText(button, "Open character sheet to loot equipment from defeated fleet");
this.addChild(button);
button = new Phaser.Button(this.game, 766, 842, "battle-outcome-button-map", () => {
// Exit battle and go back to map
parent.exitBattle();
}));
});
parent.tooltip.bindStaticText(button, "Exit the battle and go back to the map");
this.addChild(button);
} else {
this.addChild(new Phaser.Button(this.game, 344, 842, "battle-outcome-button-revert", () => {
let button = new Phaser.Button(this.game, 344, 842, "battle-outcome-button-revert", () => {
// Revert just before battle
parent.revertBattle();
}));
this.addChild(new Phaser.Button(this.game, 766, 842, "battle-outcome-button-menu", () => {
});
parent.tooltip.bindStaticText(button, "Go back to where the fleet was before the battle happened");
this.addChild(button);
button = new Phaser.Button(this.game, 766, 842, "battle-outcome-button-menu", () => {
// Quit the game, and go back to menu
parent.gameui.quitGame();
}));
});
parent.tooltip.bindStaticText(button, "Quit the game, and go back to main menu");
this.addChild(button);
}
}
}

View file

@ -22,7 +22,7 @@ module TS.SpaceTac.UI {
this.playing = null;
this.hovered = null;
battleview.ui.add(this);
battleview.layer_borders.add(this);
if (battleview.battle) {
this.setShipsFromBattle(battleview.battle);

View file

@ -9,7 +9,7 @@ module TS.SpaceTac.UI {
/**
* Display a ship equipment, either attached to a slot, in cargo, or being dragged down
*/
export class CharacterEquipment extends Phaser.Image {
export class CharacterEquipment extends Phaser.Button {
equipment: Equipment;
constructor(sheet: CharacterSheet, equipment: Equipment) {
@ -22,6 +22,9 @@ module TS.SpaceTac.UI {
this.scale.set(0.5, 0.5);
this.setupDragDrop(sheet);
// TODO better tooltip
sheet.view.tooltip.bindStaticText(this, equipment.name);
}
/**

View file

@ -8,6 +8,9 @@ module TS.SpaceTac.UI {
* Character sheet, displaying ship characteristics
*/
export class CharacterSheet extends Phaser.Image {
// Parent view
view: BaseView;
// X positions
xshown: number;
xhidden: number;
@ -52,6 +55,8 @@ module TS.SpaceTac.UI {
constructor(view: BaseView, xhidden = -2000, xshown = 0) {
super(view.game, 0, 0, "character-sheet");
this.view = view;
this.x = xhidden;
this.xshown = xshown;
this.xhidden = xhidden;
@ -60,6 +65,7 @@ module TS.SpaceTac.UI {
let close_button = new Phaser.Button(this.game, view.getWidth(), 0, "character-close", () => this.hide());
close_button.anchor.set(1, 0);
this.addChild(close_button);
view.tooltip.bindStaticText(close_button, "Close the character sheet");
this.ship_name = new Phaser.Text(this.game, 758, 48, "", { align: "center", font: "30pt Arial", fill: "#FFFFFF" });
this.ship_name.anchor.set(0.5, 0.5);
@ -147,6 +153,8 @@ module TS.SpaceTac.UI {
let portrait_pic = new Phaser.Image(this.game, 0, 0, `ship-${ship.model}-portrait`);
portrait_pic.anchor.set(0.5, 0.5);
new_portrait.addChild(portrait_pic);
this.view.tooltip.bindDynamicText(new_portrait, () => ship.name);
}
});

View file

@ -10,9 +10,10 @@ module TS.SpaceTac.UI {
this.sheet = sheet;
let sloticon = new Phaser.Image(this.game, 150, 150, `character-slot-${SlotType[slot].toLowerCase()}`);
let sloticon = new Phaser.Button(this.game, 150, 150, `character-slot-${SlotType[slot].toLowerCase()}`);
sloticon.anchor.set(0.5, 0.5);
this.addChild(sloticon);
sheet.view.tooltip.bindStaticText(sloticon, `${SlotType[slot]} slot`);
}
/**

View file

@ -2,6 +2,18 @@ module TS.SpaceTac.UI.Specs {
describe("Tools", function () {
let testgame = setupEmptyView();
it("keeps objects inside bounds", function () {
let image = testgame.baseview.add.graphics(150, 100);
image.beginFill(0xff0000);
image.drawEllipse(50, 25, 50, 25);
image.endFill();
Tools.keepInside(image, { x: 0, y: 0, width: 200, height: 200 });
expect(image.x).toBe(100);
expect(image.y).toBe(100);
});
it("normalizes angles", function () {
expect(Tools.normalizeAngle(0)).toEqual(0);
expect(Tools.normalizeAngle(0.1)).toBeCloseTo(0.1, 0.000001);

View file

@ -1,6 +1,26 @@
module TS.SpaceTac.UI {
// Common UI tools functions
export class Tools {
/**
* Reposition an object to remain inside a container
*/
static keepInside(obj: Phaser.Button | Phaser.Sprite | Phaser.Image | Phaser.Group | Phaser.Graphics, rect: { x: number, y: number, width: number, height: number }) {
let objbounds = obj.getBounds();
if (obj.y + objbounds.height > rect.height) {
obj.y = rect.height - objbounds.height;
}
if (obj.y < 0) {
obj.y = 0;
}
if (obj.x + objbounds.width > rect.width) {
obj.x = rect.width - objbounds.width;
}
if (obj.x < 0) {
obj.x = 0;
}
}
/**
* Setup a hover/hold/click routine on an object
@ -39,6 +59,12 @@ module TS.SpaceTac.UI {
}
}
if (obj.events) {
obj.events.onDestroy.addOnce(() => {
prevententer();
});
}
obj.onInputOver.add(() => {
cursorinside = true;
enternext = Timer.global.schedule(hovertime, effectiveenter);

73
src/ui/common/Tooltip.ts Normal file
View file

@ -0,0 +1,73 @@
module TS.SpaceTac.UI {
/**
* Tooltip system, to display information on hover
*/
export class Tooltip {
private view: BaseView;
private container: Phaser.Group;
constructor(view: BaseView) {
this.view = view;
this.container = new Phaser.Group(view.game);
}
/**
* Bind to an UI component
*
* When the component is hovered, the function is called to allow filling the tooltip container
*/
bind(obj: Phaser.Button, func: (container: Phaser.Group) => boolean): void {
Tools.setHoverClick(obj,
// enter
() => {
this.container.visible = false;
if (func(this.container)) {
// position
let bounds = obj.getBounds();
this.container.position.set(bounds.x + bounds.width + 4, bounds.y + bounds.height + 4);
// add background
let ttbounds = this.container.getBounds();
let background = new Phaser.Graphics(this.container.game, 0, 0);
this.container.add(background);
background.beginFill(0x202225, 0.8);
background.drawRect(-10, -10, ttbounds.width + 20, ttbounds.height + 20);
background.endFill();
this.container.sendToBack(background);
// display
Tools.keepInside(this.container, { x: 0, y: 0, width: this.view.getWidth(), height: this.view.getHeight() });
this.container.visible = true;
}
},
// leave
() => {
this.container.removeAll(true);
this.container.visible = false;
},
// click
() => {
this.container.removeAll(true);
this.container.visible = false;
}
);
}
/**
* Bind to an UI component to display a dynamic text
*/
bindDynamicText(obj: Phaser.Button, text_getter: () => string): void {
this.bind(obj, container => {
container.add(new Phaser.Text(container.game, 0, 0, text_getter(), { font: "bold 20pt Arial", fill: "#cccccc" }));
return true;
});
}
/**
* Bind to an UI component to display a simple text
*/
bindStaticText(obj: Phaser.Button, text: string): void {
this.bindDynamicText(obj, () => text);
}
}
}

View file

@ -1,6 +1,8 @@
module TS.SpaceTac.UI {
// Group to display a star system
export class StarSystemDisplay extends Phaser.Image {
view: UniverseMapView;
circles: Phaser.Group;
starsystem: Star;
player: Player;
fleet_display: FleetDisplay;
@ -9,6 +11,8 @@ module TS.SpaceTac.UI {
constructor(parent: UniverseMapView, starsystem: Star) {
super(parent.game, starsystem.x, starsystem.y, "map-starsystem-background");
this.view = parent;
this.anchor.set(0.5, 0.5);
let scale = this.width;
@ -19,6 +23,8 @@ module TS.SpaceTac.UI {
this.fleet_display = parent.player_fleet;
// Show boundary
this.circles = new Phaser.Group(this.game);
this.addChild(this.circles);
this.addCircle(starsystem.radius);
// Show locations
@ -36,6 +42,17 @@ module TS.SpaceTac.UI {
location_sprite = this.addImage(location.x, location.y, "map-location-warp", fleet_move);
}
this.view.tooltip.bindDynamicText(<Phaser.Button>location_sprite, () => {
if (location == this.player.fleet.location) {
return "Current fleet location";
} else {
let visited = this.player.hasVisitedLocation(location);
let loctype = StarLocationType[location.type].toLowerCase();
let danger = (visited && location.encounter) ? " [enemy fleet detected !]" : "";
return `${visited ? "Visited" : "Unvisited"} ${loctype} - Move the fleet there${danger}`;
}
});
if (location_sprite) {
let key = this.getVisitedKey(location);
let status_badge = this.addImage(location.x + 0.005, location.y + 0.005, key);
@ -57,7 +74,7 @@ module TS.SpaceTac.UI {
let circle = this.game.add.graphics(0, 0);
circle.lineStyle(width, color);
circle.drawCircle(0, 0, radius * 2 / this.scale.x);
this.addChild(circle);
this.circles.add(circle);
return circle;
}

View file

@ -11,8 +11,11 @@ module TS.SpaceTac.UI {
// Interacting player
player = new Player();
// Layers
layer_universe: Phaser.Group;
layer_overlay: Phaser.Group;
// Star systems
group: Phaser.Group;
starsystems: StarSystemDisplay[] = [];
starlinks: Phaser.Graphics[] = [];
@ -44,8 +47,8 @@ module TS.SpaceTac.UI {
create() {
super.create();
this.group = new Phaser.Group(this.game);
this.add.existing(this.group);
this.layer_universe = this.addLayer();
this.layer_overlay = this.addLayer();
this.starlinks = this.universe.starlinks.map(starlink => {
let loc1 = starlink.first.getWarpLocationTo(starlink.second);
@ -59,33 +62,41 @@ module TS.SpaceTac.UI {
}
return result;
});
this.starlinks.forEach(starlink => this.group.addChild(starlink));
this.starlinks.forEach(starlink => this.layer_universe.add(starlink));
this.player_fleet = new FleetDisplay(this, this.player.fleet);
this.starsystems = this.universe.stars.map(star => new StarSystemDisplay(this, star));
this.starsystems.forEach(starsystem => this.group.addChild(starsystem));
this.starsystems.forEach(starsystem => this.layer_universe.add(starsystem));
this.group.addChild(this.player_fleet);
this.layer_universe.add(this.player_fleet);
this.button_jump = new Phaser.Button(this.game, 0, 0, "map-button-jump", () => this.doJump());
this.button_jump.anchor.set(0.5, 0.5);
this.button_jump.visible = false;
this.group.addChild(this.button_jump);
this.layer_universe.add(this.button_jump);
this.tooltip.bindStaticText(this.button_jump, "Engage warp drive to jump to another star system");
this.setZoom(2);
this.add.button(1520, 100, "map-zoom-in", () => this.setZoom(this.zoom + 1)).anchor.set(0.5, 0.5);
this.add.button(1520, 980, "map-zoom-out", () => this.setZoom(this.zoom - 1)).anchor.set(0.5, 0.5);
let button = new Phaser.Button(this.game, 1520, 100, "map-zoom-in", () => this.setZoom(this.zoom + 1));
button.anchor.set(0.5, 0.5);
this.layer_overlay.add(button);
this.tooltip.bindStaticText(button, "Zoom in");
button = new Phaser.Button(this.game, 1520, 980, "map-zoom-out", () => this.setZoom(this.zoom - 1));
button.anchor.set(0.5, 0.5);
this.layer_overlay.add(button);
this.tooltip.bindStaticText(button, "Zoom out");
this.character_sheet = new CharacterSheet(this, this.getWidth() - 307);
this.character_sheet.show(this.player.fleet.ships[0], false);
this.character_sheet.hide(false);
this.add.existing(this.character_sheet);
this.layer_overlay.add(this.character_sheet);
this.gameui.audio.startMusic("walking-along");
// Inputs
this.inputs.bindCheat(Phaser.Keyboard.R, "Reveal whole map", this.revealAll);
this.setZoom(2);
}
/**
@ -132,8 +143,8 @@ module TS.SpaceTac.UI {
*/
setCamera(x: number, y: number, span: number, duration = 500, easing = Phaser.Easing.Cubic.InOut) {
let scale = 1000 / span;
this.tweens.create(this.group.position).to({ x: 800 - x * scale, y: 540 - y * scale }, duration, easing).start();
this.tweens.create(this.group.scale).to({ x: scale, y: scale }, duration, easing).start();
this.tweens.create(this.layer_universe.position).to({ x: 800 - x * scale, y: 540 - y * scale }, duration, easing).start();
this.tweens.create(this.layer_universe.scale).to({ x: scale, y: scale }, duration, easing).start();
}
/**