From c83e12b6f2de41168de22ff33779be9f2e16ea74 Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 17 Jan 2019 22:43:02 -0400 Subject: Time trial, weee --- index.html | 5 ++ main.js | 224 ++++++++++++++++++++++++++++++++++++++++--------------------- style.css | 33 +++++++++ 3 files changed, 185 insertions(+), 77 deletions(-) diff --git a/index.html b/index.html index 9ab3afc..d0a2b26 100644 --- a/index.html +++ b/index.html @@ -36,12 +36,17 @@
+

TIME TRIAL 30.00s TIME TRIAL

Correct!

Incorrect.
The correct choice was Noelle.

Next

+
+

Good job! You got 0 correct and 0 incorrect.

+

Play again?

+
diff --git a/main.js b/main.js index 97fc007..2129149 100644 --- a/main.js +++ b/main.js @@ -269,6 +269,7 @@ function waitForEvent(el, eventName) { function setupScorekeeper(numCharacters) { const container = document.getElementById('scorekeeper'); + container.innerHTML = ''; for (let i = 0; i < numCharacters; i++) { const el = document.createElement('div') el.classList.add('marker'); @@ -290,6 +291,8 @@ function markScorekeeper(cls, character) { async function mainLol() { const testChar = 'Noellef'; + // one-time initialization .............................................uuh + document.body.addEventListener('keydown', evt => { const choiceContainer = document.getElementById('choice-container'); if (!choiceContainer.classList.contains('hide')) { @@ -322,10 +325,6 @@ async function mainLol() { } }); - // pre-game ------------------------------------------------------------... - - let mode; - const modeLinks = document.querySelectorAll('#mode-picker a[data-mode]'); const modeParas = document.querySelectorAll('#mode-descriptions p[data-mode]'); @@ -344,110 +343,181 @@ async function mainLol() { el.addEventListener('click', evt => pickMode(evt.target)); } + let mode; + pickMode(modeLinks[0]); modeLinks[0].focus(); - // you can pick game options before resources are loaded await loadResources(); document.body.classList.add('resources-loaded'); - const gameEl = document.getElementById('game'); + // pre-game ------------------------------------------------------------... - const playLink = document.getElementById('play-link'); - await waitForEvent(playLink, 'click'); + while (true) { + const gameEl = document.getElementById('game'); - document.body.classList.add('game'); + const playLink = document.getElementById('play-link'); + await waitForEvent(playLink, 'click'); - const deckGames = ['deltarune']; - const hardMode = false; + document.body.classList.add('game'); + document.body.classList.add('mode-' + mode); - const characterDeck = gameData.characters.filter(chr => chr.games.some(g => deckGames.includes(g))); + const deckGames = ['deltarune']; + const hardMode = false; - // game loop -----------------------------------------------------------nym + const characterDeck = gameData.characters.filter(chr => chr.games.some(g => deckGames.includes(g))); - setupScorekeeper(characterDeck.length); + // time trial display ----------------------------------------------TT! - while (characterDeck.length) { - gameEl.classList.remove('correct'); - gameEl.classList.remove('incorrect'); + const startTime = Date.now(); + const timeTrialDuration = 30; + let timeTrialOver = false; - const correctCharacter = characterWithName(testChar) || spliceRandom(characterDeck); + let resolveTimeTrial; + const timeTrialPromise = new Promise(res => { + resolveTimeTrial = res; + }); - const numChoices = 6; - const potentialOptions = characterDeck.slice().filter(chr => chr !== correctCharacter); - const correctIndex = Math.min(Math.floor(Math.random() * numChoices), potentialOptions.length); - const allCharacters = []; - for (let i = 0; i < numChoices; i++) { - if (i === correctIndex) { - allCharacters.push(correctCharacter); - } else if (potentialOptions.length) { - let choice; - allCharacters.push(spliceRandom(potentialOptions)); - } else { - break + const updateTimeTrialDisplay = () => { + const remaining = Math.max(0, startTime + 1000 * timeTrialDuration - Date.now()); + const str = (Math.floor(remaining / 10) / 100).toString(); + const int = str.split('.')[0]; + const frac = str.split('.')[1] || ''; + document.getElementById('time-trial-time').innerHTML = `${int}.${frac.padEnd(2, '0')}s`; + + if (remaining === 0) { + resolveTimeTrial(); + timeTrialOver = true; } - } - let msg; - if (hardMode) { - msg = pickRandom(['Oh?', 'Hello!']); - } else { - msg = pickRandom(correctCharacter.messages); - } + requestAnimationFrame(updateTimeTrialDisplay); + }; if (mode === 'time-trial') { - doSpeech(correctCharacter, msg); - await delay(100); - } else { - await doSpeech(correctCharacter, msg); - await delay(500); + updateTimeTrialDisplay(); } - const choice = await displayChoices(allCharacters, mode === 'time-trial'); + // game loop -----------------------------------------------------------nym + + let numCorrect = 0; + let numIncorrect = 0; + + setupScorekeeper(characterDeck.length); + + while (characterDeck.length) { + gameEl.classList.remove('correct'); + gameEl.classList.remove('incorrect'); + + // heck sorry I don't know how to code I know this is bad + const status = await Promise.race([timeTrialPromise, (async () => { + const correctCharacter = characterWithName(testChar) || spliceRandom(characterDeck); + + const numChoices = 6; + const potentialOptions = characterDeck.slice().filter(chr => chr !== correctCharacter); + const correctIndex = Math.min(Math.floor(Math.random() * numChoices), potentialOptions.length); + const allCharacters = []; + for (let i = 0; i < numChoices; i++) { + if (i === correctIndex) { + allCharacters.push(correctCharacter); + } else if (potentialOptions.length) { + let choice; + allCharacters.push(spliceRandom(potentialOptions)); + } else { + break + } + } - const container = document.getElementById('choice-container'); - for (let i = 0; i < allCharacters.length; i++) { - const el = container.children[i]; - if (i === correctIndex) { - el.classList.add('correct'); - } else { - el.classList.add('incorrect'); - } - if (i === allCharacters.indexOf(choice)) { - el.classList.add('chosen'); - } else { - el.classList.add('not-chosen'); - } - } + let msg; + if (hardMode) { + msg = pickRandom(['Oh?', 'Hello!']); + } else { + msg = pickRandom(correctCharacter.messages); + } - if (choice === correctCharacter) { - markScorekeeper('correct', correctCharacter); - } else { - markScorekeeper('incorrect', correctCharacter); - } + if (mode === 'time-trial') { + doSpeech(correctCharacter, msg.slice(0, 10)); + await delay(100); + } else { + await doSpeech(correctCharacter, msg); + await delay(500); + } - await delay(200); + const choice = await displayChoices(allCharacters, mode === 'time-trial'); + + if (timeTrialOver) return; + + const container = document.getElementById('choice-container'); + for (let i = 0; i < allCharacters.length; i++) { + const el = container.children[i]; + if (i === correctIndex) { + el.classList.add('correct'); + } else { + el.classList.add('incorrect'); + } + if (i === allCharacters.indexOf(choice)) { + el.classList.add('chosen'); + } else { + el.classList.add('not-chosen'); + } + } - if (choice === correctCharacter) { - gameEl.classList.add('correct'); - } else { - gameEl.classList.add('incorrect'); - const el = document.getElementById('correct-character'); - el.innerHTML = ''; - el.appendChild(document.createTextNode(correctCharacter.name)); + if (choice === correctCharacter) { + markScorekeeper('correct', correctCharacter); + numCorrect++; + } else { + markScorekeeper('incorrect', correctCharacter); + numIncorrect++; + } + + await delay(200); + + if (choice === correctCharacter) { + gameEl.classList.add('correct'); + } else { + gameEl.classList.add('incorrect'); + const el = document.getElementById('correct-character'); + el.innerHTML = ''; + el.appendChild(document.createTextNode(correctCharacter.name)); + } + + if (timeTrialOver) return; + + document.getElementById('results').classList.remove('hide'); + + const nextLink = document.getElementById('next-link'); + nextLink.focus(); + await waitForEvent(nextLink, 'click'); + })()]); + + document.getElementById('choice-container').classList.add('hide'); + document.getElementById('results').classList.add('hide'); + + await delay(400); + + if (timeTrialOver) { + break; + } } - document.getElementById('results').classList.remove('hide'); + // results screen ------------------------------------------------------gg- - const nextLink = document.getElementById('next-link'); - nextLink.focus(); - await waitForEvent(nextLink, 'click'); + document.body.classList.add('game-over'); + document.getElementById('final-correct').innerHTML = numCorrect; + document.getElementById('final-incorrect').innerHTML = numIncorrect; - document.getElementById('choice-container').classList.add('hide'); - document.getElementById('results').classList.add('hide'); + const playAgain = document.getElementById('play-again-link'); + playAgain.focus(); + await waitForEvent(playAgain, 'click'); - await delay(400); + document.getElementById('choice-container').innerHTML = ''; + document.getElementById('scorekeeper').innerHTML = ''; + document.body.classList.remove('game-over'); + await delay(1000); + document.body.classList.remove('game'); + for (const el of modeLinks) { + document.body.classList.remove('mode-' + el.dataset.mode); + } } } diff --git a/style.css b/style.css index cc09a9a..7d48241 100644 --- a/style.css +++ b/style.css @@ -46,6 +46,19 @@ body:not(.resources-loaded) #play-paragraph { display: none; } +body:not(.game-over) #final-results { + opacity: 0; +} + +#final-results { + transition: opacity 1s; +} + +/* We have to hide these, or else they messes up layouting of elements below it. */ +body.game-over #results, body.game-over #choice-container { + display: none; +} + #crash-trace { text-align: start; border: 1pt dotted white; @@ -205,6 +218,26 @@ body:not(.resources-loaded) #play-paragraph { background-color: red; } +body:not(.mode-time-trial) #time-trial-heading { + display: none; +} + +#time-trial-heading { + color: rgba(255, 255, 255, 0.3); +} + +#time-trial-time { + color: red; +} + +#final-correct, #final-correct + span { + color: green; +} + +#final-incorrect, #final-incorrect + span { + color: red; +} + body, html { width: 100%; height: 100%; -- cgit 1.3.0-6-gf8a5