This commit is contained in:
@@ -30,7 +30,20 @@ function randomTier(min: number, max: number): number {
|
||||
return min + Math.floor(Math.random() * (max - min + 1));
|
||||
}
|
||||
|
||||
export function MelonGame({ citizens, onFinish }: { citizens: MemberRow[]; onFinish: (score: number) => void }) {
|
||||
export type MelonRunTelemetry = {
|
||||
v: 1;
|
||||
duration_ms: number;
|
||||
actions: number;
|
||||
merges: number;
|
||||
};
|
||||
|
||||
export function MelonGame({
|
||||
citizens,
|
||||
onFinish,
|
||||
}: {
|
||||
citizens: MemberRow[];
|
||||
onFinish: (score: number, run: MelonRunTelemetry) => void;
|
||||
}) {
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const previewRef = useRef<HTMLDivElement | null>(null);
|
||||
const guideLineRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -71,6 +84,9 @@ export function MelonGame({ citizens, onFinish }: { citizens: MemberRow[]; onFin
|
||||
const pendingMergesRef = useRef<PendingMerge[]>([]);
|
||||
const mergingBodyIdsRef = useRef(new Set<number>());
|
||||
const dangerSinceRef = useRef<number | null>(null);
|
||||
const runStartedAtRef = useRef(Date.now());
|
||||
const dropCountRef = useRef(0);
|
||||
const mergeCountRef = useRef(0);
|
||||
|
||||
const spawnPiece = useCallback(
|
||||
(tier: number, x: number, y: number): Piece => {
|
||||
@@ -128,6 +144,10 @@ export function MelonGame({ citizens, onFinish }: { citizens: MemberRow[]; onFin
|
||||
pendingMergesRef.current = [];
|
||||
mergingBodyIdsRef.current.clear();
|
||||
dangerSinceRef.current = null;
|
||||
runStartedAtRef.current = Date.now();
|
||||
dropCountRef.current = 0;
|
||||
mergeCountRef.current = 0;
|
||||
lastDropAtRef.current = -Infinity;
|
||||
scoreRef.current = 0;
|
||||
statusRef.current = "playing";
|
||||
const firstNextTier = randomTier(DROP_MIN_TIER, dropMaxTier);
|
||||
@@ -160,6 +180,7 @@ export function MelonGame({ citizens, onFinish }: { citizens: MemberRow[]; onFin
|
||||
// incrémente le compteur d'id) : appelé une seule fois ici, jamais
|
||||
// depuis l'intérieur du updater de setPieces, qui doit rester pur.
|
||||
const dropped = spawnPiece(tier, x, radius + 6);
|
||||
dropCountRef.current += 1;
|
||||
setPieces((current) => [...current, dropped]);
|
||||
|
||||
// La file glisse d'un cran : ce qui était annoncé en second devient la
|
||||
@@ -281,6 +302,7 @@ export function MelonGame({ citizens, onFinish }: { citizens: MemberRow[]; onFin
|
||||
if (!bodyA || !bodyB) continue;
|
||||
|
||||
Matter.Composite.remove(engine.world, [bodyA, bodyB]);
|
||||
mergeCountRef.current += 1;
|
||||
bodiesRef.current.delete(merge.pieceIdA);
|
||||
bodiesRef.current.delete(merge.pieceIdB);
|
||||
nodeRefs.current.delete(merge.pieceIdA);
|
||||
@@ -338,7 +360,12 @@ export function MelonGame({ citizens, onFinish }: { citizens: MemberRow[]; onFin
|
||||
} else if (now - dangerSinceRef.current >= GAME_OVER_GRACE_MS) {
|
||||
statusRef.current = "dead";
|
||||
setStatus("dead");
|
||||
onFinishRef.current(scoreRef.current);
|
||||
onFinishRef.current(scoreRef.current, {
|
||||
v: 1,
|
||||
duration_ms: Math.max(0, Date.now() - runStartedAtRef.current),
|
||||
actions: dropCountRef.current,
|
||||
merges: mergeCountRef.current,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
dangerSinceRef.current = null;
|
||||
|
||||
Reference in New Issue
Block a user