简体   繁体   中英

Changing the global scope variable inside of a function with click handlers

So I'm building a turn based game with javascript and jquery and I'm currently struggling with limiting player movement. So this is what I have:

let playerOneMoves = 0;
let playerTwoMoves = 0;

function movePlayerOne(){
    $(tile).click(function(){
        playerOneMoves += 1;
        if(playerOneMoves < 4){
            $(".active").append(playerOne);
        }else if(playerOneMoves == 4){
            alert("No more moves, players two turn!");            
            playerTwoMoves = 0;
            movePlayerTwo();

        }
    })
}
function movePlayerTwo(){
    $(tile).click(function(){
        playerTwoMoves += 1;
        if(playerTwoMoves < 4){
            $(".active").append(playerTwo);
        }else if(playerTwoMoves == 4){
            playerOneMoves = 0;
            alert("No more moves, players one turn!")
            movePlayerOne();

        }   
    })
}

So as player 2 finishes his move, and the next function (moveplayerone) is loaded, I only have 1 move with player 1. After a few more clicks, it starts appending both players to the same field. So my question is, why can't I reset the value of "let playerOneMoves = 0;" inside of a function? If you want to see the code more in-depth, you can check it on CodePen: https://codepen.io/ronydkid/pen/oyqxJY

Btw, I've checked all the other similar questions but they weren't helpful.

So we're going to semantically read your functions from top to bottom

movePlayerOne

  1. Assign a click handler

movePlayerTwo

  1. Assign a click handler

That doesn't seem like the intended functionality you're after! I'm guessing what you wanted was that on click, you need to check your moves, and then assign which player is the active player. This should be handled with a single click handler that has knowledge of which player's turn it is. To achieve this lets go ahead and make a DIFFERENT click handler called movePlayer and a new global called currentPlayer

let currentPlayer = playerOne;
let playerOneMoves = 0;
let playerTwoMoves = 0;
let active = $(".active"); // we don't want to crawl DOM every time unless needed,
// so unless you're destroying the ".active" DOM object every time, you should be fine here

function movePlayer(){
  let currentMoves = currentPlayer == playerOne
    ? ++playerOneMoves
    : ++playerTwoMoves;
  if ( currentMoves < 4 ){
    active.append(currentPlayer);
  } else { // basically if we get here we've reached 4 moves
    if (currentPlayer == playerOne) {
      currentPlayer = playerTwo;
      playerOneMoves = 0;
      alert("No more moves, players two's turn!");
    } else {
      currentPlayer = playerOne;
      playerTwoMoves = 0;
      alert("No more moves, players one turn!");
    }
  }
}

$(tile).click(movePlayer)

Now whenever you click on a tile only one function gets run, and this function handles moves for BOTH players and it doesn't register more click handlers


Some of the shortcuts used:

Ternary

if (condition) {
  console.log('true')
} else {
  console.log('false')
}

can be rewritten with a ternary as

console.log( condition ? 'true' : 'false' )

Increment

var i = 0;
console.log(i++) // 0
console.log(i) // 1
console.log(++i) // 2
console.log(i) // 2

Notes on other changes you can make

If you don't need the extra references to individual player moves variables, take a look at @geekley 's answer below. It's a little smaller and features hoisting of non evaluated variables, short circuiting the function in a conditional, and less variables.

Maybe this is what you mean?

let playerMoves = 0;
let currentPlayer = 1;

$(tile).click(movePlayer);
function movePlayer() {
    playerMoves += 1;
    if (playerMoves < 4) {
        $(".active").append(currentPlayer == 1 ? playerOne : playerTwo);
        return;
    }
    // if (playerMoves >= 4) {
        if (currentPlayer == 1) {
            alert("No more moves, player two's turn!");
            currentPlayer = 2;
        } else { // currentPlayer == 2
            alert("No more moves, player one's turn!");
            currentPlayer = 1;
        }
        playerMoves = 0;
    // }
}

The problem is not the let... the problem is your code structure:

let playerMoves = 0;
let player = 1;
$(tile).click(function() {
    if (playerMoves < 4) {
        $(".active").append(player == 1 ? playerOne : playerTwo);
        playerMoves += 1;
    }
    if (playerMoves == 4) {
        playerMoves = 0;
        player == 1 ? player = 2 : player = 1;
        alert("No more moves, " + player + "'s turn!");    
    }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM