为什么我的未完成的javascript游戏在第三次死亡后崩溃?

问题描述 投票:1回答:1

// Commented because does not work in Sandbox
// window.localStorage; //Ignore this line

// Where all my variables have been assigned

var c = document.getElementById("GameScreen");
var ctx = c.getContext("2d");
var charY = 220;
const gravity = 10;
var score = 0;
var time = 0;
var speed = 5;
var cloneID = 0;
var clonePos = [600];
var clonePoints = [0];
var animationBounce = 0;
var jump = 10;
var charDead = 0;
var dataCharY = [];
var dataDisObst = [];
var disObst = 1000;
var lowestLoopDis;
var jumpFactor = 0;
var disDeath;
var AIgames = 1;
var bestScoreAI = 0;

ctx.translate(c.width / 2, c.height / 2);

// Was going to use this for background trees but haven't done it yet

new obj(50, 50, 30, 30);

// Runs most functions

function runAll() {
  if (charDead == 0) {
    clearAll(); //This function runs most of the code
    updateChar();
    createGround();
    updateObj();
    groundDetect();
    updateScore();
    hitDetect();
    addData();
    testBetterAI();
    getDisObst();
    jumpAI();
    removeUnusedObst();
  }
}

// Was going to use this for trees but haven't yet

function obj(x, y, width, height) {
  this.width = width;
  this.height = height;
  this.x = x;
  this.y = y;

  ctx.beginPath();

  ctx = c.getContext("2d");
  ctx.fillStyle = "brown";
  ctx.fillRect(this.x, this.y, this.width, this.height);
  ctx.fillStyle = "green";
  ctx.arc(-293, 150, 50, 0, 2 * Math.PI);
  ctx.fill();
  ctx.stroke();

  this.cloneID = cloneID;
}

new obj(-293, 212, 0, 2 * Math.PI);

// Creates the floor (IKR)

function createGround() {
  ctx.fillStyle = "green";
  ctx.fillRect(-635, 250, c.width, 50);
}

// Creates the character every milisecond (or 10, I can't remember)

function updateChar() {
  ctx.fillStyle = "blue";
  ctx.fillRect(-300, charY - animationBounce, 15, 30);
  ctx.fillStyle = "pink";
  ctx.beginPath();
  ctx.arc(-293, charY - animationBounce - 15, 15, 0, 2 * Math.PI);
  ctx.fill();
  ctx.stroke();
}

// Removes everything in order to be redrawn in new position

function clearAll() {
  ctx.clearRect(-700, -700, 2000, 2000);
}

// Redraws every square / object

function updateObj() {
  for (var i = 0; i != clonePos.length; i++) {
    ctx.fillStyle = "green";
    ctx.fillRect(clonePos[i], 220, 30, 30);
  }
}

// Creates new square (I also decided to rename them half way through with obstacle instead of object)

function createObst() {
  clonePos.push(600);
  cloneID++;
}

// Changes the squares / obstacles position relative to the movement

function moveObst() {
  for (var ii = 0; ii != clonePos.length; ii++) {
    clonePos[ii] -= speed;
  }
}

// Tests to see if the character is on the ground

function groundDetect() {
  if (charY > 220) {
    charY = 220;
  }
}

// Makes gravity actually work

function charGravity() {
  if (charY < 220) {
    charY += gravity;
  }
}

// Updates the score counter text

function updateScore() {
  document.getElementById("scoreText").innerHTML = score;
}

// Gives the character a little bounce when moving

function charBounce() {
  setTimeout(function() {
    animationBounce++;
  }, 100);
  setTimeout(function() {
    animationBounce++;
  }, 200);
  setTimeout(function() {
    animationBounce++;
  }, 300);
  setTimeout(function() {
    animationBounce--;
  }, 400);
  setTimeout(function() {
    animationBounce--;
  }, 500);
  setTimeout(function() {
    animationBounce--;
  }, 600);
}

// Makes the character jump

function charJump() {
  if (charY == 220) {
    jump = 4;

    setTimeout(function() {
      charY -= jump;
    }, 20);
    jump = 8;
    setTimeout(function() {
      charY -= jump;
    }, 40);
    jump = 12;
    setTimeout(function() {
      charY -= jump;
    }, 60);
    jump = 16;
    setTimeout(function() {
      charY -= jump;
    }, 80);
    setTimeout(function() {
      charY -= jump;
    }, 100);
    setTimeout(function() {
      charY -= jump;
    }, 120);
  }
}

// Detects when the character has a hit a square

function hitDetect() {
  for (var iB = 0; iB != clonePos.length; iB++) {
    if (clonePos[iB] > -320 && clonePos[iB] < -280 && charY > 200) {
      charDied();
    }
  }
}

// Runs when character dies

function charDied() {
  disDeath = disObst;
  charDead = 1;

  charRevive();

  testBetterAI();

  decideAdjustments();
}

// Adds score very interval

function addingScore() {
  if (charDead == 0) {
    score += 100;
  }
}

// Adds to an array that I will use later

function addData() {
  dataCharY.push(charY);
  dataDisObst.push(disObst);
}

// Test to see if one of my AI's (which hasn't been made yet) scores is better than the previous best

function testBetterAI() {
  // Commented because does not work in Sandbox
  // if (score > localStorage.getItem("bestScore")) {
  // }
}

// Calculates the distance to the nearest square / obstacle

function getDisObst() {
  lowestLoopDis = 1000;

  for (var iiA = 0; iiA != clonePos.length; iiA++) {
    if (clonePos[iiA] > -320) {
      if (clonePos[iiA] > 0) {
        if (Math.abs(clonePos[iiA]) < lowestLoopDis) {
          lowestLoopDis = Math.abs(clonePos[iiA]);
        }
      } else {
        if (Math.abs(clonePos[iiA]) < lowestLoopDis) {
          lowestLoopDis = Math.abs(clonePos[iiA]);
        }
      }
    }
  }

  if (lowestLoopDis < disObst) {
    disObst = lowestLoopDis;
  }
}

// Increments the speed of the obstacles / squares and the character

function addSpeed() {
  if (speed < 25) {
    speed++;
  }
}

// Restarts the game

function charRevive() {
  clonePos = [600];
  charDead = 0;
  score = 0;
  time = 0;
  speed = 5;
  AIgames++;
}

// I accidently did this twice, whoops

function testBetterAI() {
  if (score > bestScoreAI) {
    bestScoreAI = score;
  }
}

// Makes the unfinished AI jump when it wants to

function jumpAI() {
  if (disObst <= disDeath + jumpFactor) {
    charJump();
  }
}

// What changes need to be made in order to improve the AI

function decideAdjustments() {
  jumpFactor += Math.floor(Math.random() * 10) - 5;

  if (jumpFactor < 0) {
    jumpFactor = 0;
  }
}

// Removing blocks that are off the screen

function removeUnusedObst() {
  if (clonePos[0] < -650) {
    clonePos.shift();
  }
}

// Intervals here

setInterval(function() {
  time++;
}, 1000);
setInterval(function() {
  runAll();
}, 10);
setInterval(function() {
  moveObst();
}, 50);
setInterval(function() {
  charGravity();
}, 25);
setInterval(function() {
  createObst();
}, 3000);
setInterval(function() {
  charBounce();
}, 650);
setInterval(function() {
  addingScore();
}, 3500);
setInterval(function() {
  addSpeed();
}, 25000);
#GameScreen {
  background-color: CornflowerBlue;
}

#scoreText {
  text-align: center;
  font-size: 35px;
}
<div id="scoreText"></div>
<canvas id="GameScreen" width="1270px" height="550px"></canvas>

Blex给作者的注释:我编辑了您的问题,以使您的代码在Stack Overflow上可以运行。在此过程中,我必须使用localStorage注释两行,因为该行被阻止,将引发错误。由于尚未使用,因此不重要。但是请确保之后再取消注释。在第一行,并在testBetterAI功能中。

javascript
1个回答
0
投票

会发生什么

hitDetect功能中:

function hitDetect() {
  for (var iB = 0; iB != clonePos.length; iB++) {
    if (clonePos[iB] > -320 && clonePos[iB] < -280 && charY > 200) {
      charDied();
    }
  }
}

您在clonePos数组上循环,直到iB等于该数组的长度。如果满足条件(冲突),则执行charDied,然后执行charRevive

function charRevive() {
  clonePos = [600];
  // ...
}

同时,hitDetect循环继续。在某一时刻(似乎是在开始增加速度时]iB现在高于1,这是clonePos的新长度。现在,会发生什么?好吧,您陷入了无限循环:

enter image description here

经验教训

如果您要循环的数组可能在循环中发生变化(并更改其长度),则从不]使用这种条件:

i != myArr.length

如果希望循环在某个时刻结束,总是希望使用更严格的条件:

i < myArr.length

并且,甚至更好,如果在满足条件后循环没有意义,请通过返回结束该循环。例如:

function hitDetect() {
  for (var iB = 0; iB < clonePos.length; iB++) {
    if (clonePos[iB] > -320 && clonePos[iB] < -280 && charY > 200) {
      return charDied();
    }
  }
}

固定代码

// Commented because does not work in Sandbox
// window.localStorage; //Ignore this line

// Where all my variables have been assigned

var c = document.getElementById("GameScreen");
var ctx = c.getContext("2d");
var charY = 220;
const gravity = 10;
var score = 0;
var time = 0;
var speed = 5;
var cloneID = 0;
var clonePos = [600];
var clonePoints = [0];
var animationBounce = 0;
var jump = 10;
var charDead = 0;
var dataCharY = [];
var dataDisObst = [];
var disObst = 1000;
var lowestLoopDis;
var jumpFactor = 0;
var disDeath;
var AIgames = 1;
var bestScoreAI = 0;

ctx.translate(c.width / 2, c.height / 2);

// Was going to use this for background trees but haven't done it yet

new obj(50, 50, 30, 30);

// Runs most functions

function runAll() {
  if (charDead == 0) {
    clearAll(); //This function runs most of the code
    updateChar();
    createGround();
    updateObj();
    groundDetect();
    updateScore();
    hitDetect();
    addData();
    testBetterAI();
    getDisObst();
    jumpAI();
    removeUnusedObst();
  }
}

// Was going to use this for trees but haven't yet

function obj(x, y, width, height) {
  this.width = width;
  this.height = height;
  this.x = x;
  this.y = y;

  ctx.beginPath();

  ctx = c.getContext("2d");
  ctx.fillStyle = "brown";
  ctx.fillRect(this.x, this.y, this.width, this.height);
  ctx.fillStyle = "green";
  ctx.arc(-293, 150, 50, 0, 2 * Math.PI);
  ctx.fill();
  ctx.stroke();

  this.cloneID = cloneID;
}

new obj(-293, 212, 0, 2 * Math.PI);

// Creates the floor (IKR)

function createGround() {
  ctx.fillStyle = "green";
  ctx.fillRect(-635, 250, c.width, 50);
}

// Creates the character every milisecond (or 10, I can't remember)

function updateChar() {
  ctx.fillStyle = "blue";
  ctx.fillRect(-300, charY - animationBounce, 15, 30);
  ctx.fillStyle = "pink";
  ctx.beginPath();
  ctx.arc(-293, charY - animationBounce - 15, 15, 0, 2 * Math.PI);
  ctx.fill();
  ctx.stroke();
}

// Removes everything in order to be redrawn in new position

function clearAll() {
  ctx.clearRect(-700, -700, 2000, 2000);
}

// Redraws every square / object

function updateObj() {
  for (var i = 0; i < clonePos.length; i++) {
    ctx.fillStyle = "green";
    ctx.fillRect(clonePos[i], 220, 30, 30);
  }
}

// Creates new square (I also decided to rename them half way through with obstacle instead of object)

function createObst() {
  clonePos.push(600);
  cloneID++;
}

// Changes the squares / obstacles position relative to the movement

function moveObst() {
  for (var ii = 0; ii < clonePos.length; ii++) {
    clonePos[ii] -= speed;
  }
}

// Tests to see if the character is on the ground

function groundDetect() {
  if (charY > 220) {
    charY = 220;
  }
}

// Makes gravity actually work

function charGravity() {
  if (charY < 220) {
    charY += gravity;
  }
}

// Updates the score counter text

function updateScore() {
  document.getElementById("scoreText").innerHTML = score;
}

// Gives the character a little bounce when moving

function charBounce() {
  setTimeout(function() {
    animationBounce++;
  }, 100);
  setTimeout(function() {
    animationBounce++;
  }, 200);
  setTimeout(function() {
    animationBounce++;
  }, 300);
  setTimeout(function() {
    animationBounce--;
  }, 400);
  setTimeout(function() {
    animationBounce--;
  }, 500);
  setTimeout(function() {
    animationBounce--;
  }, 600);
}

// Makes the character jump

function charJump() {
  if (charY == 220) {
    jump = 4;

    setTimeout(function() {
      charY -= jump;
    }, 20);
    jump = 8;
    setTimeout(function() {
      charY -= jump;
    }, 40);
    jump = 12;
    setTimeout(function() {
      charY -= jump;
    }, 60);
    jump = 16;
    setTimeout(function() {
      charY -= jump;
    }, 80);
    setTimeout(function() {
      charY -= jump;
    }, 100);
    setTimeout(function() {
      charY -= jump;
    }, 120);
  }
}

// Detects when the character has a hit a square

function hitDetect() {
  for (var iB = 0; iB < clonePos.length; iB++) {
    if (clonePos[iB] > -320 && clonePos[iB] < -280 && charY > 200) {
      return charDied();
    }
  }
}

// Runs when character dies

function charDied() {
  disDeath = disObst;
  charDead = 1;

  charRevive();

  testBetterAI();

  decideAdjustments();
}

// Adds score very interval

function addingScore() {
  if (charDead == 0) {
    score += 100;
  }
}

// Adds to an array that I will use later

function addData() {
  dataCharY.push(charY);
  dataDisObst.push(disObst);
}

// Test to see if one of my AI's (which hasn't been made yet) scores is better than the previous best

function testBetterAI() {
  // Commented because does not work in Sandbox
  // if (score > localStorage.getItem("bestScore")) {
  // }
}

// Calculates the distance to the nearest square / obstacle

function getDisObst() {
  lowestLoopDis = 1000;

  for (var iiA = 0; iiA < clonePos.length; iiA++) {
    if (clonePos[iiA] > -320) {
      if (clonePos[iiA] > 0) {
        if (Math.abs(clonePos[iiA]) < lowestLoopDis) {
          lowestLoopDis = Math.abs(clonePos[iiA]);
        }
      } else {
        if (Math.abs(clonePos[iiA]) < lowestLoopDis) {
          lowestLoopDis = Math.abs(clonePos[iiA]);
        }
      }
    }
  }

  if (lowestLoopDis < disObst) {
    disObst = lowestLoopDis;
  }
}

// Increments the speed of the obstacles / squares and the character

function addSpeed() {
  if (speed < 25) {
    speed++;
  }
}

// Restarts the game

function charRevive() {
  clonePos = [600];
  charDead = 0;
  score = 0;
  time = 0;
  speed = 5;
  AIgames++;
}

// I accidently did this twice, whoops

function testBetterAI() {
  if (score > bestScoreAI) {
    bestScoreAI = score;
  }
}

// Makes the unfinished AI jump when it wants to

function jumpAI() {
  if (disObst <= disDeath + jumpFactor) {
    charJump();
  }
}

// What changes need to be made in order to improve the AI

function decideAdjustments() {
  jumpFactor += Math.floor(Math.random() * 10) - 5;

  if (jumpFactor < 0) {
    jumpFactor = 0;
  }
}

// Removing blocks that are off the screen

function removeUnusedObst() {
  if (clonePos[0] < -650) {
    clonePos.shift();
  }
}

// Intervals here

setInterval(function() {
  time++;
}, 1000);
setInterval(function() {
  runAll();
}, 10);
setInterval(function() {
  moveObst();
}, 50);
setInterval(function() {
  charGravity();
}, 25);
setInterval(function() {
  createObst();
}, 3000);
setInterval(function() {
  charBounce();
}, 650);
setInterval(function() {
  addingScore();
}, 3500);
setInterval(function() {
  addSpeed();
}, 25000);
#GameScreen {
  background-color: CornflowerBlue;
  width: 380px; height: 200px;
}

#scoreText {
  text-align: center;
  font-size: 16px;
}
<div id="scoreText"></div>
<canvas id="GameScreen" width="1270px" height="550px"></canvas>
© www.soinside.com 2019 - 2024. All rights reserved.