【问题标题】:Rock Paper Scissors game loop石头剪刀布游戏循环
【发布时间】:2022-02-11 19:14:35
【问题描述】:

我正在制作一个石头、纸、剪刀游戏。 游戏应该以 3 种可能的模式运行。最好的 3 / 最好的 5 和无尽的游戏。

在我重置游戏以开始新游戏之前,我的代码运行良好。 由于我无法弄清楚的原因,每次我调用 game() 函数时,它都会播放我的游戏的多个实例。 (游戏结束后出现重置游戏按钮,需要重新选择游戏模式)

我已将整个项目添加到此 https://jsfiddle.net/vydkg3bz/,因为我无法确定问题出在哪里。

我相信,由于我添加了所有额外的日志记录,问题出在 game() 函数的某个地方,因为我试图用相同的结果替换它周围的大部分代码。

也许有人有时间查看我的代码并提示我应该查看的位置?

// global variables
var choicesObj = {
  Rock: "url('./img/stone.png')",
  Paper: "url('./img/paper.png')",
  Scissors: "url('./img/scissors.png')",
}
var choices = Object.keys(choicesObj);
var moveAI;
var movePlayer;
var winnerRound;
var winnerGame;
var roundCount = 0; 

// actual game
function game(requiredWins) {
  console.log("game");
  enabler()

  var inputs = document.querySelectorAll(".inputButton");
  console.log(inputs);
  for (var i = 0; i < inputs.length; i++) {
    inputs[i].addEventListener("click", function() {
    movePlayer = this.id
    handleClick(movePlayer)
    });    
  }

  // checking choice, display choice IMG, call compareChoices function 
  function handleClick(buttonID) {
    console.log("handleClick");
    moveAIfunc()
    movePlayer = buttonID;
    console.log('movePlayer: ' + movePlayer);
    console.log('moveAI: ' + moveAI);
    document.getElementById("mainImgPlayer").style.backgroundImage = choicesObj[movePlayer];
    document.getElementById("mainImgAI").style.backgroundImage = choicesObj[moveAI];
    compareChoices(moveAI,movePlayer);
    console.log("requiredWins", requiredWins);
    gameEnd();
    displays();
  }

  // AI control
  function moveAIfunc() {
    moveAI = choices[Math.floor(Math.random() * choices.length)]
  }

  // compare choices
  function compareChoices(a, b) {
    console.log("compareChoices");
    a = choices.indexOf(a);
    b = choices.indexOf(b);
    console.log("requiredWins", requiredWins);
    roundCount++;
    if (a == b) {
      winnerNone()
      return;
    }
    if (a == choices.length - 1 && b == 0) {
      winnerPlayer()
      return;
    }
    if (b == choices.length - 1 && a == 0) {
      winnerAI()
      return;
    }
    if (a > b) {
      winnerAI()
      return;
    }
    else {
      winnerPlayer()
      return;
    }
  }

  // game end
  function gameEnd() {
    console.log("gameEnd");
    console.log(requiredWins,winsPlayer,winsAI);
    if (winsPlayer == requiredWins) {
      console.log(requiredWins,winsPlayer,winsAI);
      winnerGame = "Player";
      disabler()
      createEndButton()
      return;
    }
    if (winsAI == requiredWins) {
      console.log(requiredWins,winsPlayer,winsAI);
      winnerGame = "AI";
      disabler()
      createEndButton()
      return;
    }
  }
}```



【问题讨论】:

    标签: javascript html


    【解决方案1】:

    您的代码似乎相当复杂。获胜/所需获胜等的状态未在其中充分保存。为了玩你添加事件监听器每场比赛(点击),这是非常低效的恕我直言。

    我创建了一个用于处理游戏的模型(minimal reproducable example),使用data attributes 来记住游戏的状态,并使用event delegation 来进行处理。也许对你有用。

    不相关,但这里是 RPS 上的 my take

    document.addEventListener(`click`, handle);
    
    function handle(evt) {
      if (evt.target.id === `play`) {
        return play(evt.target);
      }
      
      if (evt.target.name === `nWins`) {
        return reset(evt.target);
      }
    }
    
    function reset(radio) {
        const value = radio === `none` 
          ? Number.MAX_SAFE_INTEGER : +radio.value;
        const bttn = document.querySelector(`#play`);
        const result = document.querySelector(`#result`);
        result.textContent = `(Re)start initiated, click [Play]`;
        result.dataset.wins = bttn.dataset.wins = 0;
        bttn.dataset.plays = 0;
        return bttn.dataset.winsrequired = value;
    }
    
    function play(bttn) {
        if (+bttn.dataset.winsrequired < 1) {
          return document.querySelector(`#result`)
            .textContent = `Select best of to start playing ...`;
        }   
        
        const result = document.querySelector(`#result`);
        bttn.dataset.plays = +bttn.dataset.plays + 1;
        const won = Math.floor(Math.random() * 2);
        const wins = +result.dataset.wins + won;
        result.textContent = `${won ? `You win` : `You loose`} (plays: ${
          bttn.dataset.plays}, wins ${wins})`;
        result.dataset.wins = wins;
        
        if (+bttn.dataset.plays === +bttn.dataset.winsrequired) {
          result.textContent = `You won ${wins} of ${
            bttn.dataset.winsrequired} games. Choose 'Best of' 
              to start another game`;
          bttn.dataset.plays = bttn.dataset.winsrequired = 0;
          result.dataset.wins = 0;
          document.querySelectorAll(`[name="nWins"]`)
            .forEach(r => r.checked = false);
        }
    }
    Best of
    <input type="radio" name="nWins" value="3"> 3
    <input type="radio" name="nWins" value="5"> 5
    <input type="radio" name="nWins" value="none"> indefinite
    
    <button id="play" data-winsrequired="0" data-plays="0" >Play</button>
    
    <p id="result" data-wins="0"></p>

    【讨论】:

    • 您好,感谢您的回答和有用的链接。我仍然是 JS 的血腥初学者,我很感激每一个帮助我发展良好实践的好资源。你也是对的,eventListeners 处于一个非常糟糕的位置,最终对不需要的行为负责。
    • 不客气。此外,我建议将javascript.info 作为通用来源;)