mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-31 10:18:57 +00:00
ENH - scale sky flappy difficulty
This commit is contained in:
@@ -3,9 +3,12 @@ import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
createSkyFlappyGame,
|
||||
FLAPPY_GAP_HEIGHT,
|
||||
FLAPPY_MAX_SPEED,
|
||||
FLAPPY_MAX_GAP_TOP,
|
||||
FLAPPY_MIN_GAP_HEIGHT,
|
||||
FLAPPY_MIN_GAP_TOP,
|
||||
flapSkyGlider,
|
||||
getSkyFlappyDifficulty,
|
||||
stepSkyFlappy,
|
||||
} from './engine'
|
||||
|
||||
@@ -36,10 +39,21 @@ describe('sky flappy engine', () => {
|
||||
expect(high.obstacles[0].gapTop + FLAPPY_GAP_HEIGHT).toBeLessThan(100)
|
||||
})
|
||||
|
||||
it('increases speed and narrows the gap as the score rises', () => {
|
||||
const start = getSkyFlappyDifficulty(0)
|
||||
const advanced = getSkyFlappyDifficulty(20)
|
||||
const maximum = getSkyFlappyDifficulty(100)
|
||||
|
||||
expect(advanced.speed).toBeGreaterThan(start.speed)
|
||||
expect(advanced.gapHeight).toBeLessThan(start.gapHeight)
|
||||
expect(maximum.speed).toBe(FLAPPY_MAX_SPEED)
|
||||
expect(maximum.gapHeight).toBe(FLAPPY_MIN_GAP_HEIGHT)
|
||||
})
|
||||
|
||||
it('scores an obstacle only once', () => {
|
||||
const state = {
|
||||
...flapSkyGlider(createSkyFlappyGame()),
|
||||
obstacles: [{ gapTop: 30, id: 1, scored: false, x: 7 }],
|
||||
obstacles: [{ gapHeight: FLAPPY_GAP_HEIGHT, gapTop: 30, id: 1, scored: false, x: 7 }],
|
||||
}
|
||||
const scored = stepSkyFlappy(state, 0.01, () => 0.5)
|
||||
expect(scored.score).toBe(1)
|
||||
@@ -49,7 +63,7 @@ describe('sky flappy engine', () => {
|
||||
it('detects collision using the player edges', () => {
|
||||
const state = {
|
||||
...flapSkyGlider(createSkyFlappyGame()),
|
||||
obstacles: [{ gapTop: 40, id: 1, scored: false, x: 22 }],
|
||||
obstacles: [{ gapHeight: FLAPPY_GAP_HEIGHT, gapTop: 40, id: 1, scored: false, x: 22 }],
|
||||
playerY: 41,
|
||||
playerVelocity: 0,
|
||||
}
|
||||
|
||||
@@ -6,8 +6,21 @@ export const FLAPPY_GRAVITY = 82
|
||||
export const FLAPPY_IMPULSE = -34
|
||||
export const FLAPPY_OBSTACLE_WIDTH = 14
|
||||
export const FLAPPY_GAP_HEIGHT = 29
|
||||
export const FLAPPY_MIN_GAP_HEIGHT = 22
|
||||
export const FLAPPY_MIN_GAP_TOP = 15
|
||||
export const FLAPPY_MAX_GAP_TOP = 56
|
||||
export const FLAPPY_BASE_SPEED = 20.5
|
||||
export const FLAPPY_MAX_SPEED = 40
|
||||
|
||||
export function getSkyFlappyDifficulty(score: number): {
|
||||
gapHeight: number
|
||||
speed: number
|
||||
} {
|
||||
return {
|
||||
gapHeight: Math.max(FLAPPY_MIN_GAP_HEIGHT, FLAPPY_GAP_HEIGHT - score * 0.35),
|
||||
speed: Math.min(FLAPPY_MAX_SPEED, FLAPPY_BASE_SPEED + score * 0.65),
|
||||
}
|
||||
}
|
||||
|
||||
export function createSkyFlappyGame(): SkyFlappyGameState {
|
||||
return {
|
||||
@@ -27,9 +40,11 @@ export function flapSkyGlider(state: SkyFlappyGameState): SkyFlappyGameState {
|
||||
|
||||
function createObstacle(
|
||||
id: number,
|
||||
gapHeight: number,
|
||||
random: () => number,
|
||||
): SkyFlappyObstacle {
|
||||
return {
|
||||
gapHeight,
|
||||
gapTop:
|
||||
FLAPPY_MIN_GAP_TOP +
|
||||
Math.max(0, Math.min(1, random())) *
|
||||
@@ -52,7 +67,7 @@ function collidesWithObstacle(
|
||||
|
||||
return (
|
||||
playerY - FLAPPY_PLAYER_RADIUS < obstacle.gapTop ||
|
||||
playerY + FLAPPY_PLAYER_RADIUS > obstacle.gapTop + FLAPPY_GAP_HEIGHT
|
||||
playerY + FLAPPY_PLAYER_RADIUS > obstacle.gapTop + obstacle.gapHeight
|
||||
)
|
||||
}
|
||||
|
||||
@@ -63,19 +78,22 @@ export function stepSkyFlappy(
|
||||
): SkyFlappyGameState {
|
||||
if (state.status !== 'playing' || elapsedSeconds <= 0) return state
|
||||
|
||||
const speed = Math.min(33, 20.5 + state.score * 0.38)
|
||||
const difficulty = getSkyFlappyDifficulty(state.score)
|
||||
const playerVelocity = state.playerVelocity + FLAPPY_GRAVITY * elapsedSeconds
|
||||
const playerY = state.playerY + playerVelocity * elapsedSeconds
|
||||
let nextObstacleId = state.nextObstacleId
|
||||
let obstacles = state.obstacles
|
||||
.map((obstacle) => ({
|
||||
...obstacle,
|
||||
x: obstacle.x - speed * elapsedSeconds,
|
||||
x: obstacle.x - difficulty.speed * elapsedSeconds,
|
||||
}))
|
||||
.filter((obstacle) => obstacle.x + FLAPPY_OBSTACLE_WIDTH > -2)
|
||||
|
||||
if (obstacles.length === 0 || obstacles[obstacles.length - 1].x < 61) {
|
||||
obstacles = [...obstacles, createObstacle(nextObstacleId, random)]
|
||||
obstacles = [
|
||||
...obstacles,
|
||||
createObstacle(nextObstacleId, difficulty.gapHeight, random),
|
||||
]
|
||||
nextObstacleId += 1
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ export type SkyFlappyStatus = 'over' | 'paused' | 'playing' | 'ready'
|
||||
export type SkyFlappyDesign = 'dawn' | 'neon' | 'storm'
|
||||
|
||||
export type SkyFlappyObstacle = {
|
||||
gapHeight: number
|
||||
gapTop: number
|
||||
id: number
|
||||
scored: boolean
|
||||
|
||||
@@ -141,7 +141,7 @@ onBeforeUnmount(() => {
|
||||
<div class="flappy-clouds" aria-hidden="true"><i v-for="cloud in 7" :key="cloud"></i></div>
|
||||
<div v-for="obstacle in game.obstacles" :key="obstacle.id" class="flappy-obstacle" :style="obstacleStyle(obstacle)" aria-hidden="true">
|
||||
<span class="flappy-obstacle__top" :style="{ height: `${obstacle.gapTop}%` }"></span>
|
||||
<span class="flappy-obstacle__bottom" :style="{ top: `${obstacle.gapTop + 29}%` }"></span>
|
||||
<span class="flappy-obstacle__bottom" :style="{ top: `${obstacle.gapTop + obstacle.gapHeight}%` }"></span>
|
||||
</div>
|
||||
<div :key="flapEffect" class="sky-glider sky-glider--player" :style="playerStyle" aria-hidden="true"><i></i><span></span><b></b></div>
|
||||
<strong v-if="game.status === 'ready'" class="flappy-ready">{{ phone.t('Apps.skyFlappy.firstTap') }}</strong>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Sky Phone</title>
|
||||
<script type="module" crossorigin src="./assets/sky-index-DNP-Eo5h.js"></script>
|
||||
<script type="module" crossorigin src="./assets/sky-index-49wlApfN.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./assets/sky-index-D9eWeoNZ.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user