Fix pterodactyl duck hitbox and prevent duplicate leaderboard submits

This commit is contained in:
OpenClaw Engineer 2026-03-03 22:23:41 -06:00
parent 4470266234
commit d433141ccb

View File

@ -63,6 +63,15 @@ function createInitialState() {
let state = createInitialState();
let saveEligible = false;
let scoreSavedThisRun = false;
let saveInFlight = false;
const saveScoreBtnEl = saveScoreFormEl.querySelector('button[type="submit"]');
function setSaveFormBusy(isBusy) {
saveInFlight = isBusy;
playerNameEl.disabled = isBusy;
if (saveScoreBtnEl) saveScoreBtnEl.disabled = isBusy;
}
window.addEventListener('keydown', (e) => {
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) e.preventDefault();
@ -81,23 +90,33 @@ restartBtnEl.addEventListener('click', () => {
saveScoreFormEl.classList.add('hidden');
saveEligible = false;
scoreSavedThisRun = false;
setSaveFormBusy(false);
});
saveScoreFormEl.addEventListener('submit', async (e) => {
e.preventDefault();
if (!saveEligible) return;
if (!saveEligible || saveInFlight || scoreSavedThisRun) return;
const name = playerNameEl.value.trim() || 'Anonymous';
await fetch('api/scores.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, score: state.score })
});
setSaveFormBusy(true);
try {
const res = await fetch('api/scores.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, score: state.score })
});
saveEligible = false;
scoreSavedThisRun = true;
saveScoreFormEl.classList.add('hidden');
await populateLeaderboard();
if (!res.ok) throw new Error('Score save failed');
saveEligible = false;
scoreSavedThisRun = true;
saveScoreFormEl.classList.add('hidden');
await populateLeaderboard();
} catch (err) {
console.error(err);
} finally {
setSaveFormBusy(false);
}
});
function drawBackground() {
@ -177,7 +196,7 @@ async function populateLeaderboard() {
});
const qualifies = scores.length < 10 || state.score > (scores[scores.length - 1]?.score ?? -1);
saveEligible = qualifies && !scoreSavedThisRun;
saveEligible = qualifies && !scoreSavedThisRun && !saveInFlight;
saveScoreFormEl.classList.toggle('hidden', !saveEligible);
}
@ -234,10 +253,23 @@ const PTERODACTYL_LANES = [
function getPterodactylHitbox(flyer) {
return {
x: flyer.x + 6,
y: flyer.y + 5,
width: flyer.width - 12,
height: flyer.height - 10
x: flyer.x + 8,
y: flyer.y + 6,
width: flyer.width - 16,
height: flyer.height - 12
};
}
function getPlayerHitboxForAirHazards(player) {
const widthInset = player.ducking ? 8 : 6;
const topInset = player.ducking ? 8 : 4;
const bottomInset = 2;
return {
x: player.x + widthInset,
y: player.y + topInset,
width: player.width - widthInset * 2,
height: player.height - topInset - bottomInset
};
}
@ -258,9 +290,10 @@ function updatePterodactyls(dt) {
}
const p = state.player;
const playerHitbox = getPlayerHitboxForAirHazards(p);
for (const flyer of state.pterodactyls) {
flyer.x += flyer.vx * dt;
if (intersects(p, getPterodactylHitbox(flyer))) applyHit('Pterodactyl collision. Duck next time!');
if (intersects(playerHitbox, getPterodactylHitbox(flyer))) applyHit('Pterodactyl collision. Duck next time!');
}
state.pterodactyls = state.pterodactyls.filter((f) => f.x + f.width > state.cameraX - 150);
}