1

I'm new to programming and am designing a game for a school assignment. I have made a small animation in CSS of a dice being shaken, then displaying the number of eyes of the throw. What I want is to call on the function playYourTurn() once (linked to a button), and then it would run the animation twice with some delay inbetween and move the players accordingly.

As it is now, only the second animation, playSpino(), runs. I have tried many variations with not having them as separate functions, change the intervals etc but to no avail. Sometimes it's only the first animation, playSasha(), that runs. Borth markers move accordingly to their throws, I have checked by writing it out in the log, so it's just the animations I'm struggling with.

The functions and the function in which they're being called:

function playYourTurn() 
{
    playSasha();

    window.setTimeout(() => { }, 1500);
  
    playSpino(); 
}

function playSasha() 
{
    var diceResultSasha = rollDice();
    window.setTimeout(() => { moveSasha(diceResultSasha) }, 1000)

    window.setTimeout(resetDice, 3000)   
}

function playSpino() 
{
    var diceResultSpino = rollDice();
    window.setTimeout(() => { moveSpino(diceResultSpino) }, 4000)

    window.setTimeout(resetDice, 7000)
}

The function with the animation that currently only runs once:

function rollDice() 
{  
    resetDice();
    
    var diceresult = document.getElementById('diceresult')

    var dice = Math.floor(Math.random() * 6) + 1;

    document.getElementById('shakebox').className = 'diceAnimation';

    diceresult.className = 'resultVisible';

(a switch statement follows here).

Here is the CSS code for the animation:

.diceAnimation
{
   animation: shake 0.2s;
   animation-iteration-count: 5;
}
 
 @keyframes shake 
 {
   0% { transform: translate(1px, 1px) rotate(0deg); }
   10% { transform: translate(-2px, -3px) rotate(-20deg); }
   20% { transform: translate(-4px, 0px) rotate(20deg); }
   30% { transform: translate(3px, 2px) rotate(0deg); }
   40% { transform: translate(1px, -1px) rotate(10deg); }
   50% { transform: translate(-1px, 2px) rotate(-10deg); }
   60% { transform: translate(-3px, 1px) rotate(0deg); }
   70% { transform: translate(3px, 1px) rotate(-20deg); }
   80% { transform: translate(-1px, -1px) rotate(20deg); }
   90% { transform: translate(1px, 2px) rotate(0deg); }
   100% { transform: translate(1px, -2px) rotate(-10deg); }
 }

There is also a CSS effect that makes the default dice fade in to the number of eyes thrown that looks like this:

#diceresult
{
   opacity: 0;
   position: absolute;
}

.resultVisible
{
   opacity: 1 !important;
   transition: all 1s ease;
}
5
  • 2
    Please don't post code as images. Type the code and format it. Thanks. Commented May 12 at 10:50
  • Sorry about that, I've changed it now! I'm brand new to this site so haven't gotten the hang of it yet. Commented May 12 at 11:49
  • Can you add the CSS that performs the animation? And where do you use the value of dice with regards to the animation? Commented May 12 at 12:27
  • The value of dice is used in another function which moves the markers along the board. I will add the CSS code. Commented May 12 at 13:21
  • The "question" as it stands now is useless for future help seekers. I suggest to delete this question. Commented May 13 at 8:58

2 Answers 2

0

The first setTimeout() does not create a delay between calling playSasha() and playSpino(). Which means the rollDice() for the one is called shortly after the rollDice() for the other.

Moving the call to playSpino() inside that setTimeout() will fix that.

function playYourTurn() 
{
    playSasha();

    window.setTimeout(() => { playSpino(); }, 1500);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Sadly not working either, but thanks for the suggestion!
0

Realise that with setTimeout only the function that is passed as argument is delayed. Other code will just continue immediately. When your purpose is to wait for an animation to finish, then listen to the animationend event.

Also, you did not provide the resetDice code, but make sure that when you change an HTML property there, like className, that you allow for a paint cycle to happen. If not, and you immediately try to start the animation again, that animation will not happen.

Finally, all this becomes easier to do when you use async await

Here is some code you could use:

// Define two utility functions to work with promises:
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const animationCompleted = elem => new Promise(resolve => elem.addEventListener("animationend", resolve, {once:true}));

// Define constants for the HTML elements
const diceresult = document.getElementById('diceresult');
const shakebox = document.getElementById('shakebox');
const rollButton = document.getElementById('roll');

async function rollDice() {  
    await resetDice();
    const dice = Math.floor(Math.random() * 6) + 1;
    shakebox.className = 'diceAnimation';
    await animationCompleted(shakebox);
    diceresult.className = 'resultVisible';
    diceresult.textContent = dice;
    return dice;
}

async function resetDice() {
    shakebox.className = '';
    diceresult.className = 'resultHidden';
    await delay(50);
}

function moveSasha(move) {
    console.log("Sasha moves", move);
}

function moveSpino(move) {
    console.log("Spino moves", move);
}

async function playYourTurn() {
    rollButton.setAttribute("disabled", true);
    const diceResultSasha = await playSasha();
    const diceResultSpino = await playSpino(); 
    // ... 
    // ...
    rollButton.removeAttribute("disabled");
}

async function playSasha() {
    const diceResultSasha = await rollDice();
    moveSasha(diceResultSasha);
    await delay(3000);
    return diceResultSasha;
}

async function playSpino() {
    var diceResultSpino = await rollDice();
    moveSpino(diceResultSpino);
    await delay(3000); // 7000 seemed a long time. Adjusted
    return diceResultSpino;
}

rollButton.addEventListener("click", playYourTurn);
.diceAnimation {
   animation: shake 0.2s;
   animation-iteration-count: 5;
}
 
@keyframes shake {
   0% { transform: translate(1px, 1px) rotate(0deg); }
   10% { transform: translate(-2px, -3px) rotate(-20deg); }
   20% { transform: translate(-4px, 0px) rotate(20deg); }
   30% { transform: translate(3px, 2px) rotate(0deg); }
   40% { transform: translate(1px, -1px) rotate(10deg); }
   50% { transform: translate(-1px, 2px) rotate(-10deg); }
   60% { transform: translate(-3px, 1px) rotate(0deg); }
   70% { transform: translate(3px, 1px) rotate(-20deg); }
   80% { transform: translate(-1px, -1px) rotate(20deg); }
   90% { transform: translate(1px, 2px) rotate(0deg); }
   100% { transform: translate(1px, -2px) rotate(-10deg); }
}

#shakebox { border: 1px solid; display: inline-block; }
.resultHidden { visibility: hidden; }
.resultVisible { visibility: visible; }
<button id="roll">Roll die</button>
<div id="shakebox">die</div>
<span id="diceresult" class="resultHidden"></span><br>

6 Comments

Thank you so much for this extensive reply! I have tried getting this code to work but I get the error message "Uncaught (in promise) ReferenceError: delay is not defined". I definetely went in way over my head with this game, I had no idea it was this complicated and involved just to run an animation twice in the same sequence!
So did you define delay as a global, like in my answer? As you can see it works in this snippet, so probably you have a typo, or didn't define it, or defined it at the wrong place.
I did, unfortunately all this is way above my skill level so I'm having a hard time pinpointing what exactly is causing it to not work. I did however manage to solve the problem with the help of a tech savvy friend, he messed around with the timeout functions and now it works! I added the code to the original post.
Don't add solutions to the original post. Instead post it as an answer. It is a pity that you didn't give a reproducible example in your question, which makes that only those that sit next to you and see the whole context can actually see what you are doing wrong.
Ok, will delete the solution. You are most likely correct, but please keep in mind that I'm a student just learning coding. I have no real concept of how to present code, ask productive questions, etiquette for this webpage etc. I posted here out of desperation as no one I knew was able to help me and thus didn't have the ability to perfectly grasp all aspects of what makes a good question. If this forum is primarily for those of levels above beginners I will respect that and refrain from posting until I know more.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.