【发布时间】:2022-06-11 03:08:49
【问题描述】:
看似随意,我的代码在尝试将地板添加到新房间时会崩溃。该选项卡将冻结,并且此错误似乎发生在我尝试生成房间的任何地方。这发生在 Edge、Firefox 和 Chrome 上。下面是我的 index JS 文件,也是调用添加房间地板的函数的地方。
import {Character} from "./Character.js";
import {Player} from "./Player.js"
import {Room} from "./Room.js"
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
canvas.width = 1280;
canvas.height = 768;
ctx.fillRect(0, 0, 1280, 768);
let enemies = [];
let rooms = [];
let activeHitboxes = [];
let isMouseClicked = false;
let mousePosX = 640;
let mousePosY = 360;
let currentRoom = -1;
let player;
let intervalCode = 0;
let score;
document.body.onkeydown = function (e) {
if (e.key === " " ||
e.code === "Space"
) {
if(intervalCode !== 0){
clearInterval(intervalCode);}
startGame();
}
}
canvas.onmousedown = (event) => { //update mouseclick status
const {
mousePress = true
} = event;
isMouseClicked = mousePress;
}
canvas.onmouseup = (event) => {
const {
mousePress = false
} = event;
isMouseClicked = mousePress;
}
canvas.onmousemove = (event) => { //update mouse position
const {
clientX, clientY
} = event
mousePosX = clientX - event.currentTarget.getBoundingClientRect().left
mousePosY = clientY - event.currentTarget.getBoundingClientRect().top
}
function animate() { //gameplay loop
ctx.fillStyle = '#000'
ctx.fillRect(0, 0, 1280, 768);
rooms[currentRoom].draw();
for (let i = 0; i < rooms[currentRoom].hCells; i++) {
for (let j = 0; j < rooms[currentRoom].vCells; j++) {
if (rooms[currentRoom].tiles[i][j].type === 2) {
activeHitboxes.push({
width: 64,
height: 64,
x: rooms[currentRoom].tiles[i][j].location.x,
y: rooms[currentRoom].tiles[i][j].location.y,
isSourcePlayer: false,
isDoor: false
})
activeHitboxes.push({
width: 64,
height: 64,
x: rooms[currentRoom].tiles[i][j].location.x,
y: rooms[currentRoom].tiles[i][j].location.y,
isSourcePlayer: true,
isDoor: false
})
} else if (rooms[currentRoom].tiles[i][j].type === 4) {
if (i === 0) {
activeHitboxes.push({
width: 64,
height: 64,
x: rooms[currentRoom].tiles[i][j].location.x,
y: rooms[currentRoom].tiles[i][j].location.y,
isSourcePlayer: true,
isDoor: true,
isEntry: true
})
activeHitboxes.push({
width: 64,
height: 64,
x: rooms[currentRoom].tiles[i][j].location.x,
y: rooms[currentRoom].tiles[i][j].location.y,
isSourcePlayer: false,
isDoor: true,
isEntry: true
})
}
activeHitboxes.push({
width: 64,
height: 64,
x: rooms[currentRoom].tiles[i][j].location.x,
y: rooms[currentRoom].tiles[i][j].location.y,
isSourcePlayer: true,
isDoor: true,
isEntry: false
})
activeHitboxes.push({
width: 64,
height: 64,
x: rooms[currentRoom].tiles[i][j].location.x,
y: rooms[currentRoom].tiles[i][j].location.y,
isSourcePlayer: false,
isDoor: true,
isEntry: false
})
}
}
}
player.updateMouse(mousePosX, mousePosY, isMouseClicked);
checkHits(player);
if (player.getHealth() > 0) {
player.update(activeHitboxes);
} else {
player.shrink(1);
player.draw();
ctx.font = "48px inter";
ctx.fillStyle = "#fff"
ctx.strokeText("PRESS SPACE TO RETRY", canvas.width / 2 - 281, canvas.height / 2)
ctx.fillText("PRESS SPACE TO RETRY", canvas.width / 2 - 281, canvas.height / 2)
}
for (let i = 0; i < enemies.length; i++) {
enemies[i].update();
checkHits(enemies[i]);
checkHits(player);
}
activeHitboxes = [];
}
function generateRoom(x, y, ctx) {
let room = new Room(768, 1280, x, y, ctx);
room.fillRoom();
room.addFloor(x, y);
if (rooms.length <= 1) {
room.addDoors();
} else (
room.addDoors(rooms[currentRoom - 1].getDoors())
)
rooms.push(room);
currentRoom += 1;
}
function checkHits(target) { //check active hitboxes against a target
for (let i = 0; i < activeHitboxes.length; i++) {
checkHit(target, activeHitboxes[i].x, activeHitboxes[i].y, activeHitboxes[i].width, activeHitboxes[i].height, activeHitboxes[i].isSourcePlayer, activeHitboxes[i].isDoor, activeHitboxes[i].isEntry)
}
}
function checkHit(target, hitboxX, hitboxY, hitboxWidth, hitboxHeight, isSourcePlayer, isDoor, isEntry) { //judge if a hitbox connected with a target
if (hitboxX < target.getPosition().x + target.getWidth() && //if hit connects, and they're on opposite teams, remove 1 health from target;
hitboxX + hitboxWidth > target.getPosition().x &&
hitboxY < target.getPosition().y + target.getHeight() &&
hitboxY + hitboxHeight > target.getPosition().y &&
(target.isPlayer && !isSourcePlayer || !target.isPlayer && isSourcePlayer)) {
if (isDoor && !isEntry) {
console.log("Isnt entry")
console.log(currentRoom);
generateRoom(0, rooms[currentRoom].getDoors(), ctx);
player.setPosition(96, rooms[currentRoom - 1].getDoors() * 64)
} else if (isEntry && currentRoom >= 1) {
console.log("Is entry")
console.log(currentRoom);
currentRoom--;
} else {
target.removeHealth();
if (target.getHealth() === 0 && enemies.includes(target)) {
enemies.splice(enemies.indexOf(target), 1);
}
}
}
}
function startGame() {
enemies = [];
rooms = [];
activeHitboxes = [];
isMouseClicked = false;
mousePosX = 640;
mousePosY = 360;
currentRoom = -1;
player = new Player({
position: {x: 32, y: 32},
height: 32,
width: 16,
health: 1,
ctx: ctx,
isPlayer: true,
});
const enemy = new Character({
position: {x: 400, y: 100},
height: 32,
width: 32,
health: 1,
ctx: ctx,
isPlayer: false,
});
generateRoom(0, 0, ctx);
enemies.push(enemy);
player.draw();
for (let i = 0; i < enemies.length; i++) {
enemies[i].draw();
}
intervalCode = setInterval(animate, 1000 / 60);
}
ctx.font = "48px inter";
ctx.fillStyle = "#fff"
ctx.strokeText("PRESS SPACE TO START", canvas.width / 2 - 281, canvas.height / 2)
ctx.fillText("PRESS SPACE TO START", canvas.width / 2 - 281, canvas.height / 2)
房间等级来了
import {Tiles} from "./Tiles.js";
export class Room {
vCells;//Number of vertical tiles, 11
hCells;//number of horizontal tiles, 19
height;
width;
location;
tiles = [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []];
walkable = [[]];
constructor(height, width, x, y, ctx) {
this.height = height;
this.width = width;
this.location = {x: x, y: y};
this.ctx = ctx;
this.vCells = height / 64;
this.hCells = width / 64;
}
fillRoom() {
for (let i = 0; i < this.width / 64; i++) {
for (let j = 0; j < this.height / 64; j++) {
this.tiles[i][j] = (new Tiles(i * 64, j * 64, 2));
}
}
}
addFloor(x, y) {//randomized prim's algorithm to place walkable floor
let startTile = this.tiles[x][y]; //get tile
startTile.setType(3);//set start tile to floor
//compute a frontier list, all wall tiles that are 2 "steps" away from our starting tile are stored in this list if these tiles are valid
let frontier = []
this.getNeighbours(x, y, frontier, 2);
//while this frontier list is not empty, pick an arbitrary tile from this list
while (frontier.length > 0) {
let idx = this.getRandomInt(0, frontier.length);
let frontierNeighbours = [];
let pickedFrontier = frontier[idx];
if (this.getNeighbours(pickedFrontier.location.x / 64, pickedFrontier.location.y / 64, frontierNeighbours, 3)) {//make a list of all neighbours to that frontier tile (tiles 2 distance away that are floors)
let neighbourIDX = this.getRandomInt(0, frontierNeighbours.length);
let neighbourX = frontierNeighbours[neighbourIDX].location.x / 64;
let neighbourY = frontierNeighbours[neighbourIDX].location.y / 64;
let x = pickedFrontier.location.x / 64;
let y = pickedFrontier.location.y / 64;
let xDiff = x - neighbourX;
let yDiff = y - neighbourY;
let connectorX = 0;
let connectorY = 0;
if (xDiff > 0) {
connectorX = neighbourX + 1;
} else if (xDiff < 0) {
connectorX = neighbourX - 1;
} else {
connectorX = neighbourX;
}
if (yDiff > 0) {
connectorY = neighbourY + 1;
} else if (connectorY < 0) {
connectorY = neighbourY - 1;
} else {
connectorY = neighbourY
}
this.getNeighbours(connectorX, connectorY, frontier, 2);
// this.getNeighbours(x, y, frontier, 2);
if (this.isValid(connectorX, connectorY)) {
this.tiles[connectorX][connectorY].setType(3);
this.walkable.push(this.tiles[connectorX][connectorY]);
}
frontier.splice(idx, 1);
}
}
}
getNeighbours(x, y, arr, type) { //Get tiles 2 blocks away
let hasNeighbour = false;
for (let i = -2; i <= 2; i += 2) {
for (let j = -2; j <= 2; j += 2) {
if (this.isValid(x + i, y + j) && this.tiles[x + i][y + j].type === type && ((Math.abs(x - x + i) >= 2 || Math.abs(y - y + j) >= 2) && ((Math.abs(x - x + i) + Math.abs(y - y + j)) !== 4))) {
if (!arr.includes(this.tiles[x + i][y + j])) {
hasNeighbour = true;
arr.push(this.tiles[x + i][y + j]);
// this.tiles[x + i][y + j].setType(0)
}
}
}
}
return hasNeighbour;
}
canAccess(x, y) {
for (let i = -1; i <= 0; i++) {
for (let j = -1; j <= 0; j++) {
if (this.isValid(x + i, y + j) && Math.abs(j + i) !== 2) {
if (this.tiles[x + i][y + j].type === 3) {
return true;
}
}
}
}
return false;
}
isValid(x, y) {
if (x >= this.hCells) {
return false;
}
if (y >= this.vCells) {
return false;
}
if (x < 0) {
return false;
}
if (y < 0) {
return false;
}
return true;
}
getDoors() {
for (let j = 0; j < this.vCells; j++) {
if (this.tiles[this.hCells - 1][j].type === 4) {
return j;
}
}
return -1;
}
getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min) + min); //maximum is exclusive and minimum is inclusive
}
draw() {
for (let i = 0; i < this.tiles.length; i++) {
for (let j = 0; j < this.tiles[i].length; j++) {
if (this.tiles[i][j].type === 0) {
this.ctx.fillStyle = '#000'
}
if (this.tiles[i][j].type === 1) {
this.ctx.fillStyle = '#f00'
}
if (this.tiles[i][j].type === 2) {
this.ctx.fillStyle = '#000'
}
if (this.tiles[i][j].type === 3) {
this.ctx.fillStyle = '#555'
}
if (this.tiles[i][j].type === 4) {
this.ctx.fillStyle = '#00F'
}
this.ctx.fillRect(this.tiles[i][j].location.x, this.tiles[i][j].location.y, this.tiles[i][j].size, this.tiles[i][j].size);
}
}
}
}
顺便说一句,由于这是我的第一个 Javascript 程序,因此也欢迎任何特定于 JavaScript 的建议,谢谢。
编辑:我发现了我的问题,对于addDoor函数,我没有更新无效的随机数,导致死循环
【问题讨论】:
-
你有工作演示吗?
-
一旦你得到它的工作,你可以在Code Review寻求设计建议
-
我必须警告你,这对于我们大多数人来说是太多的代码,只是通过查看来试图弄清楚,所以不要抱太大希望。你应该使用调试器来单步调试它,看看它卡在哪里了。
-
这发生在 ... Chrome 上。 => I particularly like this JS debugging tutorial。它已经过时了,但不要一概而论;挺好的。
-
注释掉代码块,直到它不再崩溃,然后你就知道去哪里找了。
标签: javascript algorithm