Home > Software design >  Why animation don't complete its path when duration is decreased by JavaScript
Why animation don't complete its path when duration is decreased by JavaScript

Time:11-11

I have a animation whose duration decreases each time black jumps(using space) over the red, it works fine that subsequent jumps reduces the duration.

But after a certain decrease in time, say after reducing to 4s,3.9s,3.8s..., the animation don't start from the right-most end which is supposed to be. As it is decided path(110vw) in @keyframes animateVillan

Is there something I am doing wrong, first thought it is a glitch kind and decided to change duration only when red reaches less than 10 and tried below part

if (ourVillanFigXValue < 10) {
      ourVillanFig.style.animationDuration = ourVillanAnimeDuration - 0.1   "s";
    }

But this didn't solve the problem and path is not completely traced by the red

Sorry have to jump a little, 4 or 5 jumps only to see the error plz

let ourHeroFig = document.getElementById("ourHero");
let ourVillanFig = document.getElementById("obstacleBar");
let gameScoreDigits = document.getElementById("gameScoreDigits");
let valueXCoordinate = "";
let obstacleBarCrossed = true;

document.body.addEventListener('keydown', function(e) {
  let ourHeroFigXValue = parseInt(getComputedStyle(ourHeroFig).getPropertyValue('left'));
  let ourHeroFigYValue = parseInt(getComputedStyle(ourHeroFig).getPropertyValue('bottom'));

  if (e.code === "ArrowRight") {
    valueXCoordinate = ourHeroFigXValue   100;

  } else if (e.code === "KeyA" || e.code === "ArrowLeft") {
    if (ourHeroFigXValue > ourHeroFig.offsetWidth   90) {
      valueXCoordinate = ourHeroFigXValue - 100;
    } else {
      valueXCoordinate = 0;
    }
  } else if (e.code === "Space") {
    ourHeroFig.classList.add("animateHero");
    setTimeout(function() {
      ourHeroFig.classList.remove("animateHero");
    }, 700)
  }
  changePosition();

})

function changePosition() {
  ourHeroFig.style.left = valueXCoordinate   'px'
}

let delayInAnimeSub = ""
setInterval(
  function() {
    let ourHeroFigXValue = parseInt(getComputedStyle(ourHeroFig).getPropertyValue('left'));
    let ourHeroFigYValue = parseInt(getComputedStyle(ourHeroFig).getPropertyValue('bottom'));
    let ourVillanFigXValue = parseInt(getComputedStyle(ourVillanFig).getPropertyValue('left'));
    let ourVillanFigYValue = parseInt(getComputedStyle(ourVillanFig).getPropertyValue('bottom'));
    let gameOverValueX = Math.abs(ourVillanFigXValue - ourHeroFigXValue);
    let gameOverValueY = Math.abs(ourVillanFigYValue - ourHeroFigYValue);

    if (ourVillanFigXValue < 10) {
      ourVillanFig.style.animationDuration = ourVillanAnimeDuration - 0.3   "s";
    }
    if (gameOverValueX < ourVillanFig.offsetWidth && gameOverValueY < ourVillanFig.offsetHeight) {
      console.log("yes touched");
      ourVillanFig.classList.remove("animateVillan");
      obstacleBarCrossed = false;
    } else if (obstacleBarCrossed && gameOverValueX < ourVillanFig.offsetWidth) {
      ourVillanAnimeDuration = parseFloat(getComputedStyle(ourVillanFig).getPropertyValue('animation-duration'));
      console.log(ourVillanFigXValue < 0, ourVillanAnimeDuration)

      if (ourVillanAnimeDuration <= 2) {
        ourVillanAnimeDuration = 2
      }
    }
    // console.log(gameOverValueX,gameOverValueY)
  }, 10);
#ourHero {
  width: 20px;
  height: 180px;
  background-color: black;
  position: fixed;
  bottom: 0;
  left: 0;
  transition: 0.1s;
}

.animateHero {
  animation: animateHero 0.7s linear;
}

@keyframes animateHero {
  0% {
    bottom: 0;
  }
  50% {
    bottom: 350px;
  }
  100% {
    bottom: 0;
  }
}

#obstacleBar {
  width: 20px;
  height: 180px;
  background-color: red;
  position: fixed;
  bottom: 0;
  left: 50vw;
}

.animateVillan {
  animation: animateVillan 5s linear infinite;
}

@keyframes animateVillan {
  0% {
    left: 110vw;
  }
  100% {
    left: 0;
  }
}
<div id="ourHero"></div>
<div id="obstacleBar" class="animateVillan"></div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

Thanks for help in advance

CodePudding user response:

First make the red thing starts from far right so change left: 50vw; to something like left: 110vw;. Also, instead of the infinite animation, just remove the animateVillan class after the red gets out of screen then re-add it again. Can be done by using an animationend event handler:

ourVillanFig.addEventListener('animationend', () => {
  ourVillanFig.classList.remove('animateVillan')
  ourVillanFig.clientHeight // just to cause a reflow
  ourVillanFig.classList.add('animateVillan')
})

or maybe by checking its x position and see when it gets out.

Here is the result. It seems that it is working just fine without any glitches:

EDIT: To make the red stops where it is when it touches black, you can make the following css class:

.pauseVillan {
      animation-play-state: paused;
    }

and then when the red gets in touch just add the pauseVillan class to it:

ourVillanFig.classList.add('pauseVillan')

Here is the updated snippet:

let ourHeroFig = document.getElementById('ourHero')
let ourVillanFig = document.getElementById('obstacleBar')
let gameScoreDigits = document.getElementById('gameScoreDigits')
let valueXCoordinate = ''
let obstacleBarCrossed = true

document.body.addEventListener('keydown', function(e) {
  let ourHeroFigXValue = parseInt(
    getComputedStyle(ourHeroFig).getPropertyValue('left')
  )
  let ourHeroFigYValue = parseInt(
    getComputedStyle(ourHeroFig).getPropertyValue('bottom')
  )

  if (e.code === 'ArrowRight') {
    valueXCoordinate = ourHeroFigXValue   100
  } else if (e.code === 'KeyA' || e.code === 'ArrowLeft') {
    if (ourHeroFigXValue > ourHeroFig.offsetWidth   90) {
      valueXCoordinate = ourHeroFigXValue - 100
    } else {
      valueXCoordinate = 0
    }
  } else if (e.code === 'Space') {
    ourHeroFig.classList.add('animateHero')
    setTimeout(function() {
      ourHeroFig.classList.remove('animateHero')
    }, 700)
  }
  changePosition()
})

ourVillanFig.addEventListener('animationend', () => {
  ourVillanFig.classList.remove('animateVillan')
  ourVillanFig.clientHeight // just to cause a reflow
  ourVillanFig.classList.add('animateVillan')
})

function changePosition() {
  ourHeroFig.style.left = valueXCoordinate   'px'
}

let delayInAnimeSub = ''
setInterval(function() {
  let ourHeroFigXValue = parseInt(
    getComputedStyle(ourHeroFig).getPropertyValue('left')
  )
  let ourHeroFigYValue = parseInt(
    getComputedStyle(ourHeroFig).getPropertyValue('bottom')
  )
  let ourVillanFigXValue = parseInt(
    getComputedStyle(ourVillanFig).getPropertyValue('left')
  )
  let ourVillanFigYValue = parseInt(
    getComputedStyle(ourVillanFig).getPropertyValue('bottom')
  )
  let gameOverValueX = Math.abs(ourVillanFigXValue - ourHeroFigXValue)
  let gameOverValueY = Math.abs(ourVillanFigYValue - ourHeroFigYValue)

  if (ourVillanFigXValue < 10) {
    ourVillanFig.style.animationDuration =
      ourVillanAnimeDuration - 0.3   's'
  }
  if (
    gameOverValueX < ourVillanFig.offsetWidth &&
    gameOverValueY < ourVillanFig.offsetHeight
  ) {
    console.log('yes touched')
    ourVillanFig.classList.add('pauseVillan')
    obstacleBarCrossed = false
  } else if (
    obstacleBarCrossed &&
    gameOverValueX < ourVillanFig.offsetWidth
  ) {
    ourVillanAnimeDuration = parseFloat(
      getComputedStyle(ourVillanFig).getPropertyValue('animation-duration')
    )
    console.log(ourVillanFigXValue < 0, ourVillanAnimeDuration)

    if (ourVillanAnimeDuration <= 2) {
      ourVillanAnimeDuration = 2
    }
  }
  // console.log(gameOverValueX,gameOverValueY)
}, 10)
#ourHero {
  width: 20px;
  height: 180px;
  background-color: black;
  position: fixed;
  bottom: 0;
  left: 0;
  transition: 0.1s;
}

.animateHero {
  animation: animateHero 0.7s linear;
}

@keyframes animateHero {
  0% {
    bottom: 0;
  }
  50% {
    bottom: 350px;
  }
  100% {
    bottom: 0;
  }
}

#obstacleBar {
  width: 20px;
  height: 180px;
  background-color: red;
  position: fixed;
  bottom: 0;
  left: 110vw;
}

.animateVillan {
  animation: animateVillan 4s linear;
}

.pauseVillan {
  animation-play-state: paused;
}

@keyframes animateVillan {
  0% {
    left: 110vw;
  }
  100% {
    left: 0;
  }
}
<div id="ourHero"></div>
<div id="obstacleBar" class="animateVillan"></div>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related