Fix pterodactyl duck hitbox and prevent duplicate leaderboard submits
This commit is contained in:
parent
4470266234
commit
d433141ccb
49
js/game.js
49
js/game.js
@ -63,6 +63,15 @@ function createInitialState() {
|
|||||||
let state = createInitialState();
|
let state = createInitialState();
|
||||||
let saveEligible = false;
|
let saveEligible = false;
|
||||||
let scoreSavedThisRun = 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) => {
|
window.addEventListener('keydown', (e) => {
|
||||||
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) e.preventDefault();
|
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) e.preventDefault();
|
||||||
@ -81,23 +90,33 @@ restartBtnEl.addEventListener('click', () => {
|
|||||||
saveScoreFormEl.classList.add('hidden');
|
saveScoreFormEl.classList.add('hidden');
|
||||||
saveEligible = false;
|
saveEligible = false;
|
||||||
scoreSavedThisRun = false;
|
scoreSavedThisRun = false;
|
||||||
|
setSaveFormBusy(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
saveScoreFormEl.addEventListener('submit', async (e) => {
|
saveScoreFormEl.addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!saveEligible) return;
|
if (!saveEligible || saveInFlight || scoreSavedThisRun) return;
|
||||||
const name = playerNameEl.value.trim() || 'Anonymous';
|
const name = playerNameEl.value.trim() || 'Anonymous';
|
||||||
|
|
||||||
await fetch('api/scores.php', {
|
setSaveFormBusy(true);
|
||||||
|
try {
|
||||||
|
const res = await fetch('api/scores.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ name, score: state.score })
|
body: JSON.stringify({ name, score: state.score })
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!res.ok) throw new Error('Score save failed');
|
||||||
|
|
||||||
saveEligible = false;
|
saveEligible = false;
|
||||||
scoreSavedThisRun = true;
|
scoreSavedThisRun = true;
|
||||||
saveScoreFormEl.classList.add('hidden');
|
saveScoreFormEl.classList.add('hidden');
|
||||||
await populateLeaderboard();
|
await populateLeaderboard();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
} finally {
|
||||||
|
setSaveFormBusy(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function drawBackground() {
|
function drawBackground() {
|
||||||
@ -177,7 +196,7 @@ async function populateLeaderboard() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const qualifies = scores.length < 10 || state.score > (scores[scores.length - 1]?.score ?? -1);
|
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);
|
saveScoreFormEl.classList.toggle('hidden', !saveEligible);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,10 +253,23 @@ const PTERODACTYL_LANES = [
|
|||||||
|
|
||||||
function getPterodactylHitbox(flyer) {
|
function getPterodactylHitbox(flyer) {
|
||||||
return {
|
return {
|
||||||
x: flyer.x + 6,
|
x: flyer.x + 8,
|
||||||
y: flyer.y + 5,
|
y: flyer.y + 6,
|
||||||
width: flyer.width - 12,
|
width: flyer.width - 16,
|
||||||
height: flyer.height - 10
|
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 p = state.player;
|
||||||
|
const playerHitbox = getPlayerHitboxForAirHazards(p);
|
||||||
for (const flyer of state.pterodactyls) {
|
for (const flyer of state.pterodactyls) {
|
||||||
flyer.x += flyer.vx * dt;
|
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);
|
state.pterodactyls = state.pterodactyls.filter((f) => f.x + f.width > state.cameraX - 150);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user