Javascript 带有嵌套If的If语句未按预期工作

Javascript 带有嵌套If的If语句未按预期工作,javascript,Javascript,我用HTML画布制作了一个游戏,用户可以在其中控制角色的移动。我希望下面的外部if语句首先重置角色的x和y位置,然后如果用户没有生命,则调用一个打开模式并禁用keydown事件的函数。相反,函数被调用,打开模式,棋盘上的移动停止(移动的敌人角色停止移动);但是,x和y位置没有设置为外部if语句中指定的位置,我希望在嵌套的if语句中的任何位置之前出现。如果语句不删除事件侦听器,它将按预期工作(设置x和y值,然后打开模式) if(player.xthis.x&&player.ythis.y){ pl

我用HTML画布制作了一个游戏,用户可以在其中控制角色的移动。我希望下面的外部
if
语句首先重置角色的x和y位置,然后如果用户没有生命,则调用一个打开模式并禁用keydown事件的函数。相反,函数被调用,打开模式,棋盘上的移动停止(移动的敌人角色停止移动);但是,x和y位置没有设置为外部if语句中指定的位置,我希望在嵌套的
if
语句中的任何位置之前出现。如果语句不删除事件侦听器,它将按预期工作(设置x和y值,然后打开模式)

if(player.xthis.x&&player.ythis.y){
player.x=200;
player.y=400;
生命--;
sidebarlifes.innerHTML=生活;
modalScore.innerHTML=分数;
如果(生命===0){
//调用函数,该函数添加将modal设置为display:block的类
showModal();
//这将防止播放器x和y值更新(尽管出现模式)
文档。删除EventListener(“键控”);
}
}
游戏链接:

以下是我的完整JS代码:

"use strict"; // Enables strict mode to catch common bloopers

// TODO: Disable player movement when modal opened? Also, set 3 tries before modal opened (change to game over). Restart button.

const playAgainButton = document.querySelector('.play-again');
const restartButton = document.querySelector('.restart');

// Calls playAgain() function when user clicks play again button in modal
playAgainButton.addEventListener('click', playAgain);

// Calls playAgain() function when user clicks reset icon in sidebar
restartButton.addEventListener('click', playAgain);

// Starts lives at 3
let lives = 3;

let sidebarLives = document.querySelector('.lives-left');
sidebarLives.innerHTML = lives;

// Sets an initial player score of 0.
let score = 0;
// Sets score shown in sidebar
// document.getElementsByClassName('score')[0].innerHTML = score;
let sidebarScore = document.querySelector('.score');
sidebarScore.innerHTML = score;

let modalScore = document.querySelector('.modal-score');
modalScore.innerHTML = score;

// These 2 lines were used to set star rating in modal
// let starRating = document.querySelector('.stars').innerHTML;
// document.getElementsByClassName('star-rating')[0].innerHTML = starRating;

// Called when user clicks restart button in sidebar or play again button in modal. Sets modal to display: none, resets lives and score
function playAgain() {
  // Hides modal if present (if opened by game ending)
  modal.classList.remove('modal-visible');
  lives = 3;
  sidebarLives.innerHTML = lives;
  score = 0;
  sidebarScore.innerHTML = score;
}

// Calls playAgain() function (hides modal and restarts game) with user clicks "play again" button in modal
// TODO: remove? just one event listener for both buttons?
// modalPlayAgainButton.addEventListener('click', playAgain);

// Note: In a constructor function "this" does not have a value. It is a substitute for the new object. The value of this will become the new object when a new object is created

// Note commas not used to separate methods and properties in a class
class Player {
  // Constructor function, a special function just for initializing new objects, will automatically run when a new object is constructed (with keyword "new") from this class. Contains data needed to create it
  constructor(x, y, speed) {
    this.sprite = 'images/char-boy.png';
    this.x = x;
    this.y = y;
    this.speed = speed;
  }

  // Methods that all objects created from class will inherit. Would exist on prototype in pre-class way of writing it, but effect is the same (the following methods still exist on Player prototype [for example would be Player.prototype.update = function(dt)...])

  // When player reaches water, moves player back to starting position, and increase score by 1
  update(dt) {
    if (this.y === 25) {
      this.x = 200;
      this.y = 400;
      score++;
      sidebarScore.innerHTML = score;
    }
  }

  // Draws player on screen
  render() {
    ctx.drawImage(Resources.get(this.sprite), this.x, this.y)
  }

  // Connects keyboard input to player movement. If statements prevent player movement off screen
  handleInput(allowedKeys) {

    if (allowedKeys === 'down' && this.y < 425) {
      this.y += 25;
    }

        if (allowedKeys === 'up') {
            this.y -= 25;
        }

        if (allowedKeys === 'left' && this.x > 0) {
            this.x -= 25;
        }

        if (allowedKeys === 'right' && this.x < 400) {
            this.x += 25;
        }
  }
}

class Enemy {
// Sets enemy's initial location
  constructor(x, y, speed) {
    this.x = x;
    this.y = y;
    // Sets speed of enemy
    this.speed = speed;
    // The image/sprite for our enemies
    this.sprite = 'images/enemy-bug.png';
  }

  update(dt) {
    // Multiplies enemy's movement by time delta to ensure game runs at same speed for all computers
    this.x += this.speed * dt;
    // Once enemy finished moving across screen, moves it back so it can cross screen again and randomizes its speed
    if (this.x > 500) {
      this.x = -75;
      // Math.random() function returns random number between 0 (inclusive) and 1 (exclusive). Math.floor() returns the largest integer less than or equal to a given number
      this.speed = 70 + Math.floor(Math.random() * 450);
    }

    // When collission occurs, subtracts a life, updates lives displayed in sidebar and updates score that will be displayed in modal if no lives remaining
    if (player.x < this.x + 70 && player.x + 17 > this.x && player.y < this.y + 45 && 30 + player.y > this.y) {
        player.x = 200;
        player.y = 400;
      lives--;
      sidebarLives.innerHTML = lives;
      modalScore.innerHTML = score;
      if (lives === 0) {
        // Calls function that adds class that sets modal to display: block
        showModal();
        // This prevents player x and y values from updating (though modal appears)
        document.removeEventListener('keydown');
      }
    }
  }

  // Draws enemy on the screen
  render() {
    ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
  }
};


// ENEMY/PLAYER OBJECT INSTANTIATION

let enemyPosition = [60, 140, 220];

let allEnemies = [];

let player = new Player(200, 400, 50);

enemyPosition.forEach(function(posY) {
  let enemy = new Enemy(0, posY, 70 + Math.floor(Math.random() * 450));
  allEnemies.push(enemy);
});

// Modal

const modal = document.getElementById('myModal');
const closeIcon = document.querySelector('.close');

// When called, adds class that sets modal to display: block when player reaches water
function showModal() {
  modal.classList.add('modal-visible');
}

// Closes modal (adding class that sets it back to display: none) upon user's clicking its close icon
closeIcon.addEventListener('click', function() {
  modal.classList.remove('modal-visible');
});

// Closes modal and restarts game when key is pressed down (note: keydown used instead of keypress because keypress only works for keys that produce a character value)
document.addEventListener('keydown', function(e) {
  let keyCode = e.keyCode;
  if (keyCode === 27) {
    modal.classList.remove('modal-visible');
    playAgain()
  }
});

// Listens for keydown event (fired when a key is pressed down [regardless of whether it produces a character, unlike keypress]) and sends the keys to Player.handleInput() method
document.addEventListener('keydown', function(e) {
  let allowedKeys = {
    37: 'left',
    38: 'up',
    39: 'right',
    40: 'down'
  };
  // Not sure why "player" needs to be lowercase, given the class name is uppercase
  player.handleInput(allowedKeys[e.keyCode]);
});
“严格使用”//启用严格模式以捕获常见blooper
//TODO:模式打开时禁用播放器移动?另外,在模式打开之前设置3次尝试(更改为游戏结束)。重启按钮。
const playAgainButton=document.querySelector('.play-reach');
const restartButton=document.querySelector('.restart');
//当用户在模式中单击“再次播放”按钮时,调用playreach()函数
playAgainButton.addEventListener(“单击”,再次播放);
//当用户单击侧边栏中的重置图标时,调用playreach()函数
restartButton.addEventListener('单击',再次播放);
//3点开始生活
让生命=3;
let sidebarlifes=document.querySelector('.lifes left');
sidebarlifes.innerHTML=生活;
//将玩家的初始分数设置为0。
分数=0;
//设置边栏中显示的分数
//document.getElementsByClassName('score')[0].innerHTML=score;
让sidebarScore=document.querySelector('.score');
sidebarScore.innerHTML=分数;
让modalScore=document.querySelector('.modal score');
modalScore.innerHTML=分数;
//这两条线用于在modal中设置星级
//让starting=document.querySelector('.stars').innerHTML;
//document.getElementsByClassName('star-rating')[0].innerHTML=starting;
//当用户单击侧栏中的“重新启动”按钮或“模式”中的“再次播放”按钮时调用。设置要显示的模式:无,重置寿命和分数
函数playreach(){
//隐藏模式(如果在游戏结束时打开)
modal.classList.remove('modal-visible');
寿命=3;
sidebarlifes.innerHTML=生活;
得分=0;
sidebarScore.innerHTML=分数;
}
//调用PlayReach()函数(隐藏模式并重新启动游戏),用户单击模式中的“再次播放”按钮
//TODO:删除?两个按钮都只有一个事件侦听器?
//modalPlayAgainButton.addEventListener(“单击”,再次播放);
//注意:在构造函数中,“this”没有值。它是新对象的替代品。创建新对象时,该值将成为新对象
//注意:逗号不用于分隔类中的方法和属性
职业选手{
//构造函数是一个专门用于初始化新对象的特殊函数,当从此类构造新对象(使用关键字“new”)时,它将自动运行。包含创建新对象所需的数据
构造器(x、y、速度){
this.sprite='images/char-boy.png';
这个.x=x;
这个。y=y;
速度=速度;
}
//从类创建的所有对象将继承的方法。将以类前编写的方式存在于原型上,但效果相同(以下方法仍存在于播放器原型上[例如将是Player.prototype.update=function(dt)…])
//当玩家到达水面时,将玩家移回起始位置,并增加1分
更新(dt){
if(this.y==25){
这个.x=200;
这个y=400;
分数++;
sidebarScore.innerHTML=分数;
}
}
//在屏幕上吸引玩家
render(){
drawImage(Resources.get(this.sprite)、this.x、this.y)
}
//将键盘输入连接到播放机移动。If语句阻止播放机在屏幕外移动
handleInput(允许键){
if(allowedKeys==='down'&&this.y<425){
这个.y+=25;
}
如果(allowedKeys==='up'){
这个.y-=25;
}
if(allowedKeys==='left'&&this.x>0){
这个.x-=25;
}
if(allowedKeys==='right'&&this.x<400){
这个.x+=25;
}
}
}
阶级敌人{
//设定敌人的初始位置
构造器(x、y、速度){
这个.x=x;
这个。y=y;
//设定敌人的速度
速度=速度;
//我们敌人的形象/精灵
this.sprite='images/敌方bug.png';
}
更新(dt){
//将敌人的移动乘以时间增量,以确保所有计算机以相同的速度运行游戏
这个.x+=这个.speed*dt;
//一旦敌人在屏幕上移动完毕,将其向后移动,以便再次穿过屏幕并随机调整其速度
如果(此.x>500){
这个.x=-75;
//函数的作用是:返回介于0(包含)和1(排除)之间的随机数。函数的作用是:返回小于或等于给定数字的最大整数
this.speed=70+Math.floor(Math.random()*450);
}
//当碰撞发生时,减去一个寿命,更新侧栏中显示的寿命,并更新分数,如果没有剩余的寿命,该分数将显示在模式中
如果(player.xthis.x&&player.ythis.y){
player.x=200;
player.y=400;
生命--;
sidebarlifes.innerHTML=生活;
modalScore.innerHTML=分数;
如果(生命===0){
"use strict"; // Enables strict mode to catch common bloopers

// TODO: Disable player movement when modal opened? Also, set 3 tries before modal opened (change to game over). Restart button.

const playAgainButton = document.querySelector('.play-again');
const restartButton = document.querySelector('.restart');

// Calls playAgain() function when user clicks play again button in modal
playAgainButton.addEventListener('click', playAgain);

// Calls playAgain() function when user clicks reset icon in sidebar
restartButton.addEventListener('click', playAgain);

// Starts lives at 3
let lives = 3;

let sidebarLives = document.querySelector('.lives-left');
sidebarLives.innerHTML = lives;

// Sets an initial player score of 0.
let score = 0;
// Sets score shown in sidebar
// document.getElementsByClassName('score')[0].innerHTML = score;
let sidebarScore = document.querySelector('.score');
sidebarScore.innerHTML = score;

let modalScore = document.querySelector('.modal-score');
modalScore.innerHTML = score;

// These 2 lines were used to set star rating in modal
// let starRating = document.querySelector('.stars').innerHTML;
// document.getElementsByClassName('star-rating')[0].innerHTML = starRating;

// Called when user clicks restart button in sidebar or play again button in modal. Sets modal to display: none, resets lives and score
function playAgain() {
  // Hides modal if present (if opened by game ending)
  modal.classList.remove('modal-visible');
  lives = 3;
  sidebarLives.innerHTML = lives;
  score = 0;
  sidebarScore.innerHTML = score;
}

// Calls playAgain() function (hides modal and restarts game) with user clicks "play again" button in modal
// TODO: remove? just one event listener for both buttons?
// modalPlayAgainButton.addEventListener('click', playAgain);

// Note: In a constructor function "this" does not have a value. It is a substitute for the new object. The value of this will become the new object when a new object is created

// Note commas not used to separate methods and properties in a class
class Player {
  // Constructor function, a special function just for initializing new objects, will automatically run when a new object is constructed (with keyword "new") from this class. Contains data needed to create it
  constructor(x, y, speed) {
    this.sprite = 'images/char-boy.png';
    this.x = x;
    this.y = y;
    this.speed = speed;
  }

  // Methods that all objects created from class will inherit. Would exist on prototype in pre-class way of writing it, but effect is the same (the following methods still exist on Player prototype [for example would be Player.prototype.update = function(dt)...])

  // When player reaches water, moves player back to starting position, and increase score by 1
  update(dt) {
    if (this.y === 25) {
      this.x = 200;
      this.y = 400;
      score++;
      sidebarScore.innerHTML = score;
    }
  }

  // Draws player on screen
  render() {
    ctx.drawImage(Resources.get(this.sprite), this.x, this.y)
  }

  // Connects keyboard input to player movement. If statements prevent player movement off screen
  handleInput(allowedKeys) {

    if (allowedKeys === 'down' && this.y < 425) {
      this.y += 25;
    }

        if (allowedKeys === 'up') {
            this.y -= 25;
        }

        if (allowedKeys === 'left' && this.x > 0) {
            this.x -= 25;
        }

        if (allowedKeys === 'right' && this.x < 400) {
            this.x += 25;
        }
  }
}

class Enemy {
// Sets enemy's initial location
  constructor(x, y, speed) {
    this.x = x;
    this.y = y;
    // Sets speed of enemy
    this.speed = speed;
    // The image/sprite for our enemies
    this.sprite = 'images/enemy-bug.png';
  }

  update(dt) {
    // Multiplies enemy's movement by time delta to ensure game runs at same speed for all computers
    this.x += this.speed * dt;
    // Once enemy finished moving across screen, moves it back so it can cross screen again and randomizes its speed
    if (this.x > 500) {
      this.x = -75;
      // Math.random() function returns random number between 0 (inclusive) and 1 (exclusive). Math.floor() returns the largest integer less than or equal to a given number
      this.speed = 70 + Math.floor(Math.random() * 450);
    }

    // When collission occurs, subtracts a life, updates lives displayed in sidebar and updates score that will be displayed in modal if no lives remaining
    if (player.x < this.x + 70 && player.x + 17 > this.x && player.y < this.y + 45 && 30 + player.y > this.y) {
        player.x = 200;
        player.y = 400;
      lives--;
      sidebarLives.innerHTML = lives;
      modalScore.innerHTML = score;
      if (lives === 0) {
        // Calls function that adds class that sets modal to display: block
        showModal();
        // This prevents player x and y values from updating (though modal appears)
        document.removeEventListener('keydown');
      }
    }
  }

  // Draws enemy on the screen
  render() {
    ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
  }
};


// ENEMY/PLAYER OBJECT INSTANTIATION

let enemyPosition = [60, 140, 220];

let allEnemies = [];

let player = new Player(200, 400, 50);

enemyPosition.forEach(function(posY) {
  let enemy = new Enemy(0, posY, 70 + Math.floor(Math.random() * 450));
  allEnemies.push(enemy);
});

// Modal

const modal = document.getElementById('myModal');
const closeIcon = document.querySelector('.close');

// When called, adds class that sets modal to display: block when player reaches water
function showModal() {
  modal.classList.add('modal-visible');
}

// Closes modal (adding class that sets it back to display: none) upon user's clicking its close icon
closeIcon.addEventListener('click', function() {
  modal.classList.remove('modal-visible');
});

// Closes modal and restarts game when key is pressed down (note: keydown used instead of keypress because keypress only works for keys that produce a character value)
document.addEventListener('keydown', function(e) {
  let keyCode = e.keyCode;
  if (keyCode === 27) {
    modal.classList.remove('modal-visible');
    playAgain()
  }
});

// Listens for keydown event (fired when a key is pressed down [regardless of whether it produces a character, unlike keypress]) and sends the keys to Player.handleInput() method
document.addEventListener('keydown', function(e) {
  let allowedKeys = {
    37: 'left',
    38: 'up',
    39: 'right',
    40: 'down'
  };
  // Not sure why "player" needs to be lowercase, given the class name is uppercase
  player.handleInput(allowedKeys[e.keyCode]);
});