skip to Main Content

I’m trying to create a Simon Game and when the user click the button I want it to be animated.

I used addClass and setTimeOut with removeClass, the animation happens but I need to click the same button two times.

var buttonColours = ["red", "blue", "green", "yellow"];
var gamePattern = [];
var userClickedPattern = [];

function playSound(name) {

    var audio = new Audio("./sounds/" + name + ".mp3");
    audio.play();

}

function nextSequence() {

    var randomNumber = Math.floor(Math.random() * 4);

    var randomChosenColour = buttonColours[randomNumber];

    gamePattern.push(randomChosenColour);

    $("#" + randomChosenColour).fadeOut(100).fadeIn(100);

    playSound(randomChosenColour);

}

function animatePress(currentColour) {

    $("." + currentColour).on("click", function () {

        $("." + currentColour).addClass("pressed");

        setTimeout(function () {

            $("." + currentColour).removeClass("pressed");

        }, 100);

    })

}

$(".btn").on("click", function () {

    var userChosenColour = this.id;

    userClickedPattern.push(userChosenColour);

    playSound(userChosenColour);

    animatePress(userChosenColour);

})

2

Answers


  1. Seems like you have attached the click event handler inside the animatePress function each time the button is clicked, causing it to require two clicks on subsequent attempts.
    Please separate the click handler from the animatePress function,

    function animatePress(currentColour) {
            $("#" + currentColour).addClass("pressed");
            setTimeout(function () {
                $("#" + currentColour).removeClass("pressed");
            }, 100);
        }
        
        // Click event listener
        $(".btn").on("click", function () {
            var userChosenColour = this.id;
            userClickedPattern.push(userChosenColour);
            playSound(userChosenColour);
            animatePress(userChosenColour);
        });
    

    Hope this helps!

    Login or Signup to reply.
  2. The short answer was given by @santhoshprem but if you would like to better understand your problem and the solution here is the long answer…

    The nested event handlers in the animatePress function prevent the second click event from firing. This is because the animatePress function creates a new click event handler that is encapsulated within it.


    Understanding the Problem

    Encapsulated event handler

    The first click of the button executes the click handler as follows :

    $(".btn").on("click", function () {
        var userChosenColour = this.id;
        userClickedPattern.push(userChosenColour);
        playSound(userChosenColour);
        animatePress(userChosenColour);
    });
    

    Lets call this "first click". Now with that click event fired(first click), it calls the animatePress() function which then creates another click event handler that needs a click itself(second click) to execute the .addClass() and .removeClass() methods. This new click event handler is encapsulated inside animatePress(), meaning it’s inaccessable outside of animatePress().
    Normally these handlers could fire as one on the stack but becuase the second handler can’t be accessed until the first handler calls animatePress(). They get separated on the stack.

    It goes something like this…

    1. First click, fires first event handler.(added to stack and then removed/done)
      • Note : First event handler calls animatePress().
    2. animatePress() executes, creating a new click event handler.
      • Note : Now second click handler needs a click event(second click) to execute.
    3. Second click, fires newly created event handler, executing addClass() & removeClass().
    4. addClass() & removeClass() execute animation/s.
    5. Finished!

    The second event handler(inside animatePress()) is not created until after the first event handler is fired and done.


    Understanding the solution

    Less is more?

    To solve your problem simply remove $("." + currentColour).on("click", function () { } from the animatedPress() function like this :

    function animatePress(currentColour) {
        $("#" + currentColour).addClass("pressed");
        setTimeout(function () {
            $("#" + currentColour).removeClass("pressed");
        }, 100);
    }
    

    Now there’s only one click event needed to complete execution.

    1. Fires the only click event handler.
    2. Handler calls the animatePress() function.
    3. animatePress() function executes addClass()/removeClass() now becuase blocking condition was removed.
    4. addClass() & removeClass() execute animation/s.
    5. Finished and goal achieved!

    Complete corrected code

    var buttonColours = ["red", "blue", "green", "yellow"];
    var gamePattern = [];
    var userClickedPattern = [];
    
    function playSound(name) {
        var audio = new Audio("./sounds/" + name + ".mp3");
        audio.play();
    }
    
    function nextSequence() {
        var randomNumber = Math.floor(Math.random() * 4);
        var randomChosenColour = buttonColours[randomNumber];
        gamePattern.push(randomChosenColour);
        $("#" + randomChosenColour).fadeOut(100).fadeIn(100);
        playSound(randomChosenColour);
    }
    function animatePress(currentColour) {
        $("#" + currentColour).addClass("pressed");
        setTimeout(function () {
            $("#" + currentColour).removeClass("pressed");
        }, 100);
    }
        
    // Click event listener
    $(".btn").on("click", function () {
        var userChosenColour = this.id;
        userClickedPattern.push(userChosenColour);
        playSound(userChosenColour);
        animatePress(userChosenColour);
    });
    

    Expectation vs Reality

    If both event handlers where created and executed at the same time you could fire both events with 1 click. But that’s not the case nor is it necessary in this case. This might be a little excessive of an answer but hopefully is helps you understand and prepare for future situations.

    Happy Dev-Ops!

    -Tekk

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search