diff options
| author | simon-ec <simon@eustaceconsulting.com> | 2026-06-29 09:46:36 -0400 |
|---|---|---|
| committer | simon-ec <simon@eustaceconsulting.com> | 2026-06-29 09:46:36 -0400 |
| commit | e4d7bd675a47fd30e52dba41390eaab705ac2b1e (patch) | |
| tree | d3fc4cf729b24b6093fd606b929ea24acf682db0 | |
| parent | ff51e386c64812cfcc460f584d2ae5f78297a87c (diff) | |
game mode selection ui created
| -rw-r--r-- | quickdraw-game.html | 381 |
1 files changed, 323 insertions, 58 deletions
diff --git a/quickdraw-game.html b/quickdraw-game.html index 77191c3..7d7b9e4 100644 --- a/quickdraw-game.html +++ b/quickdraw-game.html @@ -1,112 +1,377 @@ <!DOCTYPE html> <html> <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <style> * { box-sizing: border-box; margin: 0; padding: 0; + font-family: sans-serif; } html { height: 100vh; width: 100vw; background-color: #161616; + font-size: 24px; + overflow-x: hidden; } body { display: flex; + flex-direction: column; + align-items: center; justify-content: center; + height: 100vh; + width: 100vw; } - #target { + #frame { + width: 60%; + height: 75%; + /** border: 1px solid white; */ + } + #center { + height: 20px; + width: 20px; + background-color: red; + position: absolute; + } + + .target { height: 20px; width: 20px; background-color: red; position: absolute; } - #frame { - width: 75%; - height: 100vh; - border: 1px solid white; + + .hidden { + display: none; + opacity: 0; + } + .fade { + transition: opacity 1s; + } + + .title { + font-weight: bold; + font-size: 2rem; + } + + #text-box { + display: flex; + flex-direction: row; + align-content: end; + justify-content: space-evenly; + color: red; + width: 100%; + min-height: 2rem; + line-height: 2rem; + margin-top: 2rem; + } + + @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; } } + </style> </head> <body> - <div id="frame"> + <div id="frame"></div> + + + + <div id="text-box"> + <span id="intro1" class="hidden title">QUICK</span> + <span id="intro2" class="hidden title">DRAW</span> + + <span id="instructions" class="hidden fade">hover on bullseye to start</span> + + <span id="countdown3" class="hidden title">3</span> + <span id="countdown2" class="hidden title">2</span> + <span id="countdown1" class="hidden title">1</span> + + + <div id="game-modes" class="hidden fade"> + <button id="normal" onclick="handleNormalMode">normal mode</button> + <button id="normal">infinite mode</button> + <button id="normal">countdown mode</button> + </div> + + + <span id="draw" class="hidden title">DRAW!</span> </div> <script> + let gameBorderWidth = 1; + let targetWidth = 20; + let targetHeight = 20; - const gameBorderWidth = 1; - const targetWidth = 20; - const targetHeight = 20; + let pageHeight; + let pageWidth; - let pageWidth = window.innerWidth; - let pageHeight = window.innerHeight; + let frameElement; + let frameRect; + let frameHeight; + let frameWidth; - const frameElement = document.getElementById("frame"); - let frameHeight = frameElement.offsetHeight; - let frameWidth = frameElement.offsetWidth; - - let target; + let center; + let ratio; + let xFrameAdjustment; + let yFrameAdjustment; - window.addEventListener("resize", (e) => { - this.pageWidth = window.innerWidth; - this.pageHeight = window.innerHeight; - this.frameHeight = frameElement.offsetHeight - targetHeight; - this.frameWidth = frameElement.offsetWidth - targetWidth; - console.log('page: ' + this.pageWidth + ' x ' + this.pageHeight); - console.log('frame: ' + this.frameWidth + ' x ' + this.frameHeight); - }); + let hovering = false; - let k, r, x, y; - let radians; + let hoverCount = 0; + + let currentRound = 0; + let countingDown = false; - let ratio = frameHeight / frameWidth; + // text elements + let intro1 = document.getElementById("intro1"); + let intro2 = document.getElementById("intro2"); + let instructions = document.getElementById("instructions"); - let xFrameAdjustment = ((pageWidth - frameWidth) * 2) - (targetWidth / 2); - let yFrameAdjustment = (frameHeight / 2) - (targetWidth / 2); + let one = document.getElementById("countdown1"); + let two = document.getElementById("countdown2"); + let three = document.getElementById("countdown3"); - generateTarget(xFrameAdjustment, yFrameAdjustment) + let draw = document.getElementById("draw"); - for (let i = 0; i < 360; i++) { - r = (frameWidth / 2) - (targetWidth / 2); + window.addEventListener("load", initGame); - radians = degreesToRadians(i); + function setParameters(event) { + pageHeight = window.innerHeight; + pageWidth = window.innerWidth; - x = ((r * 1 * Math.cos(radians)) + xFrameAdjustment); - y = ((r * ratio * Math.sin(radians)) + yFrameAdjustment); - console.log(x + ', ' + y); + frameElement = document.getElementById("frame"); + frameRect = frameElement.getBoundingClientRect(); + frameHeight = frameElement.offsetHeight; + frameWidth = frameElement.offsetWidth; - generateTarget(x, y); - } + // ratio = (frameHeight - (gameBorderWidth*2)) / (frameWidth - (gameBorderWidth*2)); + ratio = frameHeight / frameWidth; + + // adjustments to find center of frame in absolute coords (for origin of target cirlce) + xFrameAdjustment = ((frameWidth / 2) + frameRect.left) - (targetWidth / 2); + yFrameAdjustment = ((frameHeight / 2) + frameRect.top) - (targetWidth / 2); - // init logs: - console.log('page: ' + pageWidth + ' x ' + pageHeight); - console.log('frame: ' + frameWidth + ' x ' + frameHeight); + // init logs: + console.log('page: ' + pageWidth + ' x ' + pageHeight); + console.log('frame: ' + frameWidth + ' x ' + frameHeight); + } + async function initGame() { + setParameters(); - function degreesToRadians(degrees) { - return degrees * (Math.PI / 180) - } - - - function generateTarget(x, y) { - const target = document.createElement("div"); - target.id = "target"; - target.style.top = y +'px'; - target.style.left = x + 'px'; - // console.log(target); - document.getElementById("frame").insertAdjacentElement("afterbegin", target); - } + center = generateTarget(xFrameAdjustment, yFrameAdjustment); + center.id = "center"; + document.body.insertAdjacentElement("afterbegin", center); + + await drawTargetsInCircle(true); + + // insert intro elements into document flow + intro1.style.display = "inline"; + intro2.style.display = "inline"; + // reveal intro elements + intro1.style.opacity = "100"; + await sleep(500); + intro2.style.opacity = "100"; + await sleep(1500); - function getRandomInt(min, max) { - const minCeiled = Math.ceil(min); - const maxFloored = Math.floor(max); - return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled); // The maximum is exclusive and the minimum is inclusive + intro1.classList.add("fade"); + intro2.classList.add("fade"); + + intro1.style.opacity = "0"; + intro2.style.opacity = "0"; + + await sleep(1000); + + intro1.style.display = "none"; + intro2.style.display = "none"; + + window.addEventListener("resize", handleResize); + + document.getElementById("game-modes").style.display = "inline"; + await sleep(500); + document.getElementById("game-modes").style.opacity = "100"; + } + + function handleNormalMode(e) { + center.addEventListener("mouseover", handleHoverStart); + center.addEventListener("mouseleave", handleHoverEnd); + + // instructions.style.display = "inline"; + // instructions.style.opacity = "100"; + } + + function handleHoverStart(e) { + e.target.style.backgroundColor = "green"; + if (currentRound == 0) return; + + hovering = true; + hoverCount++; + + frameElement.replaceChildren(); + + intro1.style.display = "none"; + intro2.style.display = "none"; + instructions.style.display = "none"; + + // if (infinityMode) + + if (currentRound == 0) { startRoundOne(); } + } + + async function startRoundOne() { + if (!await startCountdown(hoverCount)) { + // if user canceled hover, don't continue round + return; + } + console.log('success'); + } + + async function startCountdown(hoverNumber) { + instructions.style.display = "none"; + + countingDown = true; + await sleep(1000); + + one.style.opacity = "0"; + two.style.opacity = "0"; + three.style.opacity = "0"; + + // this check prevents countdown from continuing if user removes / reapplies hover while we're sleeping + if (!hovering || hoverNumber != hoverCount) return false; + one.style.display = "inline"; + two.style.display = "inline"; + three.style.display = "inline"; + + three.style.opacity = "100"; + await sleep(1000); + + two.style.opacity = "100"; + await sleep(1000); + + one.style.opacity = "100"; + await sleep(1000); + + if (!hovering || hoverNumber != hoverCount) return false; + one.style.display = "none"; + two.style.display = "none"; + three.style.display = "none"; + + one.style.opacity = "0"; + two.style.opacity = "0"; + three.style.opacity = "0"; + + draw.style.display = "inline"; + draw.style.opacity = "100"; + + countingDown = false; + setTimeout(() => {draw.style.display = "none"; draw.style.opacity = "0"; }, 1000); + return true; + } + + function handleHoverEnd(e) { + hovering = false; + e.target.style.backgroundColor = "red"; + + if (countingDown) { + one.style.display = "none"; + two.style.display = "none"; + three.style.display = "none"; + draw.style.display = "none"; + + one.style.opacity = "0"; + two.style.opacity = "0"; + three.style.opacity = "0"; + + draw.style.opacity = "0"; + + instructions.style.display = "inline"; + countingDown = false; + } + } + + function handleResize(event) { + frameElement.replaceChildren(); + setParameters(); + + document.getElementById("center").remove(); + center = generateTarget(xFrameAdjustment, yFrameAdjustment); + center.id = "center"; + document.body.insertAdjacentElement("afterbegin", center); + center.addEventListener("mouseover", handleHoverStart); + center.addEventListener("mouseleave", handleHoverEnd); + + if (currentRound == 0) { + drawTargetsInCircle(false); + } + + console.log('page: ' + pageWidth + ' x ' + pageHeight); + console.log('frame: ' + frameWidth + ' x ' + frameHeight); + } + + async function drawTargetsInCircle(animate) { + let r, x, y; + let radians; + let target; + for (let i = 0; i < 360; i = i + 2) { + r = (frameWidth / 2) - (targetWidth / 2) - (gameBorderWidth * 2); + // r = (frameWidth / 2) - (targetWidth / 2); + + radians = degreesToRadians(i); + + x = (r * 1 * Math.cos(radians)) + xFrameAdjustment; + y = (r * ratio * Math.sin(radians)) + yFrameAdjustment; + + // console.log(x + ', ' + y); + // console.log(ratio); + // console.log(xFrameAdjustment + 'adj, ' + yFrameAdjustment + 'adj'); + + target = generateTarget(x, y); + document.getElementById("frame").insertAdjacentElement("afterbegin", target); + + if (animate) await sleep(15); } + } + + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + function degreesToRadians(degrees) { + return degrees * (Math.PI / 180) + } + + + 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; + } + + + function getRandomInt(min, max) { + const minCeiled = Math.ceil(min); + const maxFloored = Math.floor(max); + return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled); // The maximum is exclusive and the minimum is inclusive + } </script> </body> </html> |
