Refactored animation system to be able to control the playback speed
This commit is contained in:
parent
9fcea58fc9
commit
7879457035
1
TODO.md
1
TODO.md
|
@ -59,7 +59,6 @@ Battle
|
||||||
* Add targetting shortcuts for "previous target", "next enemy" and "next ally"
|
* Add targetting shortcuts for "previous target", "next enemy" and "next ally"
|
||||||
* Area targetting should include the hotkeyed ship at best (apply exclusion and power limit), not necessarily center on it
|
* Area targetting should include the hotkeyed ship at best (apply exclusion and power limit), not necessarily center on it
|
||||||
* Add shortcut to perform only the "move" part of a move+fire simulation
|
* Add shortcut to perform only the "move" part of a move+fire simulation
|
||||||
* Fix delay of shield/hull impact effects (should depend on weapon animation, and ship location)
|
|
||||||
* Add a turn count marker in the ship list
|
* Add a turn count marker in the ship list
|
||||||
* BattleChecks should be done proactively when all diffs have been simulated by an action, in addition to reactively after applying
|
* BattleChecks should be done proactively when all diffs have been simulated by an action, in addition to reactively after applying
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 71b309744d7760ffc4ecdc14a1f68dbe2a25d419
|
Subproject commit 1425cb08935dd996a4c7a644ab793ff3b8355c9b
|
|
@ -67,7 +67,7 @@ module TK.SpaceTac.UI {
|
||||||
|
|
||||||
this.range_hint.setLayer(this.layer_hints);
|
this.range_hint.setLayer(this.layer_hints);
|
||||||
this.addShipSprites();
|
this.addShipSprites();
|
||||||
view.battle.drones.list().forEach(drone => this.addDrone(drone, false));
|
view.battle.drones.list().forEach(drone => this.addDrone(drone, 0));
|
||||||
|
|
||||||
view.log_processor.register(diff => this.checkDroneDeployed(diff));
|
view.log_processor.register(diff => this.checkDroneDeployed(diff));
|
||||||
view.log_processor.register(diff => this.checkDroneRecalled(diff));
|
view.log_processor.register(diff => this.checkDroneRecalled(diff));
|
||||||
|
@ -218,10 +218,8 @@ module TK.SpaceTac.UI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spawn a new drone
|
* Spawn a new drone
|
||||||
*
|
|
||||||
* Return the duration of deploy animation
|
|
||||||
*/
|
*/
|
||||||
addDrone(drone: Drone, animate = true): number {
|
async addDrone(drone: Drone, speed = 1): Promise<void> {
|
||||||
if (!this.findDrone(drone)) {
|
if (!this.findDrone(drone)) {
|
||||||
let sprite = new ArenaDrone(this.view, drone);
|
let sprite = new ArenaDrone(this.view, drone);
|
||||||
let owner = this.view.battle.getShip(drone.owner) || new Ship();
|
let owner = this.view.battle.getShip(drone.owner) || new Ship();
|
||||||
|
@ -229,39 +227,32 @@ module TK.SpaceTac.UI {
|
||||||
this.layer_drones.add(sprite);
|
this.layer_drones.add(sprite);
|
||||||
this.drone_sprites.push(sprite);
|
this.drone_sprites.push(sprite);
|
||||||
|
|
||||||
if (animate) {
|
if (speed) {
|
||||||
sprite.radius.setAlpha(0);
|
sprite.radius.setAlpha(0);
|
||||||
sprite.setPosition(owner.arena_x, owner.arena_y);
|
sprite.setPosition(owner.arena_x, owner.arena_y);
|
||||||
sprite.sprite.setRotation(owner.arena_angle);
|
sprite.sprite.setRotation(owner.arena_angle);
|
||||||
let move_duration = this.view.animations.moveInSpace(sprite, drone.x, drone.y, angle, sprite.sprite);
|
await this.view.animations.moveInSpace(sprite, drone.x, drone.y, angle, sprite.sprite, speed);
|
||||||
this.view.animations.addAnimation(sprite.radius, { alpha: 1 }, 500, "Cubic.easeIn", move_duration);
|
await this.view.animations.addAnimation(sprite.radius, { alpha: 1 }, 500 / speed, "Cubic.easeIn");
|
||||||
|
|
||||||
return move_duration + 500;
|
|
||||||
} else {
|
} else {
|
||||||
sprite.setPosition(drone.x, drone.y);
|
sprite.setPosition(drone.x, drone.y);
|
||||||
sprite.setRotation(angle);
|
sprite.setRotation(angle);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.error("Drone added twice to arena", drone);
|
console.error("Drone added twice to arena", drone);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a destroyed drone
|
* Remove a destroyed drone
|
||||||
*
|
|
||||||
* Return the duration of deploy animation
|
|
||||||
*/
|
*/
|
||||||
removeDrone(drone: Drone): number {
|
async removeDrone(drone: Drone, speed = 1): Promise<void> {
|
||||||
let sprite = this.findDrone(drone);
|
let sprite = this.findDrone(drone);
|
||||||
if (sprite) {
|
if (sprite) {
|
||||||
remove(this.drone_sprites, sprite);
|
remove(this.drone_sprites, sprite);
|
||||||
return sprite.setDestroyed();
|
return sprite.setDestroyed();
|
||||||
} else {
|
} else {
|
||||||
console.error("Drone not found in arena for removal", drone);
|
console.error("Drone not found in arena for removal", drone);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,14 +281,11 @@ module TK.SpaceTac.UI {
|
||||||
private checkDroneDeployed(diff: BaseBattleDiff): LogProcessorDelegate {
|
private checkDroneDeployed(diff: BaseBattleDiff): LogProcessorDelegate {
|
||||||
if (diff instanceof DroneDeployedDiff) {
|
if (diff instanceof DroneDeployedDiff) {
|
||||||
return {
|
return {
|
||||||
foreground: async (animate) => {
|
foreground: async (speed: number) => {
|
||||||
let duration = this.addDrone(diff.drone, animate);
|
if (speed) {
|
||||||
if (duration) {
|
|
||||||
this.view.gameui.audio.playOnce("battle-drone-deploy");
|
this.view.gameui.audio.playOnce("battle-drone-deploy");
|
||||||
if (animate) {
|
|
||||||
await this.view.timer.sleep(duration);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
await this.addDrone(diff.drone, speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -311,12 +299,11 @@ module TK.SpaceTac.UI {
|
||||||
private checkDroneRecalled(diff: BaseBattleDiff): LogProcessorDelegate {
|
private checkDroneRecalled(diff: BaseBattleDiff): LogProcessorDelegate {
|
||||||
if (diff instanceof DroneRecalledDiff) {
|
if (diff instanceof DroneRecalledDiff) {
|
||||||
return {
|
return {
|
||||||
foreground: async () => {
|
foreground: async (speed: number) => {
|
||||||
let duration = this.removeDrone(diff.drone);
|
if (speed) {
|
||||||
if (duration) {
|
|
||||||
this.view.gameui.audio.playOnce("battle-drone-destroy");
|
this.view.gameui.audio.playOnce("battle-drone-destroy");
|
||||||
await this.view.timer.sleep(duration);
|
|
||||||
}
|
}
|
||||||
|
await this.removeDrone(diff.drone, speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -59,10 +59,10 @@ module TK.SpaceTac.UI {
|
||||||
*
|
*
|
||||||
* Return the animation duration
|
* Return the animation duration
|
||||||
*/
|
*/
|
||||||
setDestroyed(): number {
|
async setDestroyed(): Promise<void> {
|
||||||
this.view.animations.addAnimation<UIContainer>(this, { alpha: 0.3 }, 300, undefined, 200);
|
this.view.animations.addAnimation<UIContainer>(this, { alpha: 0.3 }, 300, undefined, 200);
|
||||||
this.view.animations.addAnimation(this.radius, { scaleX: 0, scaleY: 0 }, 500).then(() => this.destroy());
|
await this.view.animations.addAnimation(this.radius, { scaleX: 0, scaleY: 0 }, 500);
|
||||||
return 500;
|
this.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -104,9 +104,9 @@ module TK.SpaceTac.UI {
|
||||||
// Set location
|
// Set location
|
||||||
if (this.battleview.battle.cycle == 1 && this.battleview.battle.play_index == 0 && ship.alive && this.battleview.player.is(ship.fleet.player)) {
|
if (this.battleview.battle.cycle == 1 && this.battleview.battle.play_index == 0 && ship.alive && this.battleview.player.is(ship.fleet.player)) {
|
||||||
this.setPosition(ship.arena_x - 500 * Math.cos(ship.arena_angle), ship.arena_y - 500 * Math.sin(ship.arena_angle));
|
this.setPosition(ship.arena_x - 500 * Math.cos(ship.arena_angle), ship.arena_y - 500 * Math.sin(ship.arena_angle));
|
||||||
this.moveToArenaLocation(ship.arena_x, ship.arena_y, ship.arena_angle);
|
this.moveToArenaLocation(ship.arena_x, ship.arena_y, ship.arena_angle, 1);
|
||||||
} else {
|
} else {
|
||||||
this.moveToArenaLocation(ship.arena_x, ship.arena_y, ship.arena_angle, false);
|
this.moveToArenaLocation(ship.arena_x, ship.arena_y, ship.arena_angle, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log processing
|
// Log processing
|
||||||
|
@ -132,86 +132,88 @@ module TK.SpaceTac.UI {
|
||||||
* Process a ship diff
|
* Process a ship diff
|
||||||
*/
|
*/
|
||||||
private processShipDiff(diff: BaseBattleShipDiff): LogProcessorDelegate {
|
private processShipDiff(diff: BaseBattleShipDiff): LogProcessorDelegate {
|
||||||
|
let timer = this.battleview.timer;
|
||||||
|
|
||||||
if (diff instanceof ShipEffectAddedDiff || diff instanceof ShipEffectRemovedDiff) {
|
if (diff instanceof ShipEffectAddedDiff || diff instanceof ShipEffectRemovedDiff) {
|
||||||
return {
|
return {
|
||||||
background: async () => this.updateActiveEffects()
|
background: async () => this.updateActiveEffects()
|
||||||
}
|
}
|
||||||
} else if (diff instanceof ShipValueDiff) {
|
} else if (diff instanceof ShipValueDiff) {
|
||||||
return {
|
return {
|
||||||
background: async (animate, timer) => {
|
background: async (speed: number) => {
|
||||||
if (animate) {
|
if (speed) {
|
||||||
this.toggle_hsp.manipulate("value")(true);
|
this.toggle_hsp.manipulate("value")(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diff.code == "hull") {
|
if (diff.code == "hull") {
|
||||||
if (animate) {
|
if (speed) {
|
||||||
this.updateHull(this.ship.getValue("hull") - diff.diff, diff.diff);
|
this.updateHull(this.ship.getValue("hull") - diff.diff, diff.diff);
|
||||||
await timer.sleep(1000);
|
await timer.sleep(1000 / speed);
|
||||||
this.updateHull(this.ship.getValue("hull"));
|
this.updateHull(this.ship.getValue("hull"));
|
||||||
await timer.sleep(500);
|
await timer.sleep(500 / speed);
|
||||||
} else {
|
} else {
|
||||||
this.updateHull(this.ship.getValue("hull"));
|
this.updateHull(this.ship.getValue("hull"));
|
||||||
}
|
}
|
||||||
} else if (diff.code == "shield") {
|
} else if (diff.code == "shield") {
|
||||||
if (animate) {
|
if (speed) {
|
||||||
this.updateShield(this.ship.getValue("shield") - diff.diff, diff.diff);
|
this.updateShield(this.ship.getValue("shield") - diff.diff, diff.diff);
|
||||||
await timer.sleep(1000);
|
await timer.sleep(1000 / speed);
|
||||||
this.updateShield(this.ship.getValue("shield"));
|
this.updateShield(this.ship.getValue("shield"));
|
||||||
await timer.sleep(500);
|
await timer.sleep(500 / speed);
|
||||||
} else {
|
} else {
|
||||||
this.updateShield(this.ship.getValue("shield"));
|
this.updateShield(this.ship.getValue("shield"));
|
||||||
}
|
}
|
||||||
} else if (diff.code == "power") {
|
} else if (diff.code == "power") {
|
||||||
this.power_text.setText(`${this.ship.getValue("power")}`);
|
this.power_text.setText(`${this.ship.getValue("power")}`);
|
||||||
if (animate) {
|
if (speed) {
|
||||||
await this.battleview.animations.blink(this.power_text);
|
await this.battleview.animations.blink(this.power_text, { speed: speed });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animate) {
|
if (speed) {
|
||||||
await timer.sleep(500);
|
await timer.sleep(500 / speed);
|
||||||
this.toggle_hsp.manipulate("value")(false);
|
this.toggle_hsp.manipulate("value")(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (diff instanceof ShipAttributeDiff) {
|
} else if (diff instanceof ShipAttributeDiff) {
|
||||||
return {
|
return {
|
||||||
background: async (animate, timer) => {
|
background: async (speed: number) => {
|
||||||
if (animate) {
|
if (speed) {
|
||||||
this.displayAttributeChanged(diff);
|
this.displayAttributeChanged(diff, speed);
|
||||||
if (diff.code == "evasion") {
|
if (diff.code == "evasion") {
|
||||||
// TODO diff
|
// TODO diff
|
||||||
this.updateEvasion(this.ship.getAttribute("evasion"));
|
this.updateEvasion(this.ship.getAttribute("evasion"));
|
||||||
this.toggle_hsp.manipulate("attribute")(2000);
|
this.toggle_hsp.manipulate("attribute")(2000 / speed);
|
||||||
}
|
}
|
||||||
await timer.sleep(2000);
|
await timer.sleep(2000 / speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (diff instanceof ShipDamageDiff) {
|
} else if (diff instanceof ShipDamageDiff) {
|
||||||
return {
|
return {
|
||||||
background: async (animate, timer) => {
|
background: async (speed: number) => {
|
||||||
if (animate) {
|
if (speed) {
|
||||||
await this.displayEffect(`${diff.theoretical} damage`, false);
|
await this.displayEffect(`${diff.theoretical} damage`, false, speed);
|
||||||
await timer.sleep(1000);
|
await timer.sleep(1000 / speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (diff instanceof ShipActionToggleDiff) {
|
} else if (diff instanceof ShipActionToggleDiff) {
|
||||||
return {
|
return {
|
||||||
foreground: async (animate, timer) => {
|
foreground: async (speed: number) => {
|
||||||
let action = this.ship.actions.getById(diff.action);
|
let action = this.ship.actions.getById(diff.action);
|
||||||
if (action) {
|
if (action) {
|
||||||
if (animate) {
|
if (speed) {
|
||||||
if (diff.activated) {
|
if (diff.activated) {
|
||||||
await this.displayEffect(`${action.name} ON`, true);
|
await this.displayEffect(`${action.name} ON`, true, speed);
|
||||||
} else {
|
} else {
|
||||||
await this.displayEffect(`${action.name} OFF`, false);
|
await this.displayEffect(`${action.name} OFF`, false, speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateEffectsRadius();
|
this.updateEffectsRadius();
|
||||||
await timer.sleep(500);
|
await timer.sleep(500 / speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,20 +222,20 @@ module TK.SpaceTac.UI {
|
||||||
if (action) {
|
if (action) {
|
||||||
if (action instanceof EndTurnAction) {
|
if (action instanceof EndTurnAction) {
|
||||||
return {
|
return {
|
||||||
foreground: async (animate, timer) => {
|
foreground: async (speed: number) => {
|
||||||
if (animate) {
|
if (speed) {
|
||||||
await this.displayEffect("End turn", true);
|
await this.displayEffect("End turn", true, speed);
|
||||||
await timer.sleep(500);
|
await timer.sleep(500 / speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!(action instanceof ToggleAction)) {
|
} else if (!(action instanceof ToggleAction)) {
|
||||||
let action_name = action.name;
|
let action_name = action.name;
|
||||||
return {
|
return {
|
||||||
foreground: async (animate, timer) => {
|
foreground: async (speed: number) => {
|
||||||
if (animate) {
|
if (speed) {
|
||||||
await this.displayEffect(action_name, true);
|
await this.displayEffect(action_name, true, speed);
|
||||||
await timer.sleep(300);
|
await timer.sleep(300 / speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,11 +246,12 @@ module TK.SpaceTac.UI {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
} else if (diff instanceof ShipMoveDiff) {
|
} else if (diff instanceof ShipMoveDiff) {
|
||||||
let func = async (animate: boolean, timer: Timer) => {
|
let func = async (speed: number) => {
|
||||||
this.moveToArenaLocation(diff.start.x, diff.start.y, diff.start.angle, false);
|
if (speed) {
|
||||||
let duration = this.moveToArenaLocation(diff.end.x, diff.end.y, diff.end.angle, animate, !!diff.engine);
|
await this.moveToArenaLocation(diff.start.x, diff.start.y, diff.start.angle, 0);
|
||||||
if (duration && animate) {
|
await this.moveToArenaLocation(diff.end.x, diff.end.y, diff.end.angle, speed, !!diff.engine);
|
||||||
await timer.sleep(duration);
|
} else {
|
||||||
|
await this.moveToArenaLocation(diff.end.x, diff.end.y, diff.end.angle, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (diff.engine) {
|
if (diff.engine) {
|
||||||
|
@ -259,10 +262,10 @@ module TK.SpaceTac.UI {
|
||||||
} else if (diff instanceof VigilanceAppliedDiff) {
|
} else if (diff instanceof VigilanceAppliedDiff) {
|
||||||
let action = this.ship.actions.getById(diff.action);
|
let action = this.ship.actions.getById(diff.action);
|
||||||
return {
|
return {
|
||||||
foreground: async (animate, timer) => {
|
foreground: async (speed: number) => {
|
||||||
if (animate && action) {
|
if (speed && action) {
|
||||||
await this.displayEffect(`${action.name} (vigilance)`, true);
|
await this.displayEffect(`${action.name} (vigilance)`, true, speed);
|
||||||
await timer.sleep(300);
|
await timer.sleep(300 / speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,7 +318,7 @@ module TK.SpaceTac.UI {
|
||||||
//this.displayEffect("stasis", false);
|
//this.displayEffect("stasis", false);
|
||||||
this.stasis.visible = true;
|
this.stasis.visible = true;
|
||||||
this.stasis.alpha = 0;
|
this.stasis.alpha = 0;
|
||||||
this.battleview.animations.blink(this.stasis, 0.9, 0.7);
|
this.battleview.animations.blink(this.stasis, { alpha_on: 0.9, alpha_off: 0.7 });
|
||||||
} else {
|
} else {
|
||||||
this.stasis.visible = false;
|
this.stasis.visible = false;
|
||||||
}
|
}
|
||||||
|
@ -327,30 +330,31 @@ module TK.SpaceTac.UI {
|
||||||
*
|
*
|
||||||
* Return the duration of animation
|
* Return the duration of animation
|
||||||
*/
|
*/
|
||||||
moveToArenaLocation(x: number, y: number, facing_angle: number, animate = true, engine = true): number {
|
async moveToArenaLocation(x: number, y: number, facing_angle: number, speed = 1, engine = true): Promise<void> {
|
||||||
if (animate) {
|
if (speed) {
|
||||||
let animation = bound(this.arena.view.animations, engine ? "moveInSpace" : "moveTo");
|
let animation = bound(this.arena.view.animations, engine ? "moveInSpace" : "moveTo");
|
||||||
let duration = animation(this, x, y, facing_angle, this.sprite);
|
await animation(this, x, y, facing_angle, this.sprite, speed);
|
||||||
return duration;
|
|
||||||
} else {
|
} else {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.sprite.rotation = facing_angle;
|
this.sprite.rotation = facing_angle;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Briefly show an effect on this ship
|
* Briefly show an effect on this ship
|
||||||
*/
|
*/
|
||||||
async displayEffect(message: string, beneficial: boolean) {
|
async displayEffect(message: string, beneficial: boolean, speed: number) {
|
||||||
if (!this.effects_messages.visible) {
|
if (!this.effects_messages.visible) {
|
||||||
this.effects_messages.removeAll(true);
|
this.effects_messages.removeAll(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let builder = new UIBuilder(this.arena.view, this.effects_messages);
|
if (!speed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let text = builder.text(message, 0, 20 * this.effects_messages.length, {
|
let builder = new UIBuilder(this.arena.view, this.effects_messages);
|
||||||
|
builder.text(message, 0, 20 * this.effects_messages.length, {
|
||||||
color: beneficial ? "#afe9c6" : "#e9afaf"
|
color: beneficial ? "#afe9c6" : "#e9afaf"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -360,19 +364,19 @@ module TK.SpaceTac.UI {
|
||||||
(this.ship.arena_y < arena.height * 0.9) ? 60 : (-60 - this.effects_messages.height)
|
(this.ship.arena_y < arena.height * 0.9) ? 60 : (-60 - this.effects_messages.height)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.effects_messages_toggle.manipulate("added")(1400);
|
this.effects_messages_toggle.manipulate("added")(1400 / speed);
|
||||||
await this.battleview.timer.sleep(1500);
|
await this.battleview.timer.sleep(1500 / speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display interesting changes in ship attributes
|
* Display interesting changes in ship attributes
|
||||||
*/
|
*/
|
||||||
displayAttributeChanged(event: ShipAttributeDiff) {
|
displayAttributeChanged(event: ShipAttributeDiff, speed = 1) {
|
||||||
// TODO show final diff, not just cumulative one
|
// TODO show final diff, not just cumulative one
|
||||||
let diff = (event.added.cumulative || 0) - (event.removed.cumulative || 0);
|
let diff = (event.added.cumulative || 0) - (event.removed.cumulative || 0);
|
||||||
if (diff) {
|
if (diff) {
|
||||||
let name = SHIP_VALUES_NAMES[event.code];
|
let name = SHIP_VALUES_NAMES[event.code];
|
||||||
this.displayEffect(`${name} ${diff < 0 ? "-" : "+"}${Math.abs(diff)}`, diff >= 0);
|
this.displayEffect(`${name} ${diff < 0 ? "-" : "+"}${Math.abs(diff)}`, diff >= 0, speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,15 +155,14 @@ module TK.SpaceTac.UI {
|
||||||
let ship = this.view.battle.playing_ship;
|
let ship = this.view.battle.playing_ship;
|
||||||
if (ship) {
|
if (ship) {
|
||||||
let result = callback(ship);
|
let result = callback(ship);
|
||||||
let timer = new Timer(true);
|
|
||||||
if (result.foreground) {
|
if (result.foreground) {
|
||||||
let promise = result.foreground(false, timer);
|
let promise = result.foreground(0);
|
||||||
if (result.background) {
|
if (result.background) {
|
||||||
let next = result.background;
|
let next = result.background;
|
||||||
promise.then(() => next(false, timer));
|
promise.then(() => next(0));
|
||||||
}
|
}
|
||||||
} else if (result.background) {
|
} else if (result.background) {
|
||||||
result.background(false, timer);
|
result.background(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,7 +175,7 @@ module TK.SpaceTac.UI {
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
console.log("Battle diff", diff);
|
console.log("Battle diff", diff);
|
||||||
}
|
}
|
||||||
let timer = timed ? this.view.timer : new Timer(true);
|
let speed = timed ? 1 : 0;
|
||||||
|
|
||||||
// TODO add priority to sort the delegates
|
// TODO add priority to sort the delegates
|
||||||
let delegates = this.subscriber.map(subscriber => subscriber(diff));
|
let delegates = this.subscriber.map(subscriber => subscriber(diff));
|
||||||
|
@ -189,11 +188,11 @@ module TK.SpaceTac.UI {
|
||||||
this.background_promises = [];
|
this.background_promises = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let promises = foregrounds.map(foreground => foreground(timed, timer));
|
let promises = foregrounds.map(foreground => foreground(speed));
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
let promises = backgrounds.map(background => background(timed, timed ? this.view.timer : new Timer(true)));
|
let promises = backgrounds.map(background => background(speed));
|
||||||
this.background_promises = this.background_promises.concat(promises);
|
this.background_promises = this.background_promises.concat(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,9 +262,9 @@ module TK.SpaceTac.UI {
|
||||||
if (action && action instanceof TriggerAction) {
|
if (action && action instanceof TriggerAction) {
|
||||||
let effect = new WeaponEffect(this.view.arena, ship, diff.target, action);
|
let effect = new WeaponEffect(this.view.arena, ship, diff.target, action);
|
||||||
return {
|
return {
|
||||||
foreground: async (animate, timer) => {
|
foreground: async (speed: number) => {
|
||||||
if (animate) {
|
if (speed) {
|
||||||
await this.view.timer.sleep(effect.start())
|
await effect.start(speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,14 +285,14 @@ module TK.SpaceTac.UI {
|
||||||
if (ship) {
|
if (ship) {
|
||||||
let dead_ship = ship;
|
let dead_ship = ship;
|
||||||
return {
|
return {
|
||||||
foreground: async (animate) => {
|
foreground: async (speed: number) => {
|
||||||
if (dead_ship.is(this.view.ship_hovered)) {
|
if (dead_ship.is(this.view.ship_hovered)) {
|
||||||
this.view.setShipHovered(null);
|
this.view.setShipHovered(null);
|
||||||
}
|
}
|
||||||
this.view.arena.markAsDead(dead_ship);
|
this.view.arena.markAsDead(dead_ship);
|
||||||
this.view.ship_list.refresh();
|
this.view.ship_list.refresh();
|
||||||
if (animate) {
|
if (speed) {
|
||||||
await this.view.timer.sleep(2000);
|
await this.view.timer.sleep(2000 / speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,8 +323,8 @@ module TK.SpaceTac.UI {
|
||||||
* *background* is started when no other foreground delegate is working or pending
|
* *background* is started when no other foreground delegate is working or pending
|
||||||
*/
|
*/
|
||||||
export type LogProcessorDelegate = {
|
export type LogProcessorDelegate = {
|
||||||
foreground?: (animate: boolean, timer: Timer) => Promise<void>,
|
foreground?: (speed: number) => Promise<void>,
|
||||||
background?: (animate: boolean, timer: Timer) => Promise<void>,
|
background?: (speed: number) => Promise<void>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -35,7 +35,7 @@ module TK.SpaceTac.UI.Specs {
|
||||||
});
|
});
|
||||||
|
|
||||||
battle.throwInitiative();
|
battle.throwInitiative();
|
||||||
list.refresh(false);
|
list.refresh(0);
|
||||||
check.in("ship now in play order", check => {
|
check.in("ship now in play order", check => {
|
||||||
check.equals(list.items[0].visible, true, "ship card visible");
|
check.equals(list.items[0].visible, true, "ship card visible");
|
||||||
});
|
});
|
||||||
|
@ -51,14 +51,14 @@ module TK.SpaceTac.UI.Specs {
|
||||||
});
|
});
|
||||||
|
|
||||||
battle.setPlayingShip(battle.play_order[0]);
|
battle.setPlayingShip(battle.play_order[0]);
|
||||||
list.refresh(false);
|
list.refresh(0);
|
||||||
check.in("started", check => {
|
check.in("started", check => {
|
||||||
check.equals(nn(list.findItem(battle.play_order[0])).location, { x: -14, y: 962 }, "first ship position");
|
check.equals(nn(list.findItem(battle.play_order[0])).location, { x: -14, y: 962 }, "first ship position");
|
||||||
check.equals(nn(list.findItem(battle.play_order[1])).location, { x: 2, y: 843 }, "second ship position");
|
check.equals(nn(list.findItem(battle.play_order[1])).location, { x: 2, y: 843 }, "second ship position");
|
||||||
});
|
});
|
||||||
|
|
||||||
battle.advanceToNextShip();
|
battle.advanceToNextShip();
|
||||||
list.refresh(false);
|
list.refresh(0);
|
||||||
check.in("end turn", check => {
|
check.in("end turn", check => {
|
||||||
check.equals(nn(list.findItem(battle.play_order[0])).location, { x: 2, y: 843 }, "first ship position");
|
check.equals(nn(list.findItem(battle.play_order[0])).location, { x: 2, y: 843 }, "first ship position");
|
||||||
check.equals(nn(list.findItem(battle.play_order[1])).location, { x: -14, y: 962 }, "second ship position");
|
check.equals(nn(list.findItem(battle.play_order[1])).location, { x: -14, y: 962 }, "second ship position");
|
||||||
|
@ -78,7 +78,7 @@ module TK.SpaceTac.UI.Specs {
|
||||||
|
|
||||||
let dead = battle.play_order[1];
|
let dead = battle.play_order[1];
|
||||||
dead.setDead();
|
dead.setDead();
|
||||||
list.refresh(false);
|
list.refresh(0);
|
||||||
check.in("ship dead", check => {
|
check.in("ship dead", check => {
|
||||||
check.equals(list.items.length, 3, "item count");
|
check.equals(list.items.length, 3, "item count");
|
||||||
check.equals(nn(list.findItem(battle.play_order[0])).location, { x: -14, y: 962 }, "first ship position");
|
check.equals(nn(list.findItem(battle.play_order[0])).location, { x: -14, y: 962 }, "first ship position");
|
||||||
|
|
|
@ -62,7 +62,7 @@ module TK.SpaceTac.UI {
|
||||||
setShipsFromBattle(battle: Battle, animate = true): void {
|
setShipsFromBattle(battle: Battle, animate = true): void {
|
||||||
this.clearAll();
|
this.clearAll();
|
||||||
iforeach(battle.iships(true), ship => this.addShip(ship));
|
iforeach(battle.iships(true), ship => this.addShip(ship));
|
||||||
this.refresh(animate);
|
this.refresh(animate ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,8 +71,8 @@ module TK.SpaceTac.UI {
|
||||||
bindToLog(log: LogProcessor): void {
|
bindToLog(log: LogProcessor): void {
|
||||||
log.watchForShipChange(ship => {
|
log.watchForShipChange(ship => {
|
||||||
return {
|
return {
|
||||||
foreground: async (animate) => {
|
foreground: async (speed: number) => {
|
||||||
this.refresh(animate)
|
this.refresh(speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -114,7 +114,8 @@ module TK.SpaceTac.UI {
|
||||||
/**
|
/**
|
||||||
* Update the locations of all items
|
* Update the locations of all items
|
||||||
*/
|
*/
|
||||||
refresh(animate = true): void {
|
refresh(speed = 1): void {
|
||||||
|
let duration = speed ? 1000 / speed : 0;
|
||||||
this.items.forEach(item => {
|
this.items.forEach(item => {
|
||||||
if (item.ship.alive) {
|
if (item.ship.alive) {
|
||||||
let position = this.battle.getPlayOrder(item.ship);
|
let position = this.battle.getPlayOrder(item.ship);
|
||||||
|
@ -122,16 +123,16 @@ module TK.SpaceTac.UI {
|
||||||
item.visible = false;
|
item.visible = false;
|
||||||
} else {
|
} else {
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
item.moveAt(-14, 962, animate ? 1000 : 0);
|
item.moveAt(-14, 962, duration);
|
||||||
} else {
|
} else {
|
||||||
item.moveAt(2, 942 - position * 99, animate ? 1000 : 0);
|
item.moveAt(2, 942 - position * 99, duration);
|
||||||
}
|
}
|
||||||
item.visible = true;
|
item.visible = true;
|
||||||
item.setZ(99 - position);
|
item.setZ(99 - position);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
item.setZ(100);
|
item.setZ(100);
|
||||||
item.moveAt(200, item.y, animate ? 1000 : 0);
|
item.moveAt(200, item.y, duration);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,22 +12,19 @@ module TK.SpaceTac.UI.Specs {
|
||||||
battleview.timer = new Timer();
|
battleview.timer = new Timer();
|
||||||
|
|
||||||
let effect = new WeaponEffect(battleview.arena, new Ship(), new Target(0, 0), new TriggerAction("weapon"));
|
let effect = new WeaponEffect(battleview.arena, new Ship(), new Target(0, 0), new TriggerAction("weapon"));
|
||||||
effect.shieldImpactEffect({ x: 10, y: 10 }, { x: 20, y: 15 }, 500, 3000, true);
|
effect.shieldImpactEffect({ x: 10, y: 10 }, { x: 20, y: 15 }, 1, true);
|
||||||
|
|
||||||
let layer = battleview.arena.layer_weapon_effects;
|
let layer = battleview.arena.layer_weapon_effects;
|
||||||
check.equals(layer.length, 1);
|
|
||||||
|
|
||||||
testgame.clockForward(600);
|
|
||||||
check.equals(layer.length, 2);
|
check.equals(layer.length, 2);
|
||||||
|
|
||||||
let child = layer.list[0];
|
check.instance(layer.list[0], Phaser.GameObjects.Particles.ParticleEmitterManager, "first child is an emitter");
|
||||||
if (check.instance(child, UIImage, "first child is an image")) {
|
|
||||||
|
let child = layer.list[1];
|
||||||
|
if (check.instance(child, UIImage, "second child is an image")) {
|
||||||
check.nears(child.rotation, -2.677945044588987, 10);
|
check.nears(child.rotation, -2.677945044588987, 10);
|
||||||
check.equals(child.x, 20, "x");
|
check.equals(child.x, 20, "x");
|
||||||
check.equals(child.y, 15, "y");
|
check.equals(child.y, 15, "y");
|
||||||
}
|
}
|
||||||
|
|
||||||
check.instance(layer.list[1], Phaser.GameObjects.Particles.ParticleEmitterManager, "second child is an emitter");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.case("displays gatling gun effect", check => {
|
test.case("displays gatling gun effect", check => {
|
||||||
|
@ -36,14 +33,14 @@ module TK.SpaceTac.UI.Specs {
|
||||||
|
|
||||||
let ship = nn(battleview.battle.playing_ship);
|
let ship = nn(battleview.battle.playing_ship);
|
||||||
let effect = new WeaponEffect(battleview.arena, new Ship(), Target.newFromShip(ship), new TriggerAction("weapon"));
|
let effect = new WeaponEffect(battleview.arena, new Ship(), Target.newFromShip(ship), new TriggerAction("weapon"));
|
||||||
effect.gunEffect();
|
effect.bulletsExecutor(1);
|
||||||
|
|
||||||
let layer = battleview.arena.layer_weapon_effects;
|
let layer = battleview.arena.layer_weapon_effects;
|
||||||
check.equals(layer.length, 1);
|
check.equals(layer.length, 1);
|
||||||
check.instance(layer.list[0], Phaser.GameObjects.Particles.ParticleEmitterManager, "first child is an emitter");
|
check.instance(layer.list[0], Phaser.GameObjects.Particles.ParticleEmitterManager, "first child is an emitter");
|
||||||
});
|
});
|
||||||
|
|
||||||
test.case("displays shield and hull effect on impacted ships", check => {
|
test.acase("displays shield and hull effect on impacted ships", async check => {
|
||||||
let battleview = testgame.view;
|
let battleview = testgame.view;
|
||||||
battleview.timer = new Timer();
|
battleview.timer = new Timer();
|
||||||
|
|
||||||
|
@ -55,22 +52,27 @@ module TK.SpaceTac.UI.Specs {
|
||||||
|
|
||||||
let dest = new Ship();
|
let dest = new Ship();
|
||||||
let effect = new WeaponEffect(battleview.arena, dest, Target.newFromShip(dest), weapon);
|
let effect = new WeaponEffect(battleview.arena, dest, Target.newFromShip(dest), weapon);
|
||||||
check.patch(effect, "getEffectForWeapon", () => (() => 100));
|
check.patch(effect, "getEffectForWeapon", () => {
|
||||||
|
return {
|
||||||
|
execution: () => Promise.resolve(),
|
||||||
|
delay: () => 0
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
let mock_shield_impact = check.patch(effect, "shieldImpactEffect", null);
|
let mock_shield_impact = check.patch(effect, "shieldImpactEffect", null);
|
||||||
let mock_hull_impact = check.patch(effect, "hullImpactEffect", null);
|
let mock_hull_impact = check.patch(effect, "hullImpactEffect", null);
|
||||||
|
|
||||||
ship.setValue("shield", 0);
|
ship.setValue("shield", 0);
|
||||||
effect.start();
|
await effect.start(1);
|
||||||
check.called(mock_shield_impact, 0);
|
check.called(mock_shield_impact, 0);
|
||||||
check.called(mock_hull_impact, [
|
check.called(mock_hull_impact, [
|
||||||
[Target.newFromShip(dest), ship.location, 40, 400]
|
[Target.newFromShip(dest), ship.location, 1]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
ship.setValue("shield", 10);
|
ship.setValue("shield", 10);
|
||||||
effect.start();
|
await effect.start(2);
|
||||||
check.called(mock_shield_impact, [
|
check.called(mock_shield_impact, [
|
||||||
[Target.newFromShip(dest), ship.location, 40, 800, false]
|
[Target.newFromShip(dest), ship.location, 2, false]
|
||||||
]);
|
]);
|
||||||
check.called(mock_hull_impact, 0);
|
check.called(mock_hull_impact, 0);
|
||||||
});
|
});
|
||||||
|
@ -81,12 +83,12 @@ module TK.SpaceTac.UI.Specs {
|
||||||
|
|
||||||
let effect = new WeaponEffect(battleview.arena, new Ship(), Target.newFromLocation(50, 50), new TriggerAction("weapon"));
|
let effect = new WeaponEffect(battleview.arena, new Ship(), Target.newFromLocation(50, 50), new TriggerAction("weapon"));
|
||||||
|
|
||||||
effect.gunEffect();
|
effect.bulletsExecutor(1);
|
||||||
checkEmitters("gun effect started", 1);
|
checkEmitters("gun effect started", 1);
|
||||||
testgame.clockForward(6000);
|
testgame.clockForward(6000);
|
||||||
checkEmitters("gun effect ended", 0);
|
checkEmitters("gun effect ended", 0);
|
||||||
|
|
||||||
effect.hullImpactEffect({ x: 0, y: 0 }, { x: 50, y: 50 }, 1000, 2000);
|
effect.hullImpactEffect({ x: 0, y: 0 }, { x: 50, y: 50 }, 1);
|
||||||
checkEmitters("hull effect started", 1);
|
checkEmitters("hull effect started", 1);
|
||||||
testgame.clockForward(8500);
|
testgame.clockForward(8500);
|
||||||
checkEmitters("hull effect ended", 0);
|
checkEmitters("hull effect ended", 0);
|
||||||
|
@ -97,9 +99,10 @@ module TK.SpaceTac.UI.Specs {
|
||||||
battleview.timer = new Timer();
|
battleview.timer = new Timer();
|
||||||
|
|
||||||
let effect = new WeaponEffect(battleview.arena, new Ship(), Target.newFromLocation(31, 49), new TriggerAction("weapon"));
|
let effect = new WeaponEffect(battleview.arena, new Ship(), Target.newFromLocation(31, 49), new TriggerAction("weapon"));
|
||||||
|
effect.source = { x: 20, y: 30 };
|
||||||
let result = effect.angularLaser({ x: 20, y: 30 }, 300, Math.PI / 4, -Math.PI / 2, 5);
|
effect.action.angle = 90;
|
||||||
check.equals(result, 200);
|
effect.action.range = 300;
|
||||||
|
effect.laserExecutor(5);
|
||||||
|
|
||||||
let layer = battleview.arena.layer_weapon_effects;
|
let layer = battleview.arena.layer_weapon_effects;
|
||||||
check.equals(layer.length, 1);
|
check.equals(layer.length, 1);
|
||||||
|
@ -109,14 +112,13 @@ module TK.SpaceTac.UI.Specs {
|
||||||
//check.equals(image.width, 300);
|
//check.equals(image.width, 300);
|
||||||
check.equals(image.x, 20);
|
check.equals(image.x, 20);
|
||||||
check.equals(image.y, 30);
|
check.equals(image.y, 30);
|
||||||
check.nears(image.rotation, Math.PI / 4);
|
check.nears(image.rotation, 0.2606023917473408);
|
||||||
}
|
|
||||||
|
|
||||||
let values = battleview.animations.simulate(image, "rotation", 4);
|
checkTween(testgame, image, "rotation", [
|
||||||
check.nears(values[0], Math.PI / 4);
|
0.2606023917473408,
|
||||||
check.nears(values[1], 0);
|
1.8313987185422373,
|
||||||
check.nears(values[2], -Math.PI / 4);
|
]);
|
||||||
check.nears(values[3], -Math.PI / 2);
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
module TK.SpaceTac.UI {
|
module TK.SpaceTac.UI {
|
||||||
|
type WeaponEffectInfo = {
|
||||||
|
execution: (speed: number) => Promise<void>
|
||||||
|
delay: (ship: Ship) => number
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visual effects renderer for weapons.
|
* Visual effects renderer for weapons.
|
||||||
*/
|
*/
|
||||||
export class WeaponEffect {
|
export class WeaponEffect {
|
||||||
// Link to game
|
// Link to view
|
||||||
private ui: MainUI
|
|
||||||
|
|
||||||
// Link to arena
|
|
||||||
private arena: Arena
|
|
||||||
private view: BattleView
|
private view: BattleView
|
||||||
|
|
||||||
// Timer to use
|
// Timer to use
|
||||||
|
@ -20,19 +21,17 @@ module TK.SpaceTac.UI {
|
||||||
private builder: UIBuilder
|
private builder: UIBuilder
|
||||||
|
|
||||||
// Firing ship
|
// Firing ship
|
||||||
private ship: Ship
|
ship: Ship
|
||||||
private source: IArenaLocation
|
source: IArenaLocation
|
||||||
|
|
||||||
// Target (ship or space)
|
// Target (ship or space)
|
||||||
private target: Target
|
target: Target
|
||||||
private destination: IArenaLocation
|
destination: IArenaLocation
|
||||||
|
|
||||||
// Weapon used
|
// Weapon used
|
||||||
private action: TriggerAction
|
action: TriggerAction
|
||||||
|
|
||||||
constructor(arena: Arena, ship: Ship, target: Target, action: TriggerAction) {
|
constructor(arena: Arena, ship: Ship, target: Target, action: TriggerAction) {
|
||||||
this.ui = arena.game;
|
|
||||||
this.arena = arena;
|
|
||||||
this.view = arena.view;
|
this.view = arena.view;
|
||||||
this.timer = arena.view.timer;
|
this.timer = arena.view.timer;
|
||||||
this.layer = arena.layer_weapon_effects;
|
this.layer = arena.layer_weapon_effects;
|
||||||
|
@ -47,167 +46,187 @@ module TK.SpaceTac.UI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the visual effect
|
* Start the visual effect
|
||||||
*
|
|
||||||
* Returns the duration of the effect.
|
|
||||||
*/
|
*/
|
||||||
start(): number {
|
async start(speed: number): Promise<void> {
|
||||||
|
if (!speed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Fire effect
|
// Fire effect
|
||||||
let effect = this.getEffectForWeapon(this.action.code, this.action);
|
let fire_effect = this.getEffectForWeapon(this.action.code, this.action);
|
||||||
let duration = effect();
|
let promises = [fire_effect.execution(speed)];
|
||||||
|
|
||||||
// Damage effect
|
// Damage effect
|
||||||
let action = this.action;
|
let action = this.action;
|
||||||
if (any(action.effects, effect => effect instanceof DamageEffect)) {
|
if (any(action.effects, effect => effect instanceof DamageEffect)) {
|
||||||
let ships = action.getImpactedShips(this.ship, this.target, this.source);
|
let ships = action.getImpactedShips(this.ship, this.target, this.source).map((ship): [Ship, number] => {
|
||||||
|
return [ship, fire_effect.delay(ship) / speed];
|
||||||
|
});
|
||||||
let source = action.blast ? this.target : this.source;
|
let source = action.blast ? this.target : this.source;
|
||||||
let damage_duration = this.damageEffect(source, ships, duration * 0.4, this.action.code == "gatlinggun");
|
promises.push(this.damageEffect(source, ships, speed, this.action.code == "gatlinggun"));
|
||||||
duration = Math.max(duration, damage_duration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return duration;
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a damage effect on ships impacted by a weapon
|
* Add a damage effect on ships impacted by a weapon
|
||||||
*/
|
*/
|
||||||
damageEffect(source: IArenaLocation, ships: Ship[], base_delay = 0, shield_flares = false): number {
|
async damageEffect(source: IArenaLocation, ships: [Ship, number][], speed = 1, shield_flares = false): Promise<void> {
|
||||||
let duration = 0;
|
let promises = ships.map(([ship, delay]) => {
|
||||||
|
return this.timer.sleep(delay).then(() => {
|
||||||
// TODO For each ship, delay should depend on fire effect animation
|
if (ship.getValue("shield") > 0) {
|
||||||
let delay = base_delay;
|
return this.shieldImpactEffect(source, ship.location, speed, shield_flares);
|
||||||
|
} else {
|
||||||
ships.forEach(ship => {
|
return this.hullImpactEffect(source, ship.location, speed);
|
||||||
if (ship.getValue("shield") > 0) {
|
}
|
||||||
this.shieldImpactEffect(source, ship.location, delay, 800, shield_flares);
|
});
|
||||||
duration = Math.max(duration, delay + 800);
|
|
||||||
} else {
|
|
||||||
this.hullImpactEffect(source, ship.location, delay, 400);
|
|
||||||
duration = Math.max(duration, delay + 400);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return duration;
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the function that will be called to start the visual effect
|
* Get the function that will be called to start the visual effect
|
||||||
*/
|
*/
|
||||||
getEffectForWeapon(weapon: string, action: TriggerAction): () => number {
|
getEffectForWeapon(weapon: string, action: TriggerAction): WeaponEffectInfo {
|
||||||
switch (weapon) {
|
switch (weapon) {
|
||||||
case "gatlinggun":
|
case "gatlinggun":
|
||||||
return () => this.gunEffect();
|
return this.bulletsEffect();
|
||||||
case "prokhorovlaser":
|
case "prokhorovlaser":
|
||||||
let angle = arenaAngle(this.source, this.target);
|
return this.laserEffect();
|
||||||
let dangle = radians(action.angle) * 0.5;
|
|
||||||
return () => this.angularLaser(this.source, action.range, angle - dangle, angle + dangle);
|
|
||||||
default:
|
default:
|
||||||
return () => this.defaultEffect();
|
return this.genericEffect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a shield impact effect on a ship
|
* Add a shield impact effect on a ship
|
||||||
*/
|
*/
|
||||||
shieldImpactEffect(from: IArenaLocation, ship: IArenaLocation, delay: number, duration: number, particles = false) {
|
async shieldImpactEffect(from: IArenaLocation, ship: IArenaLocation, speed = 1, particles = false): Promise<void> {
|
||||||
let angle = Math.atan2(from.y - ship.y, from.x - ship.x);
|
let angle = Math.atan2(from.y - ship.y, from.x - ship.x);
|
||||||
|
|
||||||
|
if (particles) {
|
||||||
|
this.builder.particles({
|
||||||
|
key: "battle-effects-hot",
|
||||||
|
source: { x: ship.x + Math.cos(angle) * 40, y: ship.y + Math.sin(angle) * 40, radius: 10 },
|
||||||
|
emitDuration: 500 / speed,
|
||||||
|
count: 50,
|
||||||
|
lifetime: 400 / speed,
|
||||||
|
fading: true,
|
||||||
|
direction: { minangle: Math.PI + angle - 0.3, maxangle: Math.PI + angle + 0.3 },
|
||||||
|
scale: { min: 0.7, max: 1.2 },
|
||||||
|
speed: { min: 20 / speed, max: 80 / speed }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let effect = this.builder.image("battle-effects-shield-impact", ship.x, ship.y, true);
|
let effect = this.builder.image("battle-effects-shield-impact", ship.x, ship.y, true);
|
||||||
effect.setAlpha(0);
|
effect.setAlpha(0);
|
||||||
effect.setRotation(angle);
|
effect.setRotation(angle);
|
||||||
|
await this.view.animations.addAnimation(effect, { alpha: 1 }, 100 / speed, undefined);
|
||||||
let tween1 = this.view.animations.addAnimation(effect, { alpha: 1 }, 100, undefined, delay);
|
await this.timer.sleep(800 / speed);
|
||||||
let tween2 = this.view.animations.addAnimation(effect, { alpha: 0 }, 100, undefined, delay + duration);
|
await this.view.animations.addAnimation(effect, { alpha: 0 }, 100 / speed, undefined);
|
||||||
tween2.then(() => effect.destroy());
|
effect.destroy();
|
||||||
|
|
||||||
if (particles) {
|
|
||||||
this.timer.schedule(delay, () => {
|
|
||||||
this.builder.particles({
|
|
||||||
key: "battle-effects-hot",
|
|
||||||
source: { x: ship.x + Math.cos(angle) * 40, y: ship.y + Math.sin(angle) * 40, radius: 10 },
|
|
||||||
emitDuration: 500,
|
|
||||||
count: 50,
|
|
||||||
lifetime: 400,
|
|
||||||
fading: true,
|
|
||||||
direction: { minangle: Math.PI + angle - 0.3, maxangle: Math.PI + angle + 0.3 },
|
|
||||||
scale: { min: 0.7, max: 1.2 },
|
|
||||||
speed: { min: 20, max: 80 }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a hull impact effect on a ship
|
* Add a hull impact effect on a ship
|
||||||
*/
|
*/
|
||||||
hullImpactEffect(from: IArenaLocation, ship: IArenaLocation, delay: number, duration: number) {
|
async hullImpactEffect(from: IArenaLocation, ship: IArenaLocation, speed = 1): Promise<void> {
|
||||||
let angle = Math.atan2(from.y - ship.y, from.x - ship.x);
|
let angle = Math.atan2(from.y - ship.y, from.x - ship.x);
|
||||||
|
|
||||||
this.builder.particles({
|
this.builder.particles({
|
||||||
key: "battle-effects-hot",
|
key: "battle-effects-hot",
|
||||||
source: { x: ship.x + Math.cos(angle) * 40, y: ship.y + Math.sin(angle) * 40, radius: 7 },
|
source: { x: ship.x + Math.cos(angle) * 40, y: ship.y + Math.sin(angle) * 40, radius: 7 },
|
||||||
emitDuration: 500,
|
emitDuration: 500 / speed,
|
||||||
count: 50,
|
count: 50,
|
||||||
lifetime: 400,
|
lifetime: 400 / speed,
|
||||||
fading: true,
|
fading: true,
|
||||||
direction: { minangle: Math.PI + angle - 0.3, maxangle: Math.PI + angle + 0.3 },
|
direction: { minangle: Math.PI + angle - 0.3, maxangle: Math.PI + angle + 0.3 },
|
||||||
scale: { min: 1, max: 2 },
|
scale: { min: 1, max: 2 },
|
||||||
speed: { min: 120, max: 260 }
|
speed: { min: 120 / speed, max: 260 / speed }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return Promise.resolve(); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default firing effect
|
* Generic weapon effect
|
||||||
*/
|
*/
|
||||||
defaultEffect(): number {
|
async genericExecutor(speed: number): Promise<void> {
|
||||||
this.ui.audio.playOnce("battle-weapon-missile-launch");
|
this.view.audio.playOnce("battle-weapon-missile-launch", speed);
|
||||||
|
|
||||||
let missile = this.builder.image("battle-effects-default", this.source.x, this.source.y, true);
|
let missile = this.builder.image("battle-effects-default", this.source.x, this.source.y, true);
|
||||||
missile.setRotation(arenaAngle(this.source, this.destination));
|
missile.setRotation(arenaAngle(this.source, this.destination));
|
||||||
|
|
||||||
let blast_radius = this.action.blast;
|
let blast_radius = this.action.blast;
|
||||||
|
|
||||||
let projectile_duration = arenaDistance(this.source, this.destination) * 1.5;
|
let projectile_duration = (arenaDistance(this.source, this.destination) * 1.5) || 1;
|
||||||
this.view.animations.addAnimation(missile, { x: this.destination.x, y: this.destination.y }, projectile_duration || 1).then(() => {
|
await this.view.animations.addAnimation(missile, { x: this.destination.x, y: this.destination.y }, projectile_duration / speed);
|
||||||
missile.destroy();
|
missile.destroy();
|
||||||
if (blast_radius > 0) {
|
|
||||||
this.ui.audio.playOnce("battle-weapon-missile-explosion");
|
|
||||||
|
|
||||||
let blast = this.builder.image("battle-effects-blast", this.destination.x, this.destination.y, true);
|
if (blast_radius > 0) {
|
||||||
let scaling = blast_radius * 2 / (blast.width * 0.9);
|
this.view.audio.playOnce("battle-weapon-missile-explosion", speed);
|
||||||
blast.setScale(0.001);
|
|
||||||
Promise.all([
|
let blast = this.builder.image("battle-effects-blast", this.destination.x, this.destination.y, true);
|
||||||
this.view.animations.addAnimation(blast, { alpha: 0 }, 1450, "Quad.easeIn"),
|
let scaling = blast_radius * 2 / (blast.width * 0.9);
|
||||||
this.view.animations.addAnimation(blast, { scaleX: scaling, scaleY: scaling }, 1500, "Quint.easeOut"),
|
blast.setScale(0.001);
|
||||||
]).then(() => blast.destroy());
|
|
||||||
|
await Promise.all([
|
||||||
|
this.view.animations.addAnimation(blast, { alpha: 0 }, 1450 / speed, "Quad.easeIn"),
|
||||||
|
this.view.animations.addAnimation(blast, { scaleX: scaling, scaleY: scaling }, 1500 / speed, "Quint.easeOut"),
|
||||||
|
]);
|
||||||
|
blast.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private genericEffect(): WeaponEffectInfo {
|
||||||
|
return {
|
||||||
|
execution: speed => this.genericExecutor(speed),
|
||||||
|
delay: ship => {
|
||||||
|
let result = (arenaDistance(this.source, this.destination) * 1.5) || 1;
|
||||||
|
if (this.action.blast) {
|
||||||
|
result += 300 * Phaser.Math.Easing.Quintic.Out(arenaDistance(this.destination, ship.location) / this.action.blast);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return projectile_duration + (blast_radius ? 1500 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Laser effect, scanning from one angle to the other
|
* Laser effect, scanning from one angle to the other
|
||||||
*/
|
*/
|
||||||
angularLaser(source: IArenaLocation, radius: number, start_angle: number, end_angle: number, speed = 1): number {
|
laserExecutor(speed: number): Promise<void> {
|
||||||
let duration = 1000 / speed;
|
let duration = 1000 / speed;
|
||||||
|
let angle = arenaAngle(this.source, this.target);
|
||||||
|
let dangle = radians(this.action.angle) * 0.5;
|
||||||
|
|
||||||
this.view.audio.playOnce("battle-weapon-laser");
|
this.view.audio.playOnce("battle-weapon-laser", speed);
|
||||||
|
|
||||||
let laser = this.builder.image("battle-effects-laser", source.x, source.y);
|
let laser = this.builder.image("battle-effects-laser", this.source.x, this.source.y);
|
||||||
laser.setOrigin(0, 0.5);
|
laser.setOrigin(0, 0.5);
|
||||||
laser.setRotation(start_angle);
|
laser.setRotation(angle - dangle);
|
||||||
laser.setScale(radius / laser.width);
|
laser.setScale(this.action.range / laser.width);
|
||||||
let dest_angle = laser.rotation + angularDifference(laser.rotation, end_angle);
|
let dest_angle = laser.rotation + angularDifference(laser.rotation, angle + dangle);
|
||||||
this.view.animations.addAnimation(laser, { rotation: dest_angle }, duration).then(() => laser.destroy());
|
return this.view.animations.addAnimation(laser, { rotation: dest_angle }, duration).then(() => laser.destroy());
|
||||||
|
}
|
||||||
|
|
||||||
return duration;
|
private laserEffect(): WeaponEffectInfo {
|
||||||
|
return {
|
||||||
|
execution: speed => this.laserExecutor(speed),
|
||||||
|
delay: ship => {
|
||||||
|
let angle = arenaAngle(this.source, this.target);
|
||||||
|
let span = radians(this.action.angle);
|
||||||
|
return 900 * Math.abs(angularDifference(angle - span * 0.5, arenaAngle(this.source, ship.location))) / span;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submachine gun effect (quick chain of small bullets)
|
* Submachine gun effect (quick chain of small bullets)
|
||||||
*/
|
*/
|
||||||
gunEffect(): number {
|
bulletsExecutor(speed: number): Promise<void> {
|
||||||
this.ui.audio.playOnce("battle-weapon-bullets");
|
this.view.audio.playOnce("battle-weapon-bullets", speed);
|
||||||
|
|
||||||
let target_ship = this.target.getShip(this.view.battle);
|
let target_ship = this.target.getShip(this.view.battle);
|
||||||
let has_shield = target_ship && (target_ship.getValue("shield") > 0);
|
let has_shield = target_ship && (target_ship.getValue("shield") > 0);
|
||||||
|
@ -218,9 +237,8 @@ module TK.SpaceTac.UI {
|
||||||
if (guard + 1 > distance) {
|
if (guard + 1 > distance) {
|
||||||
guard = distance - 1;
|
guard = distance - 1;
|
||||||
}
|
}
|
||||||
let speed = 2000;
|
let duration = 500 / speed;
|
||||||
let duration = 500;
|
let lifetime = (distance - guard) / (2 * speed);
|
||||||
let lifetime = 1000 * (distance - guard) / speed;
|
|
||||||
this.builder.particles({
|
this.builder.particles({
|
||||||
key: "battle-effects-bullets",
|
key: "battle-effects-bullets",
|
||||||
source: { x: this.source.x + Math.cos(angle) * 35, y: this.source.y + Math.sin(angle) * 35, radius: 3 },
|
source: { x: this.source.x + Math.cos(angle) * 35, y: this.source.y + Math.sin(angle) * 35, radius: 3 },
|
||||||
|
@ -229,11 +247,18 @@ module TK.SpaceTac.UI {
|
||||||
lifetime: lifetime,
|
lifetime: lifetime,
|
||||||
direction: { minangle: angle, maxangle: angle },
|
direction: { minangle: angle, maxangle: angle },
|
||||||
scale: { min: 1, max: 1 },
|
scale: { min: 1, max: 1 },
|
||||||
speed: { min: speed, max: speed },
|
speed: { min: 2000 / speed, max: 2000 / speed },
|
||||||
facing: ParticleFacingMode.ALWAYS
|
facing: ParticleFacingMode.ALWAYS
|
||||||
});
|
});
|
||||||
|
|
||||||
return lifetime;
|
return this.timer.sleep(lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bulletsEffect(): WeaponEffectInfo {
|
||||||
|
return {
|
||||||
|
execution: speed => this.bulletsExecutor(speed),
|
||||||
|
delay: ship => 2000 / arenaDistance(this.source, ship.location)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,8 +57,7 @@ module TK.SpaceTac.UI.Specs {
|
||||||
test.case("animates rotation", check => {
|
test.case("animates rotation", check => {
|
||||||
let obj = new UIBuilder(testgame.view).image("test");
|
let obj = new UIBuilder(testgame.view).image("test");
|
||||||
obj.setRotation(-Math.PI * 2.5);
|
obj.setRotation(-Math.PI * 2.5);
|
||||||
let result = testgame.view.animations.rotationTween(obj, Math.PI * 0.25, 1, "Linear");
|
testgame.view.animations.rotationTween(obj, Math.PI * 0.25, 1, "Linear");
|
||||||
check.equals(result, 750);
|
|
||||||
let points = testgame.view.animations.simulate(obj, "rotation", 4);
|
let points = testgame.view.animations.simulate(obj, "rotation", 4);
|
||||||
check.nears(points[0], -Math.PI * 0.5);
|
check.nears(points[0], -Math.PI * 0.5);
|
||||||
check.nears(points[1], -Math.PI * 0.25);
|
check.nears(points[1], -Math.PI * 0.25);
|
||||||
|
|
|
@ -16,6 +16,16 @@ module TK.SpaceTac.UI {
|
||||||
freezeFrames?: boolean
|
freezeFrames?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration object for blink animations
|
||||||
|
*/
|
||||||
|
interface AnimationBlinkOptions {
|
||||||
|
alpha_on?: number
|
||||||
|
alpha_off?: number
|
||||||
|
times?: number
|
||||||
|
speed?: number
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manager of all animations.
|
* Manager of all animations.
|
||||||
*
|
*
|
||||||
|
@ -177,13 +187,23 @@ module TK.SpaceTac.UI {
|
||||||
/**
|
/**
|
||||||
* Catch the player eye with a blink effect
|
* Catch the player eye with a blink effect
|
||||||
*/
|
*/
|
||||||
async blink(obj: any, alpha_on = 1, alpha_off = 0.3, times = 3): Promise<void> {
|
async blink(obj: { alpha: number }, config: AnimationBlinkOptions = {}): Promise<void> {
|
||||||
|
let speed = coalesce(config.speed, 1);
|
||||||
|
let alpha_on = coalesce(config.alpha_on, 1);
|
||||||
|
|
||||||
|
if (!speed) {
|
||||||
|
obj.alpha = alpha_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
let alpha_off = coalesce(config.alpha_off, 0.3);
|
||||||
|
let times = coalesce(config.times, 3);
|
||||||
|
|
||||||
if (obj.alpha != alpha_on) {
|
if (obj.alpha != alpha_on) {
|
||||||
await this.addAnimation(obj, { alpha: alpha_on }, 150);
|
await this.addAnimation(obj, { alpha: alpha_on }, 150 / speed);
|
||||||
}
|
}
|
||||||
for (let i = 0; i < times; i++) {
|
for (let i = 0; i < times; i++) {
|
||||||
await this.addAnimation(obj, { alpha: alpha_off }, 150);
|
await this.addAnimation(obj, { alpha: alpha_off }, 150 / speed);
|
||||||
await this.addAnimation(obj, { alpha: alpha_on }, 150);
|
await this.addAnimation(obj, { alpha: alpha_on }, 150 / speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +214,7 @@ module TK.SpaceTac.UI {
|
||||||
*
|
*
|
||||||
* Returns the duration
|
* Returns the duration
|
||||||
*/
|
*/
|
||||||
rotationTween(obj: Phaser.GameObjects.Components.Transform, dest: number, speed = 1, easing = "Cubic.easeInOut"): number {
|
rotationTween(obj: Phaser.GameObjects.Components.Transform, dest: number, speed = 1, easing = "Cubic.easeInOut"): Promise<void> {
|
||||||
// Immediately change the object's current rotation to be in range (-pi,pi)
|
// Immediately change the object's current rotation to be in range (-pi,pi)
|
||||||
let value = UITools.normalizeAngle(obj.rotation);
|
let value = UITools.normalizeAngle(obj.rotation);
|
||||||
obj.setRotation(value);
|
obj.setRotation(value);
|
||||||
|
@ -210,9 +230,7 @@ module TK.SpaceTac.UI {
|
||||||
let duration = distance * 1000 / speed;
|
let duration = distance * 1000 / speed;
|
||||||
|
|
||||||
// Tween
|
// Tween
|
||||||
this.addAnimation(obj, { rotation: dest }, duration, easing);
|
return this.addAnimation(obj, { rotation: dest }, duration, easing);
|
||||||
|
|
||||||
return duration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -220,11 +238,10 @@ module TK.SpaceTac.UI {
|
||||||
*
|
*
|
||||||
* Returns the animation duration.
|
* Returns the animation duration.
|
||||||
*/
|
*/
|
||||||
moveTo(obj: Phaser.GameObjects.Components.Transform, x: number, y: number, angle: number, rotated_obj = obj, ease = true): number {
|
moveTo(obj: Phaser.GameObjects.Components.Transform, x: number, y: number, angle: number, rotated_obj = obj, speed = 1, ease = true): Promise<void> {
|
||||||
let duration_rot = this.rotationTween(rotated_obj, angle, 0.5);
|
let duration_rot = this.rotationTween(rotated_obj, angle, 0.5 * speed);
|
||||||
let duration_pos = arenaDistance(obj, { x: x, y: y }) * 2;
|
let duration_pos = arenaDistance(obj, { x: x, y: y }) * 2;
|
||||||
this.addAnimation(obj, { x: x, y: y }, duration_pos, ease ? "Quad.easeInOut" : "Linear");
|
return this.addAnimation(obj, { x: x, y: y }, duration_pos / speed, ease ? "Quad.easeInOut" : "Linear");
|
||||||
return Math.max(duration_rot, duration_pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -232,39 +249,41 @@ module TK.SpaceTac.UI {
|
||||||
*
|
*
|
||||||
* Returns the animation duration.
|
* Returns the animation duration.
|
||||||
*/
|
*/
|
||||||
moveInSpace(obj: Phaser.GameObjects.Components.Transform, x: number, y: number, angle: number, rotated_obj = obj): number {
|
moveInSpace(obj: Phaser.GameObjects.Components.Transform, x: number, y: number, angle: number, rotated_obj = obj, speed = 1): Promise<void> {
|
||||||
this.killPrevious(obj, ["x", "y"]);
|
this.killPrevious(obj, ["x", "y"]);
|
||||||
|
|
||||||
if (x == obj.x && y == obj.y) {
|
if (x == obj.x && y == obj.y) {
|
||||||
return this.rotationTween(rotated_obj, angle, 0.5);
|
return this.rotationTween(rotated_obj, angle, 0.5 * speed);
|
||||||
} else {
|
} else {
|
||||||
this.killPrevious(rotated_obj, ["rotation"]);
|
this.killPrevious(rotated_obj, ["rotation"]);
|
||||||
let distance = Target.newFromLocation(obj.x, obj.y).getDistanceTo(Target.newFromLocation(x, y));
|
let distance = Target.newFromLocation(obj.x, obj.y).getDistanceTo(Target.newFromLocation(x, y));
|
||||||
let duration = Math.sqrt(distance / 1000) * 3000;
|
let duration = Math.sqrt(distance / 1000) * 3000 / speed;
|
||||||
let curve_force = distance * 0.4;
|
let curve_force = distance * 0.4;
|
||||||
let prevx = obj.x;
|
let prevx = obj.x;
|
||||||
let prevy = obj.y;
|
let prevy = obj.y;
|
||||||
let xpts = [obj.x, obj.x + Math.cos(rotated_obj.rotation) * curve_force, x - Math.cos(angle) * curve_force, x];
|
let xpts = [obj.x, obj.x + Math.cos(rotated_obj.rotation) * curve_force, x - Math.cos(angle) * curve_force, x];
|
||||||
let ypts = [obj.y, obj.y + Math.sin(rotated_obj.rotation) * curve_force, y - Math.sin(angle) * curve_force, y];
|
let ypts = [obj.y, obj.y + Math.sin(rotated_obj.rotation) * curve_force, y - Math.sin(angle) * curve_force, y];
|
||||||
let fobj = { t: 0 };
|
let fobj = { t: 0 };
|
||||||
this.tweens.add({
|
return new Promise(resolve => {
|
||||||
targets: [fobj],
|
this.tweens.add({
|
||||||
t: 1,
|
targets: [fobj],
|
||||||
duration: duration,
|
t: 1,
|
||||||
ease: "Sine.easeInOut",
|
duration: duration,
|
||||||
onUpdate: () => {
|
ease: "Sine.easeInOut",
|
||||||
obj.setPosition(
|
onComplete: resolve,
|
||||||
Phaser.Math.Interpolation.CubicBezier(fobj.t, xpts[0], xpts[1], xpts[2], xpts[3]),
|
onUpdate: () => {
|
||||||
Phaser.Math.Interpolation.CubicBezier(fobj.t, ypts[0], ypts[1], ypts[2], ypts[3]),
|
obj.setPosition(
|
||||||
)
|
Phaser.Math.Interpolation.CubicBezier(fobj.t, xpts[0], xpts[1], xpts[2], xpts[3]),
|
||||||
if (prevx != obj.x || prevy != obj.y) {
|
Phaser.Math.Interpolation.CubicBezier(fobj.t, ypts[0], ypts[1], ypts[2], ypts[3]),
|
||||||
rotated_obj.setRotation(Math.atan2(obj.y - prevy, obj.x - prevx));
|
)
|
||||||
|
if (prevx != obj.x || prevy != obj.y) {
|
||||||
|
rotated_obj.setRotation(Math.atan2(obj.y - prevy, obj.x - prevx));
|
||||||
|
}
|
||||||
|
prevx = obj.x;
|
||||||
|
prevy = obj.y;
|
||||||
}
|
}
|
||||||
prevx = obj.x;
|
})
|
||||||
prevy = obj.y;
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
return duration;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,12 @@ module TK.SpaceTac.UI {
|
||||||
/**
|
/**
|
||||||
* Play a single sound effect (fire-and-forget)
|
* Play a single sound effect (fire-and-forget)
|
||||||
*/
|
*/
|
||||||
playOnce(key: string): void {
|
playOnce(key: string, speed = 1): void {
|
||||||
|
if (speed != 1) {
|
||||||
|
// TODO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let manager = this.getManager();
|
let manager = this.getManager();
|
||||||
if (manager) {
|
if (manager) {
|
||||||
if (this.hasCache(key)) {
|
if (this.hasCache(key)) {
|
||||||
|
|
Loading…
Reference in a new issue