From c09a4dff6b0a672e882e2d7d820c8164f30dd23d Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 28 Jul 2026 21:49:08 -0500 Subject: [PATCH] i think i finally have screen resizing fully smoothed out --- quickdraw-game.html | 150 ++++++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 67 deletions(-) diff --git a/quickdraw-game.html b/quickdraw-game.html index a2f92c1..bdb8737 100644 --- a/quickdraw-game.html +++ b/quickdraw-game.html @@ -90,14 +90,16 @@ margin-top: 2rem; } + #game-over-buttons { + gap: 2rem; + align-items: center; + justify-content: center; + } + @media screen and (max-width: 750px) { html { font-size: 32px; } - #text-box { - flex-direction: column; - align-items: center; - } .text { font-size: .5rem; } .title { font-size: 2rem; } } @@ -173,10 +175,10 @@ let countingDown = false; let hovering = false; let hoverCount = 0; // number of times the cursor has hovered over bullseye. used to cleanly handle round starting / cancelling - let gameIsOver = false; // GAMEPLAY VARIABLES let targetsClicked = 0; + let numTargets = 0; // "NORMAL" MODE ONLY VARIABLES let currentRound = 0; @@ -187,6 +189,7 @@ let bestNormalTime = 0; // "COUNTDOWN" MODE ONLY VARIABLES + let countdownBullseyeNeeded = false; let countdownTime = 0; let bestCountdownScore = 0; @@ -257,8 +260,6 @@ } async function handlePlayAgain(e) { - gameIsOver = false; - // hide game over buttons gameOverButtons.style.display = "none"; gameOverButtons.style.opacity = "0"; @@ -271,6 +272,10 @@ handleNormalMode(e); } else if (gamemode == "countdown") { + setParameters(); + center = generateTarget(xFrameAdjustment, yFrameAdjustment); + center.id = "center"; + document.body.insertAdjacentElement("afterbegin", center); handleCountdownMode(e); } else { @@ -280,7 +285,6 @@ async function handleNormalMode(e) { gamemode = "normal"; - console.log("game mode: " + gamemode); // setup mode parameters currentRound = 1; @@ -302,7 +306,7 @@ async function handleCountdownMode(e) { gamemode = "countdown"; - console.log("game mode: " + gamemode); + countdownBullseyeNeeded = true; await fadeMainMenuOut(); // set game instruction text + fade it in @@ -318,7 +322,15 @@ } async function handleReset(e) { - gameIsOver = false; + // (bullseye won't be on screen after a countdown round) + if (gamemode == "countdown") { + setParameters(); + center = generateTarget(xFrameAdjustment, yFrameAdjustment); + center.id = "center"; + document.body.insertAdjacentElement("afterbegin", center); + } + + // refresh game state variables gamemode = ""; currentRound = 0; @@ -334,6 +346,11 @@ await sleep(800); await drawTargetsInCircle(2); await fadeMainMenuIn(); + + // auto-reset bullseye if page was resized during animation + if (needsResizeAdjustment) { + handlePageResize(); + } } async function handleHoverStart(e) { @@ -366,32 +383,36 @@ // setup mode parameters targetsClicked = 0; - tempTargetsClicked = 0; + numTargets = 0; countdownTime = 15.0; // clear screen + render countdown / score center.remove(); gameText.innerText = countdownTime.toFixed(3) + "s\ntargets clicked: " + targetsClicked; - gameText.style.display = "inline"; - gameText.style.opacity = "100"; + + // delay reveal of score until after "DRAW" fades + setTimeout(() => { + gameText.style.display = "inline"; + gameText.style.opacity = "100";}, 1000); // begin actual game loop! randomTargetGenerator(1); + numTargets++; + countdownBullseyeNeeded = false; while (countdownTime > 0.0) { - gameText.innerText = countdownTime.toFixed(3) + "s\ntargets clicked: " + targetsClicked; - // auto-reset screen if page was resized during animation + gameText.innerText = countdownTime.toFixed(2) + "s\ntargets clicked: " + targetsClicked; + // auto-reset target spawn paremeters if page was resized if (needsResizeAdjustment) { handlePageResize(); } // generate new target if last one was clicked - if (targetsClicked != tempTargetsClicked) { + if (targetsClicked == numTargets) { randomTargetGenerator(1); - tempTargetsClicked++; + numTargets++; } countdownTime = countdownTime - .01; await sleep(10); } - gameIsOver = true; // ensure no targets are still on screen after timer ends frameElement.replaceChildren(); @@ -408,14 +429,11 @@ localStorage.setItem("bestCountdownScore", bestCountdownScore); } gameText.innerText = "TARGETS CLICKED: " + targetsClicked + - "\nHIGH SCORE: " + bestCountdownScore + - "\nhover on circle to go back to main menu.."; + "\nHIGH SCORE: " + bestCountdownScore; + + numTargets = 0; + targetsClicked =0; - // bring bullseye back to screen - center = generateTarget(xFrameAdjustment, yFrameAdjustment); - center.id = "center"; - document.body.insertAdjacentElement("afterbegin", center); - gameOverButtons.style.display = "flex"; gameOverButtons.style.opacity = "100"; } @@ -432,7 +450,6 @@ return; } - let numTargets = 0; if (roundNumber == 1) { numTargets = 1; } @@ -459,10 +476,16 @@ currentRound++; - // bring bullseye back to screen - center = generateTarget(xFrameAdjustment, yFrameAdjustment); - center.id = "center"; - document.body.insertAdjacentElement("afterbegin", center); + // auto-reset bullseye if page gets resized at all + if (needsResizeAdjustment) { + handlePageResize(); + } + // even if no resize, bring bullseye back to screen + else { + center = generateTarget(xFrameAdjustment, yFrameAdjustment); + center.id = "center"; + document.body.insertAdjacentElement("afterbegin", center); + } // ensure "DRAW" isn't still lingering on screen after round draw.style.display = "none"; @@ -470,7 +493,6 @@ if (roundNumber == 3) { // GAME OVER STUFF - gameIsOver = true; if (totalTime < bestNormalTime || bestNormalTime == 0) { if (bestNormalTime == 0) { alert("NEW FASTEST TIME!!! congratulations cowboy."); @@ -485,6 +507,9 @@ "s\nTOTAL: " + totalTime.toFixed(3) + "s\nBEST SCORE: " + bestNormalTime.toFixed(3); + numTargets = 0; + targetsClicked =0; + gameOverButtons.style.display = "flex"; gameOverButtons.style.opacity = "100"; } @@ -503,7 +528,7 @@ } /** - * HELPER TO KICK-OFF "NORMAL MODE" ROUNDS + * HELPER TO KICK-OFF COUNTDOWNS FROM HOVER */ async function normalModeRoundCountdown(hoverNumber) { gameText.style.display = "none"; @@ -578,8 +603,7 @@ draw.style.opacity = "0"; if (gamemode == "normal") { - if (currentRound <= 1) { - drawTargetsInCircle(0); + if (currentRound == 1) { gameText.innerText = "hover on middle circle to start the countdown,\nthen click the targets as fast as possible!"; } else { @@ -588,7 +612,6 @@ } else if (gamemode == "countdown") { - drawTargetsInCircle(0); gameText.innerText = "hover on middle circle to start the countdown,\nthen click as many targets as possible!"; } @@ -603,46 +626,40 @@ } function handlePageResize(event) { - // take note if page was resized during animation or mid-countdown round to auto-reset at earliest convenience - if (!needsResizeAdjustment && (drawingCircle || countdownTime > 0)) { - needsResizeAdjustment = true; return; + // take note if page was resized during animation or mid gameplay to auto-reset at earliest convenience + if (drawingCircle || (targetsClicked < numTargets)) { + needsResizeAdjustment = true; + return; } - /** - * if no game has started yet, re-draw circle - * - * no matter what, if targets on screen, do not reset, do not redraw middle circle, but do flag for reset - * - * if adding eventListener, need to redraw center circle! - * - * if we are playing normal mode: - * -- if round 1, redraw cirlce and addEventListener for hover - * -- if round 2/3, only addEventListener for hover - * -- if round 4, only addEvenListener for reset - * - * if we are playing countdown mode: - * -- if countdownTimer == 0, - * ----- need a way to know if this is before or after the game! - * ----- if before game, redraw cirlce and addEventListener for hover - * ----- if after game, only addEventListener for reset - * -- if countdownTimer > 0, flag for reset upon next target clicked, no event listeners - **/ - frameElement.replaceChildren(); setParameters(); - - center.remove(); - center = generateTarget(xFrameAdjustment, yFrameAdjustment); - center.id = "center"; - document.body.insertAdjacentElement("afterbegin", center); + // if at main menu, resize bullseye if (gamemode == "") { + center.remove(); + center = generateTarget(xFrameAdjustment, yFrameAdjustment); + center.id = "center"; + document.body.insertAdjacentElement("afterbegin", center); drawTargetsInCircle(0); } - else if (gamemode != "") { + // if inbetween gameplay rounds, move middle circle and add game event listener + else if ((gamemode == "normal" && currentRound < 4) || + (gamemode == "countdown" && countdownBullseyeNeeded) + ) { + center.remove(); + center = generateTarget(xFrameAdjustment, yFrameAdjustment); + center.id = "center"; + document.body.insertAdjacentElement("afterbegin", center); center.addEventListener("mouseover", handleHoverStart); center.addEventListener("mouseleave", handleHoverEnd); } + else if (gamemode == "normal" && currentRound == 4) { + center.remove(); + center = generateTarget(xFrameAdjustment, yFrameAdjustment); + center.id = "center"; + document.body.insertAdjacentElement("afterbegin", center); + } console.log('page: ' + pageWidth + ' x ' + pageHeight); console.log('frame: ' + frameWidth + ' x ' + frameHeight); @@ -661,6 +678,7 @@ y = (r * ratio * Math.sin(radians)) + yFrameAdjustment; target = generateTarget(x, y); + target.classList.add("target"); document.getElementById("frame").insertAdjacentElement("afterbegin", target); if (drawDurationSeconds) { @@ -724,7 +742,7 @@ let radians, radius let x, y; let target; - for (let i = 0; i < numTargets; i++){ + for (let i = 0; i < numTargets; i++) { radians = degreesToRadians(getRandomInt(0, 360)); radius = (frameWidth / 2) - (targetWidth / 2) - (gameBorderWidth * 2); x = (radius * 1 * Math.cos(radians)) + xFrameAdjustment; @@ -739,10 +757,8 @@ function generateTarget(x, y) { const target = document.createElement("div"); - target.classList.add("target"); target.style.top = y +'px'; target.style.left = x + 'px'; - // console.log(target); return target; }