Use atlas to pack images
|
@ -2,6 +2,7 @@
|
|||
coverage
|
||||
/node_modules
|
||||
/out/vendor
|
||||
/out/assets/atlas*
|
||||
/out/build.*
|
||||
/graphics/**/*.blend?*
|
||||
/typings/
|
||||
|
|
|
@ -21,13 +21,11 @@ The only hard dependency of the toolchain is Python3.
|
|||
If you want to build on your computer, clone the repository, then run:
|
||||
|
||||
./spacetac install # Install dependencies
|
||||
./spacetac run build # Build the final JS
|
||||
./spacetac run pack # Pack the images and sounds
|
||||
./spacetac test # Run unit tests
|
||||
./spacetac start # Start development server, and open game in web browser
|
||||
|
||||
After making changes to sources, you need to recompile:
|
||||
|
||||
./spacetac run build
|
||||
|
||||
## Credits
|
||||
|
||||
* **[Michaël Lemaire](https://thunderk.net/)** - Code and graphics
|
||||
|
|
6
TODO.md
|
@ -85,6 +85,12 @@ Common UI
|
|||
* Mobile: display tooltips larger and on the side of screen where the finger is not
|
||||
* Mobile: targetting in two times, using a draggable target indicator
|
||||
|
||||
Technical
|
||||
---------
|
||||
|
||||
* Pack all images in atlases
|
||||
* Pack sounds
|
||||
|
||||
Network
|
||||
-------
|
||||
|
||||
|
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
@ -7,6 +7,7 @@
|
|||
"shell": "${SHELL} || true",
|
||||
"postinstall": "typings install && rm -rf out/vendor && mkdir -p out/vendor && cp -r node_modules/phaser/build out/vendor/phaser && cp -r node_modules/phaser-plugin-scene-graph/dist out/vendor/phaser-plugin-scene-graph && cp -r node_modules/parse/dist out/vendor/parse && cp -r node_modules/jasmine-core/lib/jasmine-core out/vendor/jasmine",
|
||||
"build": "tsc -p .",
|
||||
"pack": "rm -f out/assets/atlas* && find graphics/exported -name '*.png' -print0 | xargs -0 gf-pack --name out/assets/atlas --fullpath --width 1024 --height 1024 --square --powerOfTwo --trim",
|
||||
"pretest": "tsc -p .",
|
||||
"test": "karma start spec/support/karma.conf.js && remap-istanbul -i out/coverage/coverage.json -o out/coverage -t html",
|
||||
"prestart": "tsc -p . || true",
|
||||
|
@ -22,6 +23,7 @@
|
|||
"devDependencies": {
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"codecov": "^2.2.0",
|
||||
"gamefroot-texture-packer": "git+https://github.com/Gamefroot/Gamefroot-Texture-Packer.git#f3687111afc94f80ea8f2877c188fb8e2004e8ff",
|
||||
"jasmine": "^2.6.0",
|
||||
"karma": "^1.7.0",
|
||||
"karma-coverage": "^1.1.1",
|
||||
|
@ -39,4 +41,4 @@
|
|||
"phaser": "^2.6.2",
|
||||
"phaser-plugin-scene-graph": "^1.0.4"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -175,11 +175,39 @@ module TS.SpaceTac.UI {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the first image found in cache
|
||||
* Get a new image from an atlas name
|
||||
*/
|
||||
getImage(...keys: string[]): string {
|
||||
let found = first(keys, key => this.game.cache.checkImageKey(key));
|
||||
return found ? found : "default";
|
||||
newImage(name: string, x = 0, y = 0): Phaser.Image {
|
||||
let info = this.getImageInfo(name);
|
||||
let result = this.game.add.image(x, y, info.key, info.frame);
|
||||
result.name = name;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an image from atlases
|
||||
*/
|
||||
getImageInfo(name: string): { key: string, frame: number } {
|
||||
// TODO Cache
|
||||
let i = 1;
|
||||
while (this.game.cache.checkImageKey(`atlas-${i}`)) {
|
||||
let data = this.game.cache.getFrameData(`atlas-${i}`);
|
||||
let frames = data.getFrames();
|
||||
let frame = first(frames, frame => Preload.getKey(frame.name) == `graphics-exported-${name}`);
|
||||
if (frame) {
|
||||
return { key: `atlas-${i}`, frame: frame.index };
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return { key: "default", frame: 0 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first image found in atlases
|
||||
*/
|
||||
getFirstImage(...names: string[]): { key: string, frame: number } {
|
||||
let infos = names.map(name => this.getImageInfo(name));
|
||||
return first(infos, info => info.key != "default") || infos[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,8 +34,6 @@ module TS.SpaceTac.UI {
|
|||
this.loadImage("battle/actionbar/background.png");
|
||||
this.loadSheet("battle/actionbar/icon.png", 88, 88);
|
||||
this.loadSheet("battle/actionbar/power.png", 58, 21);
|
||||
this.loadImage("battle/actionbar/action-move.png");
|
||||
this.loadImage("battle/actionbar/action-endturn.png");
|
||||
this.loadSheet("battle/actionbar/button-menu.png", 79, 132);
|
||||
this.loadImage("battle/arena/background.png");
|
||||
this.loadImage("battle/arena/blast.png");
|
||||
|
@ -85,31 +83,10 @@ module TS.SpaceTac.UI {
|
|||
this.loadImage("character/upgrade-available.png");
|
||||
this.loadImage("character/price-tag.png");
|
||||
this.loadImage("character/experience.png");
|
||||
this.loadImage("equipment/ironhull.png");
|
||||
this.loadImage("equipment/forcefield.png");
|
||||
this.loadImage("equipment/nuclearreactor.png");
|
||||
this.loadImage("equipment/rocketengine.png");
|
||||
this.loadImage("equipment/gatlinggun.png");
|
||||
this.loadImage("equipment/powerdepleter.png");
|
||||
this.loadImage("equipment/submunitionmissile.png");
|
||||
this.loadImage("equipment/repairdrone.png");
|
||||
this.loadImage("equipment/shieldtransfer.png");
|
||||
this.loadImage("equipment/damageprotector.png");
|
||||
|
||||
// Load ships
|
||||
this.loadShip("avenger");
|
||||
this.loadShip("breeze");
|
||||
this.loadShip("commodore");
|
||||
this.loadShip("creeper");
|
||||
this.loadShip("falcon");
|
||||
this.loadShip("flea");
|
||||
this.loadShip("jumper");
|
||||
this.loadShip("rhino");
|
||||
this.loadShip("scout");
|
||||
this.loadShip("tomahawk");
|
||||
this.loadShip("trapper");
|
||||
this.loadShip("whirlwind");
|
||||
this.loadShip("xander");
|
||||
// Load image atlases
|
||||
// TODO automatic range
|
||||
range(3).forEach(i => this.loadAtlas(i + 1));
|
||||
|
||||
// Load sounds
|
||||
this.loadSound("ui/button-down.wav");
|
||||
|
@ -144,12 +121,8 @@ module TS.SpaceTac.UI {
|
|||
return path.replace(/\//g, "-").replace(/\.[a-z0-9]+$/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a ship's sprite and portrait
|
||||
*/
|
||||
loadShip(name: string) {
|
||||
this.loadImage("ship/" + name + "/sprite.png");
|
||||
this.loadImage("ship/" + name + "/portrait.png");
|
||||
loadAtlas(index: number) {
|
||||
this.load.atlasJSONHash(`atlas-${index}`, `assets/atlas-${index}.png`, `assets/atlas-${index}.json`);
|
||||
}
|
||||
|
||||
loadSheet(path: string, frame_width: number, frame_height = frame_width) {
|
||||
|
|
|
@ -64,8 +64,8 @@ module TS.SpaceTac.UI {
|
|||
this.addChild(this.layer_selected);
|
||||
|
||||
// Icon layer
|
||||
let icon = this.battleview.getImage(`battle-actionbar-action-${action.code}`, `equipment-${action.equipment ? action.equipment.code : "---"}`);
|
||||
this.layer_icon = new Phaser.Image(this.game, this.width / 2, this.height / 2, icon, 0);
|
||||
let icon = this.battleview.getFirstImage(`action-${action.code}`, `equipment-${action.equipment ? action.equipment.code : "---"}`);
|
||||
this.layer_icon = new Phaser.Image(this.game, this.width / 2, this.height / 2, icon.key, icon.frame);
|
||||
this.layer_icon.anchor.set(0.5, 0.5);
|
||||
this.layer_icon.scale.set(0.25, 0.25);
|
||||
this.addChild(this.layer_icon);
|
||||
|
|
|
@ -7,8 +7,8 @@ module TS.SpaceTac.UI {
|
|||
* Fill the tooltip
|
||||
*/
|
||||
static fill(filler: TooltipFiller, ship: Ship, action: BaseAction, position: number) {
|
||||
let icon = filler.view.getImage(`equipment-${action.equipment ? action.equipment.code : "---"}`, `battle-actionbar-action-${action.code}`);
|
||||
filler.addImage(0, 0, icon, 0.5);
|
||||
let icon = filler.view.getFirstImage(`equipment-${action.equipment ? action.equipment.code : "---"}`, `action-${action.code}`);
|
||||
filler.addImage(0, 0, icon.key, icon.frame, 0.5);
|
||||
|
||||
filler.addText(150, 0, action.equipment ? action.equipment.name : action.name, "#ffffff", 24);
|
||||
|
||||
|
|
|
@ -45,7 +45,8 @@ module TS.SpaceTac.UI {
|
|||
this.activation.visible = false;
|
||||
this.add(this.activation);
|
||||
|
||||
this.sprite = new Phaser.Button(this.game, 0, 0, battleview.getImage(`equipment-${drone.code}`, `battle-actions-deploy-${drone.code}`));
|
||||
let info = battleview.getFirstImage(`equipment-${drone.code}`, `battle-actions-deploy-${drone.code}`);
|
||||
this.sprite = new Phaser.Button(this.game, 0, 0, info.key, undefined, undefined, info.frame, info.frame);
|
||||
this.sprite.anchor.set(0.5, 0.5);
|
||||
this.sprite.scale.set(0.1, 0.1);
|
||||
this.add(this.sprite);
|
||||
|
|
|
@ -52,7 +52,8 @@ module TS.SpaceTac.UI {
|
|||
this.add(this.effects_radius);
|
||||
|
||||
// Add ship sprite
|
||||
this.sprite = new Phaser.Button(this.game, 0, 0, "ship-" + ship.model.code + "-sprite");
|
||||
let info = this.battleview.getImageInfo(`ship-${ship.model.code}-sprite`);
|
||||
this.sprite = new Phaser.Button(this.game, 0, 0, info.key, undefined, undefined, info.frame, info.frame);
|
||||
this.sprite.rotation = ship.arena_angle;
|
||||
this.sprite.anchor.set(0.5, 0.5);
|
||||
this.sprite.scale.set(0.25);
|
||||
|
|
|
@ -28,7 +28,7 @@ module TS.SpaceTac.UI {
|
|||
fleet1.ships.forEach((ship, index) => {
|
||||
let ship_card = view.game.add.image(-100 + index * 96, -26, "battle-splash-shipcard", 0);
|
||||
ship_card.anchor.set(0.5);
|
||||
let ship_portrait = view.game.add.image(0, 0, `ship-${ship.model.code}-portrait`);
|
||||
let ship_portrait = view.newImage(`ship-${ship.model.code}-portrait`);
|
||||
ship_portrait.scale.set(0.3);
|
||||
ship_portrait.anchor.set(0.5);
|
||||
ship_card.addChild(ship_portrait);
|
||||
|
@ -49,7 +49,7 @@ module TS.SpaceTac.UI {
|
|||
fleet2.ships.forEach((ship, index) => {
|
||||
let ship_card = view.game.add.image(-104 + index * 96, -32, "battle-splash-shipcard", 1);
|
||||
ship_card.anchor.set(0.5);
|
||||
let ship_portrait = view.game.add.image(0, 0, `ship-${ship.model.code}-portrait`);
|
||||
let ship_portrait = view.newImage(`ship-${ship.model.code}-portrait`);
|
||||
ship_portrait.scale.set(0.3);
|
||||
ship_portrait.anchor.set(0.5);
|
||||
ship_card.angle = 180;
|
||||
|
|
|
@ -31,7 +31,7 @@ module TS.SpaceTac.UI {
|
|||
this.player_indicator.angle = 90;
|
||||
this.addChild(this.player_indicator);
|
||||
|
||||
this.portrait = new Phaser.Image(this.game, 18, 9, "ship-" + ship.model.code + "-portrait", 0);
|
||||
this.portrait = this.view.newImage(`ship-${ship.model.code}-portrait`, 18, 9);
|
||||
this.portrait.scale.set(0.332, 0.332);
|
||||
this.addChild(this.portrait);
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ module TS.SpaceTac.UI.Specs {
|
|||
tooltip.setShip(ship);
|
||||
|
||||
let content = (<any>tooltip).container.content;
|
||||
expect(content.children[0].data.key).toBe("ship-fake-portrait");
|
||||
expect(content.children[0].name).toBe("ship-fake-portrait");
|
||||
expect(content.children[1].text).toBe("Fury");
|
||||
expect(content.children[2].text).toBe("Plays in 2 turns");
|
||||
expect(content.children[3].text).toBe("Hull\n58");
|
||||
|
|
|
@ -24,7 +24,7 @@ module TS.SpaceTac.UI {
|
|||
|
||||
filler.configure(10, 6, this.battleview.arena.getBoundaries());
|
||||
|
||||
filler.addImage(0, 0, `ship-${ship.model.code}-portrait`, 0.5);
|
||||
filler.addImageA(0, 0, `ship-${ship.model.code}-portrait`, 0.5);
|
||||
|
||||
let enemy = ship.getPlayer() != this.battleview.player;
|
||||
filler.addText(140, 0, ship.name, enemy ? "#cc0d00" : "#ffffff", 22, false, true);
|
||||
|
|
|
@ -223,7 +223,9 @@ module TS.SpaceTac.UI {
|
|||
this.ship = action.equipment.attached_to.ship;
|
||||
this.action = action;
|
||||
|
||||
this.move_ghost.loadTexture(`ship-${this.ship.model.code}-sprite`);
|
||||
let info = this.view.getImageInfo(`ship-${this.ship.model.code}-sprite`);
|
||||
this.move_ghost.loadTexture(info.key);
|
||||
this.move_ghost.frame = info.frame;
|
||||
this.move_ghost.scale.set(0.25);
|
||||
} else {
|
||||
this.ship = null;
|
||||
|
|
|
@ -35,8 +35,8 @@ module TS.SpaceTac.UI {
|
|||
price: number
|
||||
|
||||
constructor(sheet: CharacterSheet, equipment: Equipment, container: CharacterEquipmentContainer) {
|
||||
let icon = sheet.view.getImage(`equipment-${equipment.code}`, `battle-actions-${equipment.action.code}`);
|
||||
super(sheet.game, 0, 0, icon);
|
||||
let icon = sheet.view.getImageInfo(`equipment-${equipment.code}`);
|
||||
super(sheet.game, 0, 0, icon.key, undefined, undefined, icon.frame, icon.frame);
|
||||
|
||||
this.sheet = sheet;
|
||||
this.item = equipment;
|
||||
|
|
|
@ -16,7 +16,7 @@ module TS.SpaceTac.UI {
|
|||
this.sheet = sheet;
|
||||
this.ship = ship;
|
||||
|
||||
let portrait_pic = new Phaser.Image(this.game, 0, 0, `ship-${ship.model.code}-portrait`);
|
||||
let portrait_pic = sheet.view.newImage(`ship-${ship.model.code}-portrait`);
|
||||
portrait_pic.anchor.set(0.5, 0.5);
|
||||
this.addChild(portrait_pic);
|
||||
|
||||
|
|
|
@ -100,13 +100,22 @@ module TS.SpaceTac.UI {
|
|||
/**
|
||||
* Add an image to the content
|
||||
*/
|
||||
addImage(x: number, y: number, key: string, scale = 1): void {
|
||||
let image = new Phaser.Image(this.container.game, x, y, key);
|
||||
addImage(x: number, y: number, key: string, frame = 0, scale = 1): void {
|
||||
let image = new Phaser.Image(this.container.game, x, y, key, frame);
|
||||
image.data.key = key;
|
||||
image.scale.set(scale);
|
||||
this.container.content.add(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an image to the content, coming from an atlas
|
||||
*/
|
||||
addImageA(x: number, y: number, name: string, scale = 1): void {
|
||||
let image = this.view.newImage(name, x, y);
|
||||
image.scale.set(scale);
|
||||
this.container.content.add(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a text to the content
|
||||
*/
|
||||
|
|
|
@ -43,9 +43,10 @@ module TS.SpaceTac.UI {
|
|||
this.removeAll(true);
|
||||
this.fleet.ships.forEach((ship, index) => {
|
||||
let offset = LOCATIONS[index];
|
||||
let sprite = this.game.add.image(offset[0], offset[1] + 150, `ship-${ship.model.code}-sprite`, 0, this);
|
||||
let sprite = this.map.newImage(`ship-${ship.model.code}-sprite`, offset[0], offset[1] + 150);
|
||||
sprite.scale.set(64 / sprite.width);
|
||||
sprite.anchor.set(0.5, 0.5);
|
||||
this.add(sprite);
|
||||
});
|
||||
|
||||
this.ship_count = this.fleet.ships.length;
|
||||
|
|
17
yarn.lock
|
@ -1025,6 +1025,15 @@ function-bind@^1.0.2:
|
|||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
|
||||
|
||||
"gamefroot-texture-packer@git+https://github.com/Gamefroot/Gamefroot-Texture-Packer.git#f3687111afc94f80ea8f2877c188fb8e2004e8ff":
|
||||
version "1.1.1"
|
||||
resolved "git+https://github.com/Gamefroot/Gamefroot-Texture-Packer.git#f3687111afc94f80ea8f2877c188fb8e2004e8ff"
|
||||
dependencies:
|
||||
async "^1.4.0"
|
||||
glob "^5.0.14"
|
||||
mustache "^2.1.3"
|
||||
optimist "~0.6.0"
|
||||
|
||||
gauge@~2.7.3:
|
||||
version "2.7.4"
|
||||
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
|
||||
|
@ -1075,7 +1084,7 @@ glob-parent@^2.0.0:
|
|||
dependencies:
|
||||
is-glob "^2.0.0"
|
||||
|
||||
glob@^5.0.15:
|
||||
glob@^5.0.14, glob@^5.0.15:
|
||||
version "5.0.15"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
|
||||
dependencies:
|
||||
|
@ -2020,6 +2029,10 @@ multipipe@^0.1.2:
|
|||
dependencies:
|
||||
duplexer2 "0.0.2"
|
||||
|
||||
mustache@^2.1.3:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0"
|
||||
|
||||
nan@^2.3.0:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
|
||||
|
@ -2154,7 +2167,7 @@ opn@latest:
|
|||
dependencies:
|
||||
is-wsl "^1.1.0"
|
||||
|
||||
optimist@^0.6.1:
|
||||
optimist@^0.6.1, optimist@~0.6.0:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
|
||||
dependencies:
|
||||
|
|