Browse Source

map: Added sound and effect for jumps between systems

master
Michaël Lemaire 3 years ago
parent
commit
9fcea58fc9
  1. 2
      TODO.md
  2. BIN
      data/stage3/image/map/jump-effect.png
  3. BIN
      data/stage3/sound/map/warp-in.wav
  4. BIN
      data/stage3/sound/map/warp-out.wav
  5. 140
      graphics/ui/map.svg
  6. 13
      src/ui/BaseView.ts
  7. 41
      src/ui/TestGame.ts
  8. 14
      src/ui/battle/WeaponEffect.spec.ts
  9. 16
      src/ui/common/Animations.spec.ts
  10. 29
      src/ui/common/Animations.ts
  11. 9
      src/ui/common/InputManager.spec.ts
  12. 3
      src/ui/common/Tooltip.spec.ts
  13. 2
      src/ui/common/UIAwaiter.ts
  14. 7
      src/ui/common/UIContainer.ts
  15. 41
      src/ui/map/FleetDisplay.spec.ts
  16. 73
      src/ui/map/FleetDisplay.ts
  17. 6
      src/ui/map/UniverseMapView.ts

2
TODO.md

@ -23,13 +23,13 @@ Menu/settings/saves
Map/story
---------
* Add sound effects and more visual effects (jumps...)
* Add factions and reputation
* Allow to cancel secondary missions
* Forbid to end up with more than 5 ships in the fleet because of escorts
* Fix problems when several dialogs are active at the same time
* Add a zoom level, to see the location only
* Restore the progressive text effect
* Improve performance when refreshing (and thus during jumps)
Character sheet
---------------

BIN
data/stage3/image/map/jump-effect.png

Binary file not shown.

After

Width: 352  |  Height: 122  |  Size: 38 KiB

BIN
data/stage3/sound/map/warp-in.wav

Binary file not shown.

BIN
data/stage3/sound/map/warp-out.wav

Binary file not shown.

140
graphics/ui/map.svg

@ -20,6 +20,42 @@
enable-background="new">
<defs
id="defs2">
<linearGradient
inkscape:collect="always"
id="linearGradient1898">
<stop
style="stop-color:#bfd0d1;stop-opacity:1;"
offset="0"
id="stop1894" />
<stop
style="stop-color:#495757;stop-opacity:0.98507464"
offset="1"
id="stop1896" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1774">
<stop
style="stop-color:#97a3a4;stop-opacity:1;"
offset="0"
id="stop1770" />
<stop
id="stop1784"
offset="0.05601373"
style="stop-color:#c9d0d1;stop-opacity:0.99607843" />
<stop
id="stop1782"
offset="0.49102494"
style="stop-color:#384a4c;stop-opacity:0.99215686" />
<stop
style="stop-color:#bfd0d1;stop-opacity:0.98823529"
offset="0.94595039"
id="stop1786" />
<stop
style="stop-color:#97a3a4;stop-opacity:0.9880597"
offset="1"
id="stop1772" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1765">
@ -1121,6 +1157,76 @@
fx="342.45343"
fy="142.875"
r="9.7939377" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1774"
id="linearGradient1776"
x1="362.30035"
y1="284.25162"
x2="362.8378"
y2="347.94138"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,8.1204444)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1774"
id="linearGradient1866"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1973483,0,0,1.0696619,-71.568108,-13.910532)"
x1="362.30035"
y1="284.25162"
x2="362.8378"
y2="347.94138" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter1876"
x="-0.078789305"
width="1.1575786"
y="-0.048446666"
height="1.0968933">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="1.3719322"
id="feGaussianBlur1878" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter1888"
x="-0.023691724"
width="1.0473834"
y="-0.013014261"
height="1.0260285">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.34454164"
id="feGaussianBlur1890" />
</filter>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient1898"
id="radialGradient1900"
cx="362.64804"
cy="324.37646"
fx="362.64804"
fy="324.37646"
r="89.845749"
gradientTransform="matrix(1,0,0,0.13157894,0,281.69535)"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter1926"
x="-0.099126316"
width="1.1982526"
y="-0.75336001"
height="2.50672">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="7.4217317"
id="feGaussianBlur1928" />
</filter>
</defs>
<sodipodi:namedview
id="base"
@ -1129,11 +1235,11 @@
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="3.3234019"
inkscape:cx="855.45368"
inkscape:cy="455.29087"
inkscape:zoom="2.35"
inkscape:cx="1289.633"
inkscape:cy="-91.7479"
inkscape:document-units="px"
inkscape:current-layer="layer5"
inkscape:current-layer="g1933"
showgrid="false"
units="px"
inkscape:snap-bbox="true"
@ -1644,6 +1750,32 @@
inkscape:export-filename="/home/michael/workspace/spacetac/data/stage3/image/map/location-planet-hover.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
<g
id="g1933"
transform="matrix(0.4321442,0,0,0.4321442,205.93179,184.19907)"
inkscape:export-filename="/home/michael/workspace/spacetac/data/stage3/image/map/jump-effect.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<path
style="opacity:0.756;fill:url(#linearGradient1866);fill-opacity:1;stroke:none;stroke-width:0.29943049;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.22985074;filter:url(#filter1876)"
d="m 341.75272,292.9497 c 13.45982,-3.15113 27.31495,-3.65375 41.79041,0 -26.10679,19.87768 -23.47344,40.49956 0,61.66109 -13.65748,5.35883 -27.62513,4.62167 -41.79041,0 23.43318,-20.5537 24.73093,-41.10739 0,-61.66109 z"
id="path1864"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="rect1695"
d="m 345.19681,294.99636 c 11.24137,-2.94592 22.81288,-3.4158 34.90248,0 -21.80385,18.58313 -19.60453,37.86201 0,57.64539 -11.40644,5.00984 -23.07193,4.32069 -34.90248,0 19.57091,-19.21513 20.65476,-38.43026 0,-57.64539 z"
style="opacity:1;fill:url(#linearGradient1776);fill-opacity:1;stroke:none;stroke-width:0.26458335;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.22985074;filter:url(#filter1888)" />
<ellipse
ry="11.821809"
rx="89.845749"
cy="324.37646"
cx="362.64804"
id="path1892"
style="opacity:0.756;fill:url(#radialGradient1900);fill-opacity:1;stroke:none;stroke-width:0.26458335;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.22985074;filter:url(#filter1926)" />
</g>
</g>
<g
inkscape:groupmode="layer"

13
src/ui/BaseView.ts

@ -75,14 +75,19 @@ module TK.SpaceTac.UI {
create() {
// Layers
this.layers = this.add.container(0, 0);
this.layers = new UIContainer(this);
this.add.existing(this.layers);
this.layers.setName("View layers");
this.dialogs_layer = this.add.container(0, 0);
this.dialogs_layer = new UIContainer(this);
this.dialogs_layer.setName("Dialogs layer");
this.tooltip_layer = this.add.container(0, 0);
this.add.existing(this.dialogs_layer);
this.tooltip_layer = new UIContainer(this);
this.tooltip_layer.setName("Tooltip layer");
this.add.existing(this.tooltip_layer);
this.tooltip = new Tooltip(this);
this.messages_layer = this.add.container(0, 0);
this.messages_layer = new UIContainer(this);
this.messages_layer.setName("Messages layer");
this.add.existing(this.messages_layer);
this.messages = new Messages(this);
this.dialogs_opened = [];

41
src/ui/TestGame.ts

@ -2,22 +2,37 @@
module TK.SpaceTac.UI.Specs {
/**
* Class to hold references to test objects (used as singleton in "describe" blocks)
* Class to hold references to test objects (used as singleton in "testing" blocks)
*
* Attributes should only be accessed from inside corresponding "it" blocks (they are initialized by the setup).
* Attributes should only be accessed from inside corresponding "test.case" blocks (they are initialized by the setup).
*/
export class TestGame<T extends Phaser.Scene> {
ui!: MainUI;
view!: T;
multistorage!: Multi.FakeRemoteStorage;
clock!: FakeClock;
check!: TestContext
ui!: MainUI
view!: T
multistorage!: Multi.FakeRemoteStorage
clock: FakeClock
time = 0
constructor(test: TestSuite) {
this.clock = test.clock();
}
/**
* Advance the time in the view and fake testing clock
*/
clockForward(milliseconds: number) {
this.time += milliseconds;
this.clock.forward(milliseconds);
this.ui.headlessStep(this.time, milliseconds);
}
}
/**
* Setup a headless test UI, with a single view started.
*/
export function setupSingleView<T extends Phaser.Scene & { create: Function }>(test: TestSuite, buildView: () => [T, object]) {
let testgame = new TestGame<T>();
let testgame = new TestGame<T>(test);
test.asetup(() => new Promise((resolve, reject) => {
let check = new TestContext(); // TODO Should be taken from test suite
@ -25,6 +40,7 @@ module TK.SpaceTac.UI.Specs {
check.patch(console, "warn", null);
testgame.ui = new MainUI(true);
testgame.check = check;
let [scene, scenedata] = buildView();
@ -133,6 +149,17 @@ module TK.SpaceTac.UI.Specs {
}
}
/**
* Check a simulation of a tweened property
*/
export function checkTween<T, P extends keyof T>(game: TestGame<any>, obj: T, property: P, expected: number[]): void {
let tweendata = game.view.animations.simulate(obj, property, expected.length);
game.check.equals(tweendata.length, expected.length, "number of points");
expected.forEach((value, idx) => {
game.check.nears(tweendata[idx], value, undefined, `point ${idx}`);
});
}
/**
* Simulate a click on a button
*/

14
src/ui/battle/WeaponEffect.spec.ts

@ -1,20 +1,12 @@
module TK.SpaceTac.UI.Specs {
testing("WeaponEffect", test => {
let testgame = setupBattleview(test);
let clock = test.clock();
let t = 0;
function checkEmitters(step: string, expected: number) {
test.check.same(testgame.view.arena.layer_weapon_effects.length, expected, `${step} - layer children`);
//test.check.same(keys(testgame.view.particles.emitters).length, expected, `${step} - registered emitters`);
}
function fastForward(milliseconds: number) {
t += milliseconds;
clock.forward(milliseconds);
testgame.ui.headlessStep(t, milliseconds);
}
test.case("displays shield hit effect", check => {
let battleview = testgame.view;
battleview.timer = new Timer();
@ -25,7 +17,7 @@ module TK.SpaceTac.UI.Specs {
let layer = battleview.arena.layer_weapon_effects;
check.equals(layer.length, 1);
clock.forward(600);
testgame.clockForward(600);
check.equals(layer.length, 2);
let child = layer.list[0];
@ -91,12 +83,12 @@ module TK.SpaceTac.UI.Specs {
effect.gunEffect();
checkEmitters("gun effect started", 1);
fastForward(6000);
testgame.clockForward(6000);
checkEmitters("gun effect ended", 0);
effect.hullImpactEffect({ x: 0, y: 0 }, { x: 50, y: 50 }, 1000, 2000);
checkEmitters("hull effect started", 1);
fastForward(8500);
testgame.clockForward(8500);
checkEmitters("hull effect ended", 0);
});

16
src/ui/common/Animations.spec.ts

@ -65,5 +65,21 @@ module TK.SpaceTac.UI.Specs {
check.nears(points[2], 0);
check.nears(points[3], Math.PI * 0.25);
});
test.case("stops previous animations before starting a new one", check => {
let obj = { x: 0, y: 0 };
testgame.view.animations.addAnimation(obj, { x: 1 }, 1000);
testgame.clockForward(1);
testgame.clockForward(1);
check.equals(testgame.view.tweens.getAllTweens().length, 1);
testgame.view.animations.addAnimation(obj, { y: 1 }, 1000);
testgame.clockForward(1);
testgame.clockForward(1);
check.equals(testgame.view.tweens.getAllTweens().length, 2);
testgame.view.animations.addAnimation(obj, { x: 2 }, 1000);
testgame.clockForward(1);
testgame.clockForward(1);
check.equals(testgame.view.tweens.getAllTweens().length, 2);
});
});
}

29
src/ui/common/Animations.ts

@ -22,11 +22,9 @@ module TK.SpaceTac.UI {
* This is a wrapper around phaser's tweens.
*/
export class Animations {
private tweens: Phaser.Tweens.TweenManager
private immediate = false
constructor(tweens: Phaser.Tweens.TweenManager) {
this.tweens = tweens;
constructor(private tweens: Phaser.Tweens.TweenManager) {
}
/**
@ -39,11 +37,14 @@ module TK.SpaceTac.UI {
}
/**
* Kill previous tweens from an object
* Kill previous tweens currently running on an object's properties
*/
killPrevious(obj: object): void {
// TODO Only updated properties
this.tweens.killTweensOf(obj);
killPrevious<T extends object>(obj: T, properties: Extract<keyof T, string>[]): void {
this.tweens.getTweensOf(obj).forEach(tween => {
if (tween.data && any(tween.data, data => bool(data.key) && contains(properties, data.key))) {
tween.stop();
}
});
}
/**
@ -70,7 +71,7 @@ module TK.SpaceTac.UI {
* Display an object, with opacity transition
*/
show(obj: IAnimationFadeable, duration = 1000, alpha = 1): void {
this.killPrevious(obj);
this.killPrevious(obj, ['alpha']);
if (!obj.visible) {
obj.alpha = 0;
@ -105,7 +106,7 @@ module TK.SpaceTac.UI {
* Hide an object, with opacity transition
*/
hide(obj: IAnimationFadeable, duration = 1000, alpha = 0): void {
this.killPrevious(obj);
this.killPrevious(obj, ['alpha']);
if (obj.changeStateFrame) {
obj.changeStateFrame("Out");
@ -155,8 +156,8 @@ module TK.SpaceTac.UI {
* Add an asynchronous animation to an object.
*/
addAnimation<T extends object>(obj: T, properties: Partial<T>, duration: number, ease = "Linear", delay = 0, loop = 1, yoyo = false): Promise<void> {
return new Promise((resolve, reject) => {
this.killPrevious(obj);
return new Promise(resolve => {
this.killPrevious(obj, keys(properties));
this.tweens.add(merge<object>({
targets: obj,
@ -232,12 +233,12 @@ module TK.SpaceTac.UI {
* Returns the animation duration.
*/
moveInSpace(obj: Phaser.GameObjects.Components.Transform, x: number, y: number, angle: number, rotated_obj = obj): number {
this.killPrevious(obj, ["x", "y"]);
if (x == obj.x && y == obj.y) {
this.killPrevious(obj);
return this.rotationTween(rotated_obj, angle, 0.5);
} else {
this.killPrevious(obj);
this.killPrevious(rotated_obj);
this.killPrevious(rotated_obj, ["rotation"]);
let distance = Target.newFromLocation(obj.x, obj.y).getDistanceTo(Target.newFromLocation(x, y));
let duration = Math.sqrt(distance / 1000) * 3000;
let curve_force = distance * 0.4;

9
src/ui/common/InputManager.spec.ts

@ -1,7 +1,6 @@
module TK.SpaceTac.UI.Specs {
testing("InputManager", test => {
let testgame = setupEmptyView(test);
let clock = test.clock();
test.case("handles hover and click on desktops and mobile targets", check => {
let inputs = testgame.view.inputs;
@ -46,7 +45,7 @@ module TK.SpaceTac.UI.Specs {
[button, mocks] = newButton();
check.in("Leaves on destroy", check => {
press(button);
clock.forward(150);
testgame.clockForward(150);
check.called(mocks.enter, 1);
check.called(mocks.leave, 0);
check.called(mocks.click, 0);
@ -65,7 +64,7 @@ module TK.SpaceTac.UI.Specs {
let [button1, funcs1] = newButton();
let [button2, funcs2] = newButton();
enter(button1);
clock.forward(150);
testgame.clockForward(150);
check.called(funcs1.enter, 1);
check.called(funcs1.leave, 0);
check.called(funcs1.click, 0);
@ -76,7 +75,7 @@ module TK.SpaceTac.UI.Specs {
check.called(funcs2.enter, 0);
check.called(funcs2.leave, 0);
check.called(funcs2.click, 0);
clock.forward(150);
testgame.clockForward(150);
check.called(funcs1.enter, 0);
check.called(funcs1.leave, 0);
check.called(funcs1.click, 0);
@ -88,7 +87,7 @@ module TK.SpaceTac.UI.Specs {
[button, mocks] = newButton();
check.in("Hold to hover on mobile", check => {
button.emit("pointerdown", pointer);
clock.forward(150);
testgame.clockForward(150);
check.called(mocks.enter, 1);
check.called(mocks.leave, 0);
check.called(mocks.click, 0);

3
src/ui/common/Tooltip.spec.ts

@ -1,7 +1,6 @@
module TK.SpaceTac.UI.Specs {
testing("Tooltip", test => {
let testgame = setupEmptyView(test);
let clock = test.clock();
test.case("shows near the hovered button", check => {
let button = new UIBuilder(testgame.view).button("fake");
@ -18,7 +17,7 @@ module TK.SpaceTac.UI.Specs {
button.emit("pointerover", { pointer: pointer });
check.equals(container.visible, false);
clock.forward(1000);
testgame.clockForward(1000);
container.update();
check.equals(container.visible, true);
check.equals(container.x, 113);

2
src/ui/common/UIAwaiter.ts

@ -2,7 +2,7 @@ module TK.SpaceTac.UI {
/**
* UI component to show a loader animation while waiting for something
*/
export class UIAwaiter extends Phaser.GameObjects.Container {
export class UIAwaiter extends UIContainer {
constructor(view: BaseView, x: number, y: number, visible: boolean) {
super(view, x, y);
this.setName("awaiter");

7
src/ui/common/UIContainer.ts

@ -3,6 +3,13 @@ module TK.SpaceTac.UI {
* UI component able to contain other UI components
*/
export class UIContainer extends Phaser.GameObjects.Container {
/**
* Get a container to build UI components inside the container
*/
getBuilder(): UIBuilder {
return new UIBuilder(<BaseView>this.scene, this);
}
/**
* Fixed version that does not force (0, 0) to be in bounds
*/

41
src/ui/map/FleetDisplay.spec.ts

@ -1,20 +1,43 @@
module TK.SpaceTac.UI.Specs {
testing("FleetDisplay", test => {
let testgame = setupMapview(test);
let testgame = setupEmptyView(test);
test.case("orbits the fleet around its current location", check => {
let mapview = testgame.view;
let fleet = mapview.player_fleet;
let session = new GameSession();
session.startNewGame(true, false);
let fleet = new FleetDisplay(testgame.view, session.player.fleet, session.universe, undefined, false);
fleet.loopOrbit();
check.equals(fleet.rotation, 0);
let tweendata = mapview.animations.simulate(fleet, "rotation", 4);
check.equals(tweendata.length, 4);
check.nears(tweendata[0], 0);
check.nears(tweendata[1], -Math.PI * 2 / 3);
check.nears(tweendata[2], Math.PI * 2 / 3);
check.nears(tweendata[3], 0);
checkTween(testgame, fleet, "rotation", [0, -Math.PI * 2 / 3, Math.PI * 2 / 3, 0]);
});
test.case("animates jumps between locations", check => {
let session = new GameSession();
session.startNewGame(true, false);
let fleet_disp = new FleetDisplay(testgame.view, session.player.fleet, session.universe, undefined, false);
let on_leave = check.mockfunc("on_leave", (duration: number): any => null);
let on_finished = check.mockfunc();
let current = nn(session.universe.getLocation(session.player.fleet.location));
let dest = nn(first(current.star.locations, loc => loc !== current));
dest.universe_x = current.universe_x - 0.1;
dest.universe_y = current.universe_y;
dest.clearEncounter();
fleet_disp.moveToLocation(dest, 1, on_leave.func, on_finished.func);
check.called(on_leave, 0);
check.called(on_finished, 0);
checkTween(testgame, fleet_disp, "rotation", [
0,
-0.0436332312998573,
-0.3490658503988655,
-1.178097245096172,
-2.7925268031909276,
0.8290313946973056,
-3.141592653589793
]);
});
});
}

73
src/ui/map/FleetDisplay.ts

@ -13,25 +13,23 @@ module TK.SpaceTac.UI {
* Group to display a fleet
*/
export class FleetDisplay extends UIContainer {
private map: UniverseMapView
private fleet: Fleet
private ship_count = 0
private is_moving = false
constructor(parent: UniverseMapView, fleet: Fleet) {
super(parent);
this.map = parent;
this.fleet = fleet;
constructor(private map: BaseView, private fleet: Fleet, private universe: Universe, private location_marker?: CurrentLocationMarker, orbit = true) {
super(map);
this.updateShipSprites();
let location = this.map.universe.getLocation(fleet.location);
let location = this.universe.getLocation(fleet.location);
if (location) {
this.setPosition(location.star.x + location.x, location.star.y + location.y);
}
this.setScale(SCALING, SCALING);
this.loopOrbit();
if (orbit) {
this.loopOrbit();
}
}
/**
@ -54,14 +52,14 @@ module TK.SpaceTac.UI {
}
get location(): StarLocation {
return this.map.universe.getLocation(this.fleet.location) || new StarLocation();
return this.universe.getLocation(this.fleet.location) || new StarLocation();
}
/**
* Animate to a given position in orbit of its current star location
*/
goToOrbitPoint(angle: number, speed = 1, fullturns = 0, then: Function | null = null, ease = false) {
this.map.animations.killPrevious(this);
async goToOrbitPoint(angle: number, speed = 1, fullturns = 0, ease = false): Promise<void> {
this.map.animations.killPrevious<UIContainer>(this, ["angle"]);
this.rotation %= PI2;
let target = -angle;
@ -70,33 +68,32 @@ module TK.SpaceTac.UI {
}
target -= PI2 * fullturns;
let distance = Math.abs(target - this.rotation) / PI2;
let tween = this.map.animations.addAnimation<UIContainer>(this, { rotation: target }, 30000 * distance / speed, ease ? "Cubic.easeIn" : "Linear");
if (then) {
tween.then(() => then());
}
await this.map.animations.addAnimation<UIContainer>(this, { rotation: target }, 30000 * distance / speed, ease ? "Cubic.easeIn" : "Linear");
}
/**
* Make the fleet loop in orbit
*/
loopOrbit() {
this.goToOrbitPoint(this.rotation + PI2, 1, 0, () => {
this.loopOrbit();
});
if (!this.is_moving) {
this.goToOrbitPoint(this.rotation + PI2, 1, 0).then(() => this.loopOrbit());
}
}
/**
* Make the fleet move to another location in the same system
*/
moveToLocation(location: StarLocation, speed = 1, on_leave: ((duration: number) => any) | null = null, on_finished: Function | null = null) {
let fleet_location = this.map.universe.getLocation(this.fleet.location);
let fleet_location = this.universe.getLocation(this.fleet.location);
if (fleet_location && this.fleet.move(location)) {
let dx = location.universe_x - fleet_location.universe_x;
let dy = location.universe_y - fleet_location.universe_y;
let distance = Math.sqrt(dx * dx + dy * dy);
let angle = Math.atan2(dx, dy);
this.map.current_location.setFleetMoving(true);
this.goToOrbitPoint(angle - Math.PI / 2, 40, 1, () => {
let angle = Math.atan2(-dy, dx);
this.setMoving(true);
console.error(fleet_location, location, angle);
this.goToOrbitPoint(angle, 40, 1, true).then(() => {
this.setRotation(-angle);
let duration = 10000 * distance / speed;
if (on_leave) {
on_leave(duration);
@ -106,7 +103,7 @@ module TK.SpaceTac.UI {
if (this.fleet.battle) {
this.map.backToRouter();
} else {
this.map.current_location.setFleetMoving(false);
this.setMoving(false);
this.loopOrbit();
}
@ -114,7 +111,33 @@ module TK.SpaceTac.UI {
on_finished();
}
});
}, true);
});
}
}
/**
* Display a jump flash effect
*/
async showJumpEffect(lag = 0, duration = 0): Promise<void> {
this.map.audio.playOnce(lag ? "map-warp-out" : "map-warp-in");
let effect = this.getBuilder().image("map-jump-effect", 0, 150, true);
effect.setScale(0.01);
effect.setZ(-1);
if (lag && duration) {
this.map.animations.addAnimation(effect, { x: -lag / SCALING }, duration * 0.5, "Cubic.easeOut");
}
await this.map.animations.addAnimation(effect, { scaleX: 3, scaleY: 3 }, 100);
await this.map.animations.addAnimation(effect, { scaleX: 2, scaleY: 2, alpha: 0 }, 200);
effect.destroy();
}
/**
* Mark the fleet as moving
*/
private setMoving(moving: boolean): void {
this.is_moving = moving;
if (this.location_marker) {
this.location_marker.setFleetMoving(moving);
}
}
}

6
src/ui/map/UniverseMapView.ts

@ -94,7 +94,7 @@ module TK.SpaceTac.UI {
this.starsystems = this.universe.stars.map(star => new StarSystemDisplay(this, star));
this.starsystems.forEach(starsystem => this.layer_universe.add(starsystem));
this.player_fleet = new FleetDisplay(this, this.player.fleet);
this.player_fleet = new FleetDisplay(this, this.player.fleet, this.universe, this.current_location);
this.layer_universe.add(this.player_fleet);
this.current_location = new CurrentLocationMarker(this, this.player_fleet);
@ -290,7 +290,9 @@ module TK.SpaceTac.UI {
let dest_location = location.jump_dest;
let dest_star = dest_location.star;
this.player_fleet.moveToLocation(dest_location, 3, duration => {
this.timer.schedule(duration / 3, () => this.updateInfo(dest_star, false));
this.player_fleet.showJumpEffect(location.getDistanceTo(dest_location), duration);
this.timer.schedule(duration * 0.3, () => this.updateInfo(dest_star, false));
this.timer.schedule(duration * 0.7, () => this.player_fleet.showJumpEffect());
this.setCamera(dest_star.x, dest_star.y, dest_star.radius * 2, duration, "Cubic.easeOut");
}, () => {
this.setInteractionEnabled(true);

Loading…
Cancel
Save