New title screen

This commit is contained in:
Michaël Lemaire 2018-04-12 18:30:08 +02:00
父節點 b4b54c8e2d
當前提交 c625b215de
共有 31 個文件被更改,包括 1290 次插入657 次删除

1
.gitignore vendored
查看文件

@ -5,5 +5,6 @@ coverage
/out/assets
/out/build.*
/graphics/**/*.blend?*
/graphics/**/output.png
/typings/
*.log

Binary file not shown.

After

Width:  |  Height:  |  大小: 609 B

Binary file not shown.

After

Width:  |  Height:  |  大小: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  大小: 612 B

Binary file not shown.

After

Width:  |  Height:  |  大小: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  大小: 407 KiB

Binary file not shown.

Before

Width:  |  Height:  |  大小: 32 KiB

After

Width:  |  Height:  |  大小: 4.1 KiB

二進制
data/stage1/image/menu/button-on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  大小: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  大小: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  大小: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  大小: 33 KiB

After

Width:  |  Height:  |  大小: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  大小: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  大小: 13 KiB

二進制
data/stage1/image/menu/input.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  大小: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  大小: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  大小: 216 KiB

After

Width:  |  Height:  |  大小: 266 KiB

二進制
graphics/title/metal1.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  大小: 539 KiB

二進制
graphics/title/metal2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  大小: 417 KiB

二進制
graphics/title/starmap.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  大小: 1.2 MiB

二進制
graphics/title/title.blend Normal file

Binary file not shown.

文件差異過大導致無法顯示 Load Diff

Before

Width:  |  Height:  |  大小: 40 KiB

After

Width:  |  Height:  |  大小: 72 KiB

查看文件

@ -110,11 +110,11 @@ module TK.SpaceTac {
/**
* Start a new "quick battle" game
*/
startQuickBattle(with_ai: boolean = false): void {
startQuickBattle(with_ai: boolean = false, level?: number, shipcount?: number): void {
this.player = new Player();
this.universe = new Universe();
let battle = Battle.newQuickRandom(true, RandomGenerator.global.randInt(1, 10));
let battle = Battle.newQuickRandom(true, level || RandomGenerator.global.randInt(1, 10), shipcount);
this.player.setFleet(battle.fleets[0]);
this.player.setBattle(battle);

查看文件

@ -85,6 +85,7 @@ module TK.SpaceTac.UI {
}
tween.start();
} else {
this.tweens.removeFrom(obj, false);
obj.alpha = alpha;
if (obj.input) {
obj.input.enabled = true;

查看文件

@ -80,6 +80,11 @@ module TK.SpaceTac.UI {
// Text content style override
text_style?: UITextStyleI
// Icon content
icon?: string
icon_x?: number
icon_y?: number
}
/**
@ -155,9 +160,10 @@ module TK.SpaceTac.UI {
/**
* Add a group of components
*/
group(name: string, x = 0, y = 0): UIGroup {
group(name: string, x = 0, y = 0, visible = true): UIGroup {
let result = new Phaser.Group(this.game, undefined, name);
result.position.set(x, y);
result.visible = visible;
this.add(result);
return result;
}
@ -293,6 +299,10 @@ module TK.SpaceTac.UI {
this.in(result).text(options.text, options.text_x || 0, options.text_y || 0, options.text_style);
}
if (options.icon) {
this.in(result).image(options.icon, options.icon_x || 0, options.icon_y || 0, options.center);
}
this.add(result);
return result;
}

查看文件

@ -11,8 +11,7 @@ module TK.SpaceTac.UI {
this.addText(this.width * 0.5, this.height * 0.3, message, "#90FEE3", 32);
let input = new UITextInput(this, 600, 80, 16);
input.setPositionInsideParent(0.5, 0.5);
let input = new UITextInput(this.builder.styled({ size: 24 }), "menu-input", this.width / 2, this.height / 2, 12);
if (initial) {
input.setContent(initial);
}

查看文件

@ -1,29 +1,24 @@
/// <reference path="UIComponent.ts" />
module TK.SpaceTac.UI {
/**
* UI component to allow the user to enter a small text
*/
export class UITextInput extends UIComponent {
export class UITextInput {
private content: Phaser.Text
private placeholder: Phaser.Text
private maxlength: number
constructor(parent: UIComponent, width: number, height: number, maxlength?: number, fontcolor = "#FFFFFF") {
super(parent, width, height);
let input_bg = this.builder.image("common-transparent", 0, 0, false);
input_bg.scale.set(width, height);
constructor(builder: UIBuilder, background: string, x = 0, y = 0, maxlength: number, placeholder = "") {
let input_bg = builder.image(background, x, y, true);
input_bg.inputEnabled = true;
input_bg.input.useHandCursor = true;
input_bg.events.onInputUp.add(() => this.setKeyboardFocus(key => this.processKey(key)));
this.addInternalChild(input_bg);
input_bg.events.onInputUp.add(() => {
builder.view.inputs.grabKeyboard(this, key => this.processKey(key));
});
let fontsize = Math.ceil(height * 0.8);
this.content = new Phaser.Text(this.game, width / 2, height / 2, "", { align: "center", font: `${fontsize}px SpaceTac`, fill: fontcolor });
this.content.anchor.set(0.5, 0.5);
this.addInternalChild(this.content);
this.maxlength = maxlength || (width / fontsize);
this.content = builder.in(input_bg).text("");
this.placeholder = builder.in(input_bg).text(placeholder);
this.placeholder.alpha = 0.5;
this.maxlength = maxlength;
}
/**
@ -31,9 +26,9 @@ module TK.SpaceTac.UI {
*/
processKey(key: string): void {
if (key.length == 1 && this.content.text.length < this.maxlength) {
this.content.text += key;
this.setContent(this.content.text + key);
} else if (key == "Backspace" && this.content.text.length > 0) {
this.content.text = this.content.text.substr(0, this.content.text.length - 1);
this.setContent(this.content.text.substr(0, this.content.text.length - 1));
}
}
@ -49,6 +44,7 @@ module TK.SpaceTac.UI {
*/
setContent(content: string): void {
this.content.text = content.slice(0, this.maxlength);
this.placeholder.visible = !this.content.text;
}
}
}

查看文件

@ -3,7 +3,7 @@
module TK.SpaceTac.UI.Specs {
testing("LoadDialog", test => {
let testgame = setupSingleView(test, () => [new MainMenu(), []]);
let testgame = setupEmptyView(test);
test.acase("joins remote sessions as spectator", async check => {
return new Promise((resolve, reject) => {
@ -13,7 +13,7 @@ module TK.SpaceTac.UI.Specs {
check.equals(session.primary, true);
check.equals(session.spectator, false);
view.getConnection().publish(session, "Test").then(token => {
let dialog = new LoadDialog(view);
let dialog = new InputInviteCode(view, new UIBuilder(view), 0, 0);
dialog.token_input.setContent(token);
check.patch(view.gameui, "setSession", (joined: GameSession) => {

查看文件

@ -0,0 +1,30 @@
module TK.SpaceTac.UI {
/**
* Input to display available save games, and load one
*/
export class InputInviteCode {
token_input: UITextInput
constructor(private view: BaseView, private builder: UIBuilder, x: number, y: number) {
this.token_input = new UITextInput(builder, "menu-input", x, y, 8, "Invite code");
}
/**
* Join an online game
*/
join(): void {
let token = this.token_input.getContent();
let connection = this.view.getConnection();
connection.loadByToken(token).then(session => {
if (session) {
// For now, we will only spectate
session.primary = false;
session.spectator = true;
this.view.gameui.setSession(session, token);
}
});
}
}
}

查看文件

@ -1,29 +1,19 @@
/// <reference path="../common/UIComponent.ts"/>
module TK.SpaceTac.UI {
/**
* Dialog to load a saved game, or join an online one
* Input to display available save games, and load one
*/
export class LoadDialog extends UIComponent {
saves: [string, string][] = []
save_selected = 0
save_name: UILabel
token_input: UITextInput
export class InputSavegames {
private saves: [string, string][] = []
private save_selected = 0
private save_name?: UIText
constructor(parent: MainMenu) {
super(parent, 1344, 566, "menu-load-bg");
constructor(private view: BaseView, private builder: UIBuilder, x: number, y: number) {
builder.in(builder.image("menu-input", x, y, true), builder => {
builder.button("menu-arrow-left", -196, 0, () => this.paginateSave(1), "Older saves", undefined, { center: true });
builder.button("menu-arrow-right", 196, 0, () => this.paginateSave(-1), "Newer saves", undefined, { center: true });
let button = this.addButton(600, 115, () => this.paginateSave(-1), "common-arrow", 0, 0, "Scroll to newer saves");
button.angle = 180;
this.addButton(1038, 115, () => this.paginateSave(1), "common-arrow", 0, 0, "Scroll to older saves");
this.addButton(1224, 115, () => this.load(), "common-button-ok");
this.addButton(1224, 341, () => this.join(), "common-button-ok");
this.save_name = new UILabel(this, 351, 185, "", 32, "#000000");
this.save_name.setPosition(645, 28);
this.token_input = new UITextInput(this, 468, 68, 10, "#000000");
this.token_input.setPosition(585, 304);
this.save_name = builder.text("", 0, 0, { size: 24 });
});
this.refreshSaves();
}
@ -47,13 +37,17 @@ module TK.SpaceTac.UI {
* Set the current selected save game
*/
setCurrentSave(position: number): void {
if (!this.save_name) {
return;
}
if (this.saves.length == 0) {
this.save_name.setContent("No save game found");
this.builder.change(this.save_name, "No save game found");
} else {
this.save_selected = clamp(position, 0, this.saves.length - 1);
let [saveid, saveinfo] = this.saves[this.save_selected];
this.save_name.setContent(saveinfo);
this.builder.change(this.save_name, saveinfo);
}
}
@ -64,24 +58,6 @@ module TK.SpaceTac.UI {
this.setCurrentSave(this.save_selected + offset);
}
/**
* Join an online game
*/
join(): void {
let token = this.token_input.getContent();
let connection = this.view.getConnection();
connection.loadByToken(token).then(session => {
if (session) {
// For now, we will only spectate
session.primary = false;
session.spectator = true;
this.view.gameui.setSession(session, token);
}
});
}
/**
* Load selected save game
*/

查看文件

@ -1,19 +0,0 @@
/// <reference path="../TestGame.ts" />
/// <reference path="MainMenu.ts" />
module TK.SpaceTac.UI.Specs {
testing("MainMenu", test => {
let testgame = setupSingleView(test, () => [new MainMenu(), []]);
test.case("adds moving stars, a title and three buttons", check => {
let view = <MainMenu>testgame.ui.state.getCurrentState();
check.equals(view.layer_stars.children.length, 300);
check.equals(view.layer_title.children.length, 6);
check.equals(view.layer_title.children[0] instanceof Phaser.Button, true);
check.equals(view.layer_title.children[1] instanceof Phaser.Button, true);
check.equals(view.layer_title.children[2] instanceof Phaser.Button, true);
check.equals(view.layer_title.children[3] instanceof Phaser.Image, true);
});
});
}

查看文件

@ -6,75 +6,114 @@ module TK.SpaceTac.UI {
*/
export class MainMenu extends BaseView {
static returned = false
layer_stars!: Phaser.Group
layer_presents!: Phaser.Group
layer_title!: Phaser.Group
button_new_game!: Phaser.Button
button_quick_battle!: Phaser.Button
button_load_game!: Phaser.Button
dialog_load_game!: LoadDialog
create() {
super.create();
let builder = new UIBuilder(this);
this.layer_stars = this.getLayer("stars");
this.layer_presents = this.getLayer("presents");
this.layer_title = this.getLayer("title");
// Layers
let layer_background = this.getLayer("background");
let layer_presents = this.getLayer("presents");
let layer_title = this.getLayer("title");
// 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, "common-particles", 32, this.layer_stars);
star.anchor.set(0.5, 0.5);
star.angle = 225;
star.alpha = 0.7 * fade;
star.scale.set(0.8 * fade, 0.8 * 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();
}
// Background
builder.in(layer_background, builder => {
builder.image("menu-background");
});
// Presents...
builder.in(this.layer_presents, builder => {
builder.in(layer_presents, builder => {
builder.styled({ center: true }, builder => {
builder.text("Michael Lemaire", this.getMidWidth(), this.getHeight() * 0.4, { size: 32 });
builder.text("presents", this.getMidWidth(), this.getHeight() * 0.6, { size: 24 });
});
});
// Menu buttons
this.button_new_game = this.addButton(320, 730, "New Game", "Start a new campaign in a generated universe", () => this.onNewGame());
this.button_load_game = this.addButton(958, 730, "Load / Join", "Load a saved game or join a friend", () => this.onLoadGame());
this.button_quick_battle = this.addButton(1604, 730, "Quick Battle", "Play a single generated battle", () => this.onQuickBattle());
builder.styled({ color: "#9fc4d6", size: 40, shadow: true }).in(layer_title, builder => {
// Title
let title = builder.in(layer_title).image("menu-title", 960, 784, true);
// Fullscreen button
let button = builder.in(this.layer_title).button("options-option-fullscreen", this.getWidth(), 0, () => this.options.toggleBoolean("fullscreen"), "Toggle full-screen");
button.anchor.set(1, 0);
// Title
let title = builder.in(this.layer_title).image("menu-title", 274, 187);
// Dialogs
this.dialog_load_game = new LoadDialog(this);
this.dialog_load_game.setPosition(286, 120);
this.dialog_load_game.moveToLayer(this.layer_title);
this.dialog_load_game.setVisible(false);
// Buttons
let group_new_game = builder.group("new-game", 0, 0, false);
let group_load_game = builder.group("load-game", 0, 0, false);
let group_join_game = builder.group("join-game", 0, 0, false);
let group_skirmish = builder.in(group_new_game).group("skirmish", 0, 0, false);
let button_new_game = builder.button("menu-button", 280, 106, undefined, "Start a new game", (on: boolean) => {
if (on) {
this.animations.show(group_new_game, 200);
builder.switch(button_load_game, false);
builder.switch(button_join_game, false);
} else {
this.animations.hide(group_new_game, 200);
}
return on;
}, { text: "New game", center: true, on_bottom: true });
let button_campaign = builder.in(group_new_game).button("menu-button", 770, 106, () => this.startCampaign(), "Start a campaign in story mode", undefined, {
text: "Campaign", center: true
});
let button_skirmish = builder.in(group_new_game).button("menu-button", 770, 266, undefined, "Start a quick battle", (on: boolean) => {
this.animations.setVisible(group_skirmish, on, 200);
return on;
}, { text: "Skirmish", center: true, on_bottom: true });
let button_skirmish_shipcount = this.addNumberSelector(builder.in(group_skirmish), 1130, 266, "Ships", 2, 5, 3);
let button_skirmish_level = this.addNumberSelector(builder.in(group_skirmish), 1386, 266, "Level", 1, 10, 1);
let button_skirmish_go = builder.in(group_skirmish).button("menu-button-small", 1632, 266, () => {
this.startSkirmish(button_skirmish_shipcount(), button_skirmish_level())
}, "Start the skirmish with selected settings", undefined, { text: "Go", center: true });
let button_load_game = builder.button("menu-button", 280, 266, undefined, "Load a previously saved game", (on: boolean) => {
if (on) {
this.animations.show(group_load_game, 200);
builder.switch(button_new_game, false);
builder.switch(button_join_game, false);
} else {
this.animations.hide(group_load_game, 200);
}
return on;
}, { text: "Load game", center: true, on_bottom: true });
builder.in(group_load_game, builder => {
let input = new InputSavegames(this, builder, 770, 266);
builder.button("menu-button-small", 1112, 266, () => input.load(), "Load the selected save game", undefined, {
text: "Go", center: true
});
})
let button_join_game = builder.button("menu-button", 280, 426, undefined, "Join a friend's game", (on: boolean) => {
if (on) {
this.animations.show(group_join_game, 200);
builder.switch(button_new_game, false);
builder.switch(button_load_game, false);
} else {
this.animations.hide(group_join_game, 200);
}
return on;
}, { text: "Join game", center: true, on_bottom: true });
builder.in(group_join_game, builder => {
let input = new InputInviteCode(this, builder, 770, 426);
builder.button("menu-button-small", 1112, 426, () => input.join(), "Join the game", undefined, {
text: "Go", center: true
});
})
let button_options = builder.button("menu-button-small", 1780, 106, () => this.showOptions(), "Options", undefined, {
center: true,
icon: "menu-icon-options",
});
});
// Animations
this.layer_stars.visible = false;
this.layer_presents.visible = false;
this.layer_title.visible = false;
this.animations.show(this.layer_presents, 500);
this.animations.show(this.layer_stars, 5000);
layer_background.visible = false;
layer_presents.visible = false;
layer_title.visible = false;
this.animations.show(layer_presents, 500);
this.animations.show(layer_background, 5000);
let fading = this.timer.schedule(5000, () => {
this.animations.show(this.layer_title, 1000);
this.animations.hide(this.layer_presents, 300);
this.animations.show(layer_title, 1000);
this.animations.hide(layer_presents, 300);
});
let pass = () => {
this.timer.cancel(fading);
this.animations.show(this.layer_title, 0);
this.animations.hide(this.layer_presents, 0);
this.animations.show(layer_background, 0);
this.animations.show(layer_title, 0);
this.animations.hide(layer_presents, 0);
};
if (MainMenu.returned) {
pass();
@ -86,38 +125,40 @@ module TK.SpaceTac.UI {
this.gameui.audio.startMusic("supernatural");
}
addButton(x: number, y: number, caption: string, tooltip: string, callback: Function): Phaser.Button {
let builder = new UIBuilder(this).in(this.layer_title);
let result = builder.button("menu-button", x, y, callback, tooltip);
result.anchor.set(0.5);
builder.in(result).text(caption, 0, 0, { bold: true, size: 40, color: "#529aee" });
return result;
/**
* Add a number selector in a given range
*/
addNumberSelector(builder: UIBuilder, x: number, y: number, label: string, min: number, max: number, initial: number): () => number {
let value = initial;
builder.in(builder.image("menu-input-small", x, y + 30, true), builder => {
let display = builder.text(`${value}`, 0, -32);
builder.text(label, 0, 54, { color: "#6690a4", size: 28 });
builder.button("menu-arrow-left", -68, -32, () => {
value = Math.max(min, value - 1);
builder.change(display, `${value}`);
}, undefined, undefined, { center: true });
builder.button("menu-arrow-right", 68, -32, () => {
value = Math.min(max, value + 1);
builder.change(display, `${value}`);
}, undefined, undefined, { center: true });
});
return () => value;
}
// Called when "New Game" is clicked
onNewGame(): void {
var gameui = <MainUI>this.game;
gameui.session.startNewGame(false);
this.game.state.start("router");
/**
* Start a campaign mode
*/
startCampaign(): void {
this.session.startNewGame(false);
this.backToRouter();
}
// Called when "Quick Battle" is clicked
onQuickBattle(): void {
var gameui = <MainUI>this.game;
gameui.session.startQuickBattle(true);
this.game.state.start("router");
}
// Called when "Load Game" is clicked
onLoadGame(): void {
this.dialog_load_game.setVisible(true);
/**
* Start a skirmish
*/
startSkirmish(shipcount: number, level: number): void {
this.session.startQuickBattle(true, level, shipcount);
this.backToRouter();
}
}
}