skip to Main Content

I am trying to make a very basic RPG game where when you attack, the exp bar will decrease by 20px in css width.
Now that I have done it and everything seems to be working well, but then I noticed a bug when I clicked the attack button faster. The exp value is not decreasing by 20px at some point. It might just decrease by 10px or maybe even 3px. I am not sure if my math implementation is wrong or it’s a bug that I am yet to figure out.

Here is my javascript code :

const atkBtn = document.getElementById("atk-btn");
let expBar = document.getElementById("bar");

function attack(){
    var barWidth = expBar.offsetWidth;
    var atkVal = 20;
    newBar = (barWidth - atkVal)+"px";
    expBar.style.maxWidth = newBar;
    console.log(newBar)
}

atkBtn.addEventListener("click", attack);

Here is my css code :

p{
    margin: 0px;
    display: inline-block;
}

#bar{
    width: 200px;
    height: 15px;
    margin-top: 10px;
    background-color: red;
    display: inline-block;
    max-width: 200px;
    overflow-x: hidden;
    transition: all 0.4s;
}

Here is when I clicked the btn slowly:
enter image description here

Here is when I clicked the btn faster(to simulate gaming condition):
enter image description here

Should you have any answer please feel free to reply. Thanks

3

Answers


  1. You are setting the maxWidth instead of width, so the attack function should look like this:

    function attack(){
      var barWidth = expBar.offsetWidth;
      var atkVal = 20;
      newBar = (barWidth - atkVal)+"px";
      expBar.style.width = newBar;
      console.log(newBar)
    }
    
    Login or Signup to reply.
  2. This:

    transition: all 0.4s;
    

    If two clicks are faster than 0.4s apart, the style is still changing over time and the calculation for the latter click will be based on wherever you are in the transition when clicking. Removing the transition entirely fixes the issue.

    To keep the transition as an animation, track the ongoing width separately. Basically, don’t use the styling to store data. Instead, store the data separately and build the styling from it. For example:

    const atkBtn = document.getElementById("atk-btn");
    let expBar = document.getElementById("bar");
    let barWidth = 200;
    
    function attack(){
        var atkVal = 20;
        barWidth -= atkVal;
        newBar = barWidth+"px";
        expBar.style.maxWidth = newBar;
        console.log(newBar)
    }
    
    atkBtn.addEventListener("click", attack);
    p{
        margin: 0px;
        display: inline-block;
    }
    
    #bar{
        width: 200px;
        height: 15px;
        margin-top: 10px;
        background-color: red;
        display: inline-block;
        max-width: 200px;
        overflow-x: hidden;
        transition: all 0.4s;
    }
    <button id="atk-btn">Attack</button>
    <div id="bar"></div>
    Login or Signup to reply.
  3. There is a transition effect on the bar:

    #bar{
        ...
        transition: all 0.4s;
    }
    

    and since you are using the current width of the bar, if you click before the transition has ended, you get a value above the expected one, since the bar has not yet decreased fully.

    In general, I would suggest separating the data from the layout, i.e. store the HP in a variable and derive bar length from it, instead of using the bar length directly. Something like:

    var hp = 200
    
    function updateBarWidth(){
      expBar.style.maxWidth = hp + 'px';
    }
    
    updateBarWidth()
    
    function attack(){
        var atkVal = 20;
        hp - atkVal
        updateBarWidth()
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search