Skip to content

Commit

Permalink
🎥 Animate fights
Browse files Browse the repository at this point in the history
  • Loading branch information
ferdodo committed Nov 18, 2024
1 parent ea54ecb commit 4a14237
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 9 deletions.
1 change: 0 additions & 1 deletion core/fixtures/with-game-over.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { withTwoPlayerGameStarted } from "./with-two-player-game-started";

export async function withGameOver(): Promise<TestContext> {
const testContext = await withTwoPlayerGameStarted();
const game = await getGame(testContext);

while (isGameInProgress(await getGame(testContext))) {
await goToNextPhase(testContext);
Expand Down
25 changes: 25 additions & 0 deletions core/utils/compute-animation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Hero } from "../types/hero";
import type { Action } from "../types/action";
import { Animation } from "../types/animation";

export function computeAnimation(hero: Hero, actions: Action[]) {
for (const action of actions) {
if (action.move?.heroId === hero.id) {
return Animation.Walk;
}

if (action.attack?.attacker === hero.id) {
return Animation.Attack;
}

if (action.attack?.target === hero.id) {
if (hero.attributes.health > 0) {
return Animation.Hurt;
}

return Animation.Death;
}
}

return Animation.Idle;
}
109 changes: 109 additions & 0 deletions core/utils/observe-portrayed-confrontation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import type { Game } from "../types/game";
import type { OperatorFunction } from "rxjs";
import { switchMap, distinctUntilKeyChanged } from "rxjs/operators";
import { Observable } from "rxjs";
import type { Confrontation } from "../types/confrontation";
import { Phase } from "../types/phase";
import type { PublicKey } from "../types/public-key";
import { computeConfrontation } from "./compute-confrontation";
import type { Piece } from "../types/piece";
import { Animation } from "../types/animation";
import { revertPosition } from "./revert-position";
import { computeAnimation } from "./compute-animation";

export function observePortrayedConfrontation(
publicKey: PublicKey,
): OperatorFunction<Game, Piece[] | undefined> {
return (source) => {
return source.pipe(
distinctUntilKeyChanged("phase"),
switchMap((game: Game) => {
return new Observable<Piece[] | undefined>((subscriber) => {
if (game.phase !== Phase.Combat) {
subscriber.next(undefined);
subscriber.complete();
return;
}

if (!game.combats) {
throw new Error("No combat found !");
}

const combat = game.combats.find(
(combat) =>
combat.playerAPublicKey === publicKey ||
combat.playerBPublicKey === publicKey,
);

if (!combat) {
throw new Error("No combat found !");
}

const actionIterator = combat.actions[Symbol.iterator]();

let confrontation = {
playerAHeroes: combat.playerAHeroes,
playerBHeroes: combat.playerBHeroes,
};

let portrayedConfrontation: Piece[] = [
...confrontation.playerAHeroes.map((hero) => ({
hero,
animation: Animation.Idle,
transposed: false,
animationStartAt: Date.now(),
right: false,
})),
...confrontation.playerBHeroes.map((hero) => ({
hero: {
...hero,
position: revertPosition(hero.position),
},
animation: Animation.Idle,
transposed: false,
animationStartAt: Date.now(),
right: true,
})),
];

subscriber.next(portrayedConfrontation);

const interval = setInterval(() => {
const item = actionIterator.next();

if (item.done) {
clearInterval(interval);
subscriber.complete();
return;
}

const action = item.value;
confrontation = computeConfrontation(confrontation, item.value);

portrayedConfrontation = [
...confrontation.playerAHeroes.map((hero) => ({
hero,
animation: computeAnimation(hero, [action]),
transposed: false,
animationStartAt: Date.now(),
right: false,
})),
...confrontation.playerBHeroes.map((hero) => ({
hero: {
...hero,
position: revertPosition(hero.position),
},
animation: computeAnimation(hero, [action]),
transposed: false,
animationStartAt: Date.now(),
right: true,
})),
];

subscriber.next(portrayedConfrontation);
}, 1000);
});
}),
);
};
}
13 changes: 9 additions & 4 deletions core/utils/portray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,29 @@ import type { Display } from "../types/display";
import type { Game } from "../types/game";
import type { Observable, OperatorFunction } from "rxjs";
import { map, combineLatestWith, startWith } from "rxjs/operators";
import { Phase } from "../types/phase";
import { Animation } from "../types/animation";
import { interval } from "rxjs";
import { getLevelUpCost } from "./get-level-up-cost";
import { observePortrayedConfrontation } from "./observe-portrayed-confrontation";
import type { PublicKey } from "../types/public-key";
import type { Piece } from "../types/piece";

export function portray(publicKey: string): OperatorFunction<Game, Display> {
export function portray(publicKey: PublicKey): OperatorFunction<Game, Display> {
return (source: Observable<Game>) =>
source.pipe(
map((game: Game) => {
combineLatestWith(source.pipe(observePortrayedConfrontation(publicKey))),
map(([game, confrontationPieces]: [Game, Piece[] | undefined]) => {
const display: Display = {
pieces:
confrontationPieces ||
game.playerHeroes[publicKey]?.map((hero) => ({
hero,
animation: Animation.Idle,
transposed: false,
animationStartAt: Date.now(),
right: false,
})) || [],
})) ||
[],
players: game.publicKeys.map((p) => ({
name: game.nicknames[p],
health: game.playerHealths[p] || 0,
Expand Down
5 changes: 1 addition & 4 deletions interface/utils/render-piece-mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ export function renderPieceMesh(
mesh.material = material;
}

if (meshCreated) {
mesh.rotation.set(0, piece.right ? Math.PI : 0, 0);
}

mesh.rotation.set(0, piece.right ? Math.PI : 0, 0);
const scale = 5.3;
mesh.scale.set(scale, scale, 1);
}

0 comments on commit 4a14237

Please sign in to comment.