sei-ec-remote / project-1-issues

Open new issues here
1 stars 2 forks source link

Game project issue #174

Closed cooperwhitley closed 1 year ago

cooperwhitley commented 1 year ago

What's the problem you're trying to solve?

I have text set to type out to describe actions taken by the two characters, and theoretically I have a check within an event listener cb function that should prevent the player from advancing text before it has printed. It is not currently working as I would hope, and sometimes if you click through dialogue too fast it will bleed into the next set of text.

Post any code you think might be relevant (one fenced block per file)

typing function & promise constructor:

// typing function
async function typeSentence(str, elId) {
    const letters = str.split('');
    let i = 0;
    let typingTarget = elId;
    while (i < letters.length) {
    // note that wait time here is mirrored in my wait for text function
        await waitForMs(25);
        typingTarget.append(letters[i]);
        i++
    }
    return;
}
// wait promise constructor
function waitForMs(ms) {
    return new Promise(resolve => setTimeout(resolve, ms))
}

wait to advance text function (also includes rendering an indicator which is not relevant to the issue)

async function waitAndRenderSelectorEl(str) {
    const timeToWait = (str.length + 1) * 25;
    await waitForMs(timeToWait);
    // textPrinted is the variable which is important here, placed after the await fn
    textPrinted = true;
    menuSelectorEl.style.visibility = 'visible';
    menuSelectorEl.style.gridArea = '6 / 10 / 7 / 11';
    menuSelectorEl.style.justifySelf = 'center';
    return;
}

turn handler including logic that should prevent text from advancing

function advanceTurn() {
    // check if textPrinted and it is not a turn where the turn count must return to beginning of loop or one with player choice
    if (textPrinted && turn != 1 && turn != 6 && winner === 0) {
        turn += 1;
        turns[turn]();
    } else if (textPrinted && turn === 6 && winner === 0) {
        turn = 1;
        turns[turn]();
    } else return;
}

event listeners that call advanceTurn:

// I needed one for each as due to the stacking of elements it wouldn't behave as a player would expect when they clicked on parts of the text menu
textBoxEl.addEventListener('click', advanceTurn);
menuEl.addEventListener('click', advanceTurn);
menuSelectorEl.addEventListener('click', advanceTurn);

finally, an example turn structure:

function turn5() {
    // make textPrinted false, should prevent turn advancing until it is true again
    textPrinted = false;
    menuSelectorEl.style.visibility = 'hidden';
    renderTextBoxEl();
    // print action text
    let enemyActionText = enemyMoveChoice.info;
    // calls typeSentence function, passing the defined enemyActionText as a string and the textBoxEl as the target
    typeSentence(enemyActionText, textBoxEl);
   // here's my wait to make textPrinted true function, passing the same string so it should calculate the same wait time
    waitAndRenderSelectorEl(enemyActionText);
    // apply and animate damage received
    player.health -= enemyMoveChoice.dmg;
    playerHealth.value -= enemyMoveChoice.dmg;
    pain(playerSpriteEl);
}

If you see an error message, post it here. If you don't, what unexpected behavior are you seeing?

The game allowing players to advance the turn before they should be able to, while the typing function continues, which mangles the text of the next turn

What is your best guess as to the source of the problem?

Best guess would either be waitAndRenderSelectorEl() or advanceTurn(). Not really sure though.

What things have you already tried to solve the problem?

adding a buffer of an additional cycle onto the waitAndRenderSelectorEl() function, but that didn't change anything

Paste a link to your repository here

https://github.com/cooperwhitley/morpheusmelee

timmshinbone commented 1 year ago

Since you're using promises(nice job!) you might wanna make the turn5 function async so that you can await certain other functions like typeSentence and waitAndRenderSelectorEl. Try switching that up and report back here

cooperwhitley commented 1 year ago

Just found a workaround by just combining my typeSentence and waitAndRenderSelectorEl functions. However I'm still unsure what was causing the issue. By making my turn functions async I'm not sure what await would do for me, as it is only calling the two async functions, the only thing looking for their result is advanceTurn which has a check when triggered looking to see if textPrinted has been made true, which is handled within waitAndRenderSelectorEl. I attached a timer to both typeSentence and waitAndRenderSelectorEl using:

// start of function
const start = performance.now();
// body of function
const end = performance.now();
console.log(`function name execution time: ${end - start} ms`);
return;

and this was a series of results for it:

script.js:365 Wait and Render execution time: 902.7000000001863 ms
script.js:384 Typing execution time: 1438.5999999996275 ms
script.js:365 Wait and Render execution time: 1300.4000000003725 ms
script.js:384 Typing execution time: 1516.4000000003725 ms
script.js:365 Wait and Render execution time: 305.3999999994412 ms
script.js:384 Typing execution time: 321.3999999994412 ms
script.js:365 Wait and Render execution time: 527.5 ms
script.js:384 Typing execution time: 567.5 ms
script.js:365 Wait and Render execution time: 603.7000000001863 ms
script.js:384 Typing execution time: 679.3999999994412 ms
script.js:365 Wait and Render execution time: 375.5 ms
script.js:384 Typing execution time: 415.20000000018626 m

This tells me that something about the time setting of each function isn't quite right, however the only difference in how I'm counting wait time for each is:

// for waitAndRenderSelectorEl()
const timeToWait = (str.length + 1) * 25;
// for typeSentence()
const letters = str.split('');
let i = 0;
let typingTarget = elId;
while (i < letters.length) {
    await waitForMs(25);
    typingTarget.append(letters[i]);
    i++
}

this is just as the typing function necessitates splitting the string into an array in order to append letters 1 by 1, however in reading mdn's documentation on string.length vs array.length they should yield the same numerical result. The only thing I imagine could cause a difference would be the greater amount of code in typeSentence taking more compute time, yet the execution times vary wildly in difference. Sometimes less than 30ms apart, sometimes hundreds. For now I'm going to just sub in the combination of the function, however if I get to where I can make the explorable area as I want to I would like to be able to reuse the typing code without it triggering the other two components as they are chiefly meant for the turn based combat phase. Also on the game end screen I don't want the selector to render as it breaks the intended meaning, as you are not meant to click on the text box to start over.

Sorry for the novel, just find this issue interesting/annoying at the same time. Since I got this bug fixed technically this is definitely like last priority territory for right now anyways.

timmshinbone commented 1 year ago

My line of thinking for adding async to the turn was that you'd be able to await the entire completion of each function within that turn. I'd be interested to check this out after lunch and see what's going on here. Could be a quick fix, might need a little more doin to get it going, but it's something that I would have to see live before confidently guiding to a solution.

cooperwhitley commented 1 year ago

Wait time was differing based on execution time for typeSentence taking about an extra 5ms per letter. Fixed by increasing wait multiplier for waitAndRenderSelectorEl to account for this difference.