Ajoute une difficulté progressive au Vol d'Icare
Build and deploy / deploy (push) Successful in 1m36s
Build and deploy / deploy (push) Successful in 1m36s
À partir du score 10, la vitesse de défilement augmente et l'écart entre les colonnes se resserre progressivement, jusqu'à un palier à score 50 (vitesse ×1.6, écart réduit à 75%) pour ne pas devenir injouable sur une longue partie. Le gap est maintenant stocké par colonne (plutôt qu'une constante globale) pour que les colonnes déjà en place ne changent pas de taille rétroactivement.
This commit is contained in:
@@ -6,13 +6,17 @@ import {
|
||||
COLUMN_GAP_MARGIN,
|
||||
COLUMN_SPACING,
|
||||
COLUMN_WIDTH,
|
||||
DIFFICULTY_RAMP_SPAN,
|
||||
DIFFICULTY_START_SCORE,
|
||||
FIXED_DT_MS,
|
||||
FLAP_IMPULSE,
|
||||
FORWARD_SPEED,
|
||||
GAP_MIN_MULTIPLIER,
|
||||
GROUND_Y,
|
||||
ICARUS_RADIUS,
|
||||
ICARUS_X,
|
||||
MAX_FRAME_DT_MS,
|
||||
SPEED_MAX_MULTIPLIER,
|
||||
TILT_MAX_RADIANS,
|
||||
VIEWPORT_HEIGHT,
|
||||
VIEWPORT_WIDTH,
|
||||
@@ -29,9 +33,16 @@ type Status = "idle" | "flying" | "dead";
|
||||
|
||||
const CONFETTI_COLORS = ["#E7C560", "#C9A227", "#F4ECD8", "#A5342A", "#5E6B3B", "#2E6E7E", "#B08D57"];
|
||||
|
||||
function randomGapCenter(): number {
|
||||
const minCenter = COLUMN_GAP / 2 + COLUMN_GAP_MARGIN;
|
||||
const maxCenter = GROUND_Y - COLUMN_GAP / 2 - COLUMN_GAP_MARGIN;
|
||||
// 0 avant DIFFICULTY_START_SCORE, monte jusqu'à 1 sur DIFFICULTY_RAMP_SPAN
|
||||
// points, puis reste à 1 (palier, pour ne pas devenir injouable).
|
||||
function difficultyProgress(score: number): number {
|
||||
if (score <= DIFFICULTY_START_SCORE) return 0;
|
||||
return Math.min(1, (score - DIFFICULTY_START_SCORE) / DIFFICULTY_RAMP_SPAN);
|
||||
}
|
||||
|
||||
function randomGapCenter(gap: number): number {
|
||||
const minCenter = gap / 2 + COLUMN_GAP_MARGIN;
|
||||
const maxCenter = GROUND_Y - gap / 2 - COLUMN_GAP_MARGIN;
|
||||
return minCenter + Math.random() * Math.max(0, maxCenter - minCenter);
|
||||
}
|
||||
|
||||
@@ -112,8 +123,8 @@ function drawColumnShaft(
|
||||
}
|
||||
|
||||
function drawColumn(ctx: CanvasRenderingContext2D, column: Column) {
|
||||
const gapTop = column.gapCenterY - COLUMN_GAP / 2;
|
||||
const gapBottom = column.gapCenterY + COLUMN_GAP / 2;
|
||||
const gapTop = column.gapCenterY - column.gap / 2;
|
||||
const gapBottom = column.gapCenterY + column.gap / 2;
|
||||
drawColumnShaft(ctx, column.x, 0, gapTop, true);
|
||||
drawColumnShaft(ctx, column.x, gapBottom, GROUND_Y - gapBottom, false);
|
||||
}
|
||||
@@ -203,8 +214,14 @@ export function IcarusGame({ onFinish }: { onFinish: (score: number) => void })
|
||||
}
|
||||
icarusRef.current = stepIcarus(icarusRef.current, FIXED_DT_MS);
|
||||
|
||||
// Difficulté progressive : vitesse en hausse et écart resserré au
|
||||
// fil du score, jusqu'à un palier (voir difficultyProgress).
|
||||
const progress = difficultyProgress(scoreRef.current);
|
||||
const currentSpeed = FORWARD_SPEED * (1 + (SPEED_MAX_MULTIPLIER - 1) * progress);
|
||||
const currentGap = COLUMN_GAP * (1 - (1 - GAP_MIN_MULTIPLIER) * progress);
|
||||
|
||||
for (const column of columnsRef.current) {
|
||||
column.x -= FORWARD_SPEED * (FIXED_DT_MS / 1000);
|
||||
column.x -= currentSpeed * (FIXED_DT_MS / 1000);
|
||||
if (!column.scored && column.x + COLUMN_WIDTH < ICARUS_X - ICARUS_RADIUS) {
|
||||
column.scored = true;
|
||||
scoreRef.current += 1;
|
||||
@@ -217,7 +234,8 @@ export function IcarusGame({ onFinish }: { onFinish: (score: number) => void })
|
||||
if (!last || last.x < VIEWPORT_WIDTH - COLUMN_SPACING) {
|
||||
columnsRef.current.push({
|
||||
x: last ? last.x + COLUMN_SPACING : VIEWPORT_WIDTH,
|
||||
gapCenterY: randomGapCenter(),
|
||||
gapCenterY: randomGapCenter(currentGap),
|
||||
gap: currentGap,
|
||||
scored: false,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user