You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Anime.js切换玩家时背景动画出现卡顿延迟问题求助

双人骰子游戏Anime.js背景动画卡顿问题

我在开发一款双人同屏骰子游戏时,使用Anime.js实现背景切换动画:根据当前活跃玩家(左侧或右侧),对一个宽度为50vw、z-index为负值的背景div执行位置(左右移动)和背景色切换动画。我将动画的play()和reverse()方法放在switchPlayer函数中,但两次玩家切换之间背景动画会出现明显卡顿,无法实现顺畅过渡的效果。

HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="style.css">
  <!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> -->
  <title>Dice Game</title>
</head>
<body>
  <div id="player-background"></div>
  <!-- This is whre the whole game is contained -->
  <div class="gameContainer"> 
    
    <!-- Player one content -->
    <div id="player1">
      <h2>PLAYER 1</h2>
      <span class="score" id="globalP1">0</span>
      <div class="current">
        <span class="cText">Current :</span>
        <span id="roundP1">0</span>
      </div>
    </div>
    
    <!-- Center content -->
    <div id="center">
      <button class="NewGame" id="new-game" type="button">NEW GAME</button>
      <img alt="Dice" id="img" src="./images/1.png">
      <button class="roll-dice" id="roll" type="button">ROLL DICE !</button>
      <button id="hold" type="button">HOLD</button>
    </div>

    <!-- Player two content -->
    <div id="player2">
      <h2>PLAYER 2</h2>
      <span class="score" id="globalP2">0</span>
      <div class="current">
        <span class="cText">Current :</span>
        <span id="roundP2">0</span>
      </div>
    </div>
  </div>

    <script src="./node_modules/animejs/lib/anime.min.js"></script>
    <script src="./script.js"></script>
</body>
</html>

CSS代码

@import url('https://fonts.googleapis.com/css2?family=Lato:wght@300;400&display=swap');

body {
  margin: 0px;
  overflow: hidden;
  font-family: 'Lato', sans-serif;
  /* background-image: url(images/GameBackground.png);
  background-size: cover;
  background-position: center; */
}

img {
  height: 300px;
  width: 300px;
  padding: 200px 0px 150px 0px;
}

button {
  background: none;
  border: 0;
  font-size: 50px;
}

.roll-dice {
  padding-bottom: 25px;
}



.gameContainer {
  display: flex;
  justify-content: space-around;
  align-items: center;
  align-content: center;
  height: 100vh;
  width: 100vw;
  z-index: 5;
}

#player-background {
  position: absolute;
  height: 100vh;
  width: 50vw;
  background: paleturquoise;
  z-index: -5;
}

#player1, #player2, #center {
  font-size: 50px;
  font-weight: 300;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}


.score {
  color: red;
  font-size: 100px;
  font-weight: 300;
  display: flex;
  margin-bottom: 250px;
}

.cText {
  font-size: 30px;
}

.current {
  display: flex;
  align-items: center;
  justify-content: space-evenly;
  background: rgb(226, 226, 187);
  height: 125px;
  width: 350px;
}

JS代码

//------------------------ Get element variables ---------------
let newGame = document.getElementById("new-game");
let roll = document.getElementById("roll");
let hold = document.getElementById("hold");
let img = document.getElementById("img");
let globalP1 = document.getElementById("globalP1");
let roundP1 = document.getElementById("roundP1");
let globalP2 = document.getElementById("globalP2");
let roundP2 = document.getElementById("roundP2");
let backgroundTarget = document.getElementById("player-background");
//----------------------- Game variables ---------------
let activePlayer = 1;

//----------------------------Anime JS---------------------

let background = anime({
  targets: backgroundTarget,
  translateX: "50vw",
  autoplay: false,
  backgroundColor: "#676790",
});

//------------------ Functions used later ---------------

// Switch the player display depending on the situation
function switchPlayer() {
  if (activePlayer == 1) {
    background.reverse();
    player1.style.opacity = "1";
    player2.style.opacity = "0.3";
  } else {
    background.play();
    player1.style.opacity = "0.3";
    player2.style.opacity = "1";
  }
}

let gameReset = () => {
  // rewrite everything to "0"
  roundP1.textContent = "0";
  globalP1.textContent = "0";
  roundP2.textContent = "0";
  globalP2.textContent = "0";
  // Force player one display
  activePlayer = 1;
  switchPlayer();
};

//--------------------- Main functions ----------------------

// Roll logic
let rollfunction = () => {
  // Generates a random number between 1 to 6
  let diceNumber = Math.floor(Math.random() * 6) + 1;
  // Generate a string with the img path, including a random number between then display the img
  let randomImg = "images/" + diceNumber + ".png";
  // Used to get the img element then set the src attribute to randomImg (= images/1.png or any other numbers)
  document.querySelector("img").setAttribute("src", randomImg);

  if (activePlayer == 1 && diceNumber > 1) {
    roll.textContent = "ROLL DICE !";
    // puts the number into the current score
    let totalCurrentP1 = roundP1.textContent;
    // I had to put a "+" to make the addition possible beacause rounsP2.textContent is a string, the + is here to convert a string into a number
    roundP1.textContent = +totalCurrentP1 + +diceNumber;
    switchPlayer();
  } else if (activePlayer == 1 && diceNumber == 1) {
    // Switch player if dice = 1
    roll.textContent = "NEXT PLAYER";
    roundP1.textContent = "0";
    activePlayer = activePlayer + 1;
    switchPlayer();
  } else if (activePlayer == 2 && diceNumber > 1) {
    // Put score into P2 section
    roll.textContent = "ROLL DICE !";
    let totalCurrentP2 = roundP2.textContent;
    roundP2.textContent = +totalCurrentP2 + +diceNumber;
  } else {
    // Switch to player 1 if player 2 get "1"
    roundP2.textContent = "0";
    roll.textContent = "NEXT PLAYER";
    activePlayer = activePlayer - 1;
  }
};

// Hold ogic
let holdFunction = () => {
  let totalGlobalP1 = globalP1.textContent;
  let totalGlobalP2 = globalP2.textContent;
  let numberRoundP1 = roundP1.textContent;
  let numberRoundP2 = roundP2.textContent;
  if (activePlayer == 1 && +totalGlobalP1 + +numberRoundP1 < 100) {
    globalP1.textContent = +totalGlobalP1 + +roundP1.textContent;
    roundP1.textContent = "0";
    activePlayer = 2;
    switchPlayer();
    // background.play();
  } else if (activePlayer == 1 && +totalGlobalP1 + +numberRoundP1 >= 100) {
    activePlayer = 1;
    alert("P1 t'as gagné mon pote !");
    gameReset();
    // background.reverse();
  } else if (activePlayer == 2 && +totalGlobalP2 + +numberRoundP2 < 100) {
    globalP2.textContent = +totalGlobalP2 + +roundP2.textContent;
    roundP2.textContent = "0";
    activePlayer = 1;
    switchPlayer();
    // background.reverse();
  } else if (activePlayer == 2 && +totalGlobalP2 + +numberRoundP2 >= 100) {
    activePlayer = 2;
    alert(
      "Le joueur 2 a gagné cette manche ! (De toute façon c'était mon préféré"
    );
    gameReset();
  }
};

//--------------------- Buttons ----------------------------
// Every buttons holding every functions
hold.addEventListener("click", () => {
  holdFunction();
});

roll.addEventListener("click", () => {
  rollfunction();
});

newGame.addEventListener("click", () => {
  gameReset();
});

已尝试的解决方法

  • 在Stack Overflow搜索同类问题
  • 深入研读Anime.js官方文档
  • 创建空白项目单独测试该动画逻辑,但问题依然存在

期望实现效果

背景div能根据活跃玩家顺畅地左右移动,清晰标识当前操作的玩家。

内容的提问来源于stack exchange,提问作者ill us

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 06:25:28