在 Tic Tac Toe 中改变游戏模式 [The Odin Project]
Changing game mode in Tic Tac Toe [The Odin Project]
这是我的第一个问题,如果我做错了,请先道歉!
我正在学习使用 Odin 项目 编写代码。到目前为止,我一直在做每个项目,没有遇到任何重大问题:偶尔会遇到一些困难,但经过一番思考,我能够成功解决它们。
目前,我在 Tic Tac Toe JavaScript 项目中。我已经让游戏运行起来,实现了两种游戏模式:VS Player 2 和 VS CPU。两者都是先通过HTML欢迎window选择的,我为了避免使用提示,都运行没有问题。但是,每当我尝试通过放置在界面中的按钮更改游戏模式时,我都会失败并且模式保持不变。
例如,如果我想从VS Player 2模式更改为VS CPU模式,分数会重置并且玩家的名字改变了,但游戏保持 运行ning 在 VS Player 2 模式。没有显示控制台错误,所以我确定这与范围或逻辑有关!
我已经尝试了很多东西,包括生成 HTML 欢迎 window 和 JavaScript DOM 操作,但我无法使其工作。我遇到这个问题已经两周了,但我仍然碰壁!
这是管理模式选择的代码部分:
const modeSelector = {
constants: [
/* 0 */ modalOverlay = document.getElementById("modal-overlay"),
/* 1 */ modalWindow = document.getElementById("modal-window"),
/* 2 */ modalContent = document.getElementById("modal-content"),
/* 3 */ gameButtons = document.getElementById("game-buttons"),
/* 4 */ popUpVs = document.getElementById("popUpVs"),
/* 5 */ popUpCpu = document.getElementById("popUpCpu"),
/* 6 */ vsPlayerTwo = document.getElementById("vsplayer2"),
/* 7 */ vsCPU = document.getElementById("vsCPU"),
],
gameMode(mode) {
if (mode === "") {
} else if (mode === "vsPlayerTwoMode") {
gameBoard.cleanBoard();
p1 = playerCreator.createPlayer();
p1.name = playerCreator.names[0].innerHTML;
playerCreator.scores[0].innerHTML = "0";
p2 = playerCreator.createPlayer();
p2.name = playerCreator.names[1].innerHTML;
playerCreator.scores[1].innerHTML = "0";
movements.movement();
rules.turnChanger();
} else if (mode === "vsCPUMode") {
gameBoard.cleanBoard();
p1 = playerCreator.createPlayer();
p1.name = playerCreator.names[0].innerHTML;
playerCreator.scores[0].innerHTML = "0";
p2 = playerCreator.createPlayer();
p2.name = "CPU"
playerCreator.names[1].innerHTML = p2.name;
playerCreator.scores[1].innerHTML = "0";
movements.vsCpuMovement();
rules.turnChanger();
}
},
reset() {
gameBoard.cleanBoard();
modeSelector.gameMode("");
playerCreator.names[0].innerHTML = "0";
playerCreator.names[1].innerHTML = "0";
playerCreator.scores[0].innerHTML = "0";
playerCreator.scores[1].innerHTML = "0";
},
popUpMode(mode) {
if (mode === "popUpVsMode") {
modeSelector.constants[2].innerHTML = "Insert Player 1 name";
} else if (mode === "popUpCPUMode") {
modeSelector.constants[2].innerHTML = "Insert Player name";
}
modeSelector.constants[2].style.marginLeft = "130px";
modeSelector.constants[4].remove();
modeSelector.constants[5].remove();
let p1NameBar = document.createElement("input");
p1NameBar.id = "p1NameBar";
p1NameBar.maxLength = "6";
modeSelector.constants[3].appendChild(p1NameBar);
let p1NameOk = document.createElement("h2");
p1NameOk.class = "popUpButton";
p1NameOk.type = "button";
p1NameOk.id = "popUpP1NameOk";
p1NameOk.innerHTML = "OK";
modeSelector.constants[3].appendChild(p1NameOk);
p1NameOk.addEventListener("click", () => {
if (mode === "popUpVsMode") {
playerCreator.names[0].innerHTML = p1NameBar.value;
modeSelector.constants[2].innerHTML = "Insert Player 2 name";
modeSelector.constants[2].style.marginLeft = "130px";
p1NameBar.remove();
p1NameOk.remove();
let p2NameBar = document.createElement("input");
p2NameBar.id = "p2NameBar";
p2NameBar.maxLength = "6";
modeSelector.constants[3].appendChild(p2NameBar);
let p2NameOk = document.createElement("h2");
p2NameOk.className = "popUpButton";
p2NameOk.type = "button";
p2NameOk.id = "popUpP2NameOk";
p2NameOk.innerHTML = "OK";
modeSelector.constants[3].appendChild(p2NameOk);
p2NameOk.addEventListener("click", () => {
playerCreator.names[1].innerHTML= p2NameBar.value;
document.body.removeChild(modalOverlay);
modeSelector.gameMode("vsPlayerTwoMode");
});
} else if (mode === "popUpCPUMode") {
playerCreator.names[0].innerHTML = p1NameBar.value;
document.body.removeChild(modalOverlay);
modeSelector.gameMode("vsCPUMode");
}
});
},
inGameMode(mode) {
modeSelector.reset()
let inGameOverlay = document.createElement("div");
inGameOverlay.id = "inGameOverlay";
inGameOverlay.className = "modal-overlay";
document.body.appendChild(inGameOverlay);
let inGameWindow = document.createElement("div");
inGameWindow.className = "modal-window";
inGameWindow.id = "inGameWindow";
inGameOverlay.appendChild(inGameWindow);
let inGameTitleBar = document.createElement("div");
inGameTitleBar.className = "modal-titlebar";
inGameTitleBar.id = "inGameTitleBar";
inGameWindow.appendChild(inGameTitleBar);
let inGameTitle = document.createElement("span");
inGameTitle.className = "modal-title";
inGameTitle.id = "inGameTitle";
if (mode === "VSP2") {
inGameTitle.innerHTML = "VS Player 2 Mode";
inGameTitle.style.marginLeft = "160px";
inGameTitleBar.appendChild(inGameTitle);
let inGameContent = document.createElement("div");
inGameContent.className = "modal-content";
inGameContent.id = "inGameContent";
inGameContent.innerHTML = "Insert Player 1 name";
inGameContent.style.marginLeft = "120px";
inGameWindow.appendChild(inGameContent);
let inGameButtons = document.createElement("div");
inGameButtons.className = "modal-buttons";
inGameButtons.id = "inGameButtons";
inGameWindow.appendChild(inGameButtons);
let inGameP1NameBar = document.createElement("input");
inGameP1NameBar.id = "p1NameBar";
inGameP1NameBar.maxLength = "6";
inGameButtons.appendChild(inGameP1NameBar);
let inGameP1NameOk = document.createElement("h2");
inGameP1NameOk.className = "popUpButton";
inGameP1NameOk.type = "button";
inGameP1NameOk.id = "popUpP1NameOk";
inGameP1NameOk.innerHTML = "OK";
inGameButtons.appendChild(inGameP1NameOk);
inGameP1NameOk.addEventListener("click", () => {
playerCreator.names[0].innerHTML = inGameP1NameBar.value;
inGameContent.innerHTML = "Insert Player 2 name";
inGameContent.style.marginLeft = "130px";
inGameP1NameBar.remove();
inGameP1NameOk.remove();
let inGameP2NameBar = document.createElement("input");
inGameP2NameBar.id = "p2NameBar";
inGameP2NameBar.maxLength = "6";
inGameButtons.appendChild(inGameP2NameBar);
let inGameP2NameOk = document.createElement("h2");
inGameP2NameOk.className = "popUpButton";
inGameP2NameOk.type = "button";
inGameP2NameOk.id = "popUpP2NameOk";
inGameP2NameOk.innerHTML = "OK";
inGameButtons.appendChild(inGameP2NameOk);
inGameP2NameOk.addEventListener("click", () => {
playerCreator.names[1].innerHTML= inGameP2NameBar.value;
document.body.removeChild(inGameOverlay);
modeSelector.gameMode("vsPlayerTwoMode");
})
});
} else if (mode === "VSCPU") {
inGameTitle.innerHTML = "VS CPU Mode";
inGameTitle.style.marginLeft = "210px";
inGameTitleBar.appendChild(inGameTitle);
let inGameContent = document.createElement("div");
inGameContent.className = "modal-content";
inGameContent.id = "inGameContent";
inGameContent.innerHTML = "Insert Player 1 name";
inGameContent.style.marginLeft = "120px";
inGameWindow.appendChild(inGameContent);
let inGameButtons = document.createElement("div");
inGameButtons.className = "modal-buttons";
inGameButtons.id = "inGameButtons";
inGameWindow.appendChild(inGameButtons);
let inGameP1NameBar = document.createElement("input");
inGameP1NameBar.id = "p1NameBar";
inGameP1NameBar.maxLength = "6";
inGameButtons.appendChild(inGameP1NameBar);
let inGameP1NameOk = document.createElement("h2");
inGameP1NameOk.className = "popUpButton";
inGameP1NameOk.type = "button";
inGameP1NameOk.id = "popUpP1NameOk";
inGameP1NameOk.innerHTML = "OK";
inGameButtons.appendChild(inGameP1NameOk);
inGameP1NameOk.addEventListener("click", () => {
playerCreator.names[0].innerHTML = inGameP1NameBar.value;
document.body.removeChild(inGameOverlay);
modeSelector.gameMode("vsCPUMode");
});
}
let inGameInfo = document.createElement("div");
inGameInfo.id = "modal-info";
inGameInfo.innerHTML = "You can reset the game mode during the match by clicking on any of the buttons to the right";
inGameWindow.appendChild(inGameInfo);
},
};
还有一些用于“点击”的 addEventListeners 在不同的按钮中实现上述代码,但我不想添加更多代码,所以我也分享了完整的事情在 GitHub:
https://github.com/roznerx/tic_tac_toe
提前致谢,再次抱歉,如果我问错了!
如果我们首先以 vsPlayerTwoMode
模式开始,那么 movements.movement()
会为棋盘上的每个框添加一个事件侦听器。单击一个框时,它会检查它是否为空,并根据轮到谁(基于 playerCreator.turns[0]
和 playerCreator.turns[1]
的值)将 gameBoard.board[i].innerHTML
设置为 X
或 O
.
现在让我们切换到vsCPUMode
模式。板上的每个框现在都附加了原始事件侦听器(来自 movements.movement()
),以及来自 movements.vsCpuMovement()
的新事件侦听器。单击框时,它将首先评估上段中的逻辑(如 movements.movement()
事件侦听器中定义的),然后是 movements.vsCpuMovement()
函数中的逻辑(值得注意的是,检查是否 gameBoard.board[i].innerHTML == ""
).
但是,由于 movements.movement()
事件在 movements.vsCpuMovement()
事件之前调用,因此 gameBoard.board[i].innerHTML
将被设置为 X
或 O
取决于 playerCreator.turns[0]
和 playerCreator.turns[1]
的先前值。然后,movements.vsCpuMovement()
检查 gameBoard.board[i].innerHTML
是否为空字符串,事实并非如此,因此函数 returns.
重要的是,当模式为vsCPUMode
启动时,movements.movement()
事件侦听器永远不会被注册,所以无论值是多少都没有关系playerCreator.turns[0]
或 playerCreator.turns[1]
是。
我们如何解决它?一种选择是重置 playerCreator.turns[...]
的值,以便在调用 movements.movement()
事件时,它只是忽略依赖于这些值的逻辑( 有点等价 以 vsCPUMode
模式开始游戏)。也就是说,在line 215:
后面加上这两行
playerCreator.turns[0] = ""
playerCreator.turns[1] = ""
有没有更好的方法解决问题?你打赌!我建议在添加新的侦听器之前将您的代码发布到 Code Review and asking people for suggestions. If you are only interested in solving this immediate problem, I would keep track of all the event listeners you add to the gameboard boxes, and if you change the modes, remove 任何现有的侦听器上。
这是我的第一个问题,如果我做错了,请先道歉!
我正在学习使用 Odin 项目 编写代码。到目前为止,我一直在做每个项目,没有遇到任何重大问题:偶尔会遇到一些困难,但经过一番思考,我能够成功解决它们。
目前,我在 Tic Tac Toe JavaScript 项目中。我已经让游戏运行起来,实现了两种游戏模式:VS Player 2 和 VS CPU。两者都是先通过HTML欢迎window选择的,我为了避免使用提示,都运行没有问题。但是,每当我尝试通过放置在界面中的按钮更改游戏模式时,我都会失败并且模式保持不变。
例如,如果我想从VS Player 2模式更改为VS CPU模式,分数会重置并且玩家的名字改变了,但游戏保持 运行ning 在 VS Player 2 模式。没有显示控制台错误,所以我确定这与范围或逻辑有关!
我已经尝试了很多东西,包括生成 HTML 欢迎 window 和 JavaScript DOM 操作,但我无法使其工作。我遇到这个问题已经两周了,但我仍然碰壁!
这是管理模式选择的代码部分:
const modeSelector = {
constants: [
/* 0 */ modalOverlay = document.getElementById("modal-overlay"),
/* 1 */ modalWindow = document.getElementById("modal-window"),
/* 2 */ modalContent = document.getElementById("modal-content"),
/* 3 */ gameButtons = document.getElementById("game-buttons"),
/* 4 */ popUpVs = document.getElementById("popUpVs"),
/* 5 */ popUpCpu = document.getElementById("popUpCpu"),
/* 6 */ vsPlayerTwo = document.getElementById("vsplayer2"),
/* 7 */ vsCPU = document.getElementById("vsCPU"),
],
gameMode(mode) {
if (mode === "") {
} else if (mode === "vsPlayerTwoMode") {
gameBoard.cleanBoard();
p1 = playerCreator.createPlayer();
p1.name = playerCreator.names[0].innerHTML;
playerCreator.scores[0].innerHTML = "0";
p2 = playerCreator.createPlayer();
p2.name = playerCreator.names[1].innerHTML;
playerCreator.scores[1].innerHTML = "0";
movements.movement();
rules.turnChanger();
} else if (mode === "vsCPUMode") {
gameBoard.cleanBoard();
p1 = playerCreator.createPlayer();
p1.name = playerCreator.names[0].innerHTML;
playerCreator.scores[0].innerHTML = "0";
p2 = playerCreator.createPlayer();
p2.name = "CPU"
playerCreator.names[1].innerHTML = p2.name;
playerCreator.scores[1].innerHTML = "0";
movements.vsCpuMovement();
rules.turnChanger();
}
},
reset() {
gameBoard.cleanBoard();
modeSelector.gameMode("");
playerCreator.names[0].innerHTML = "0";
playerCreator.names[1].innerHTML = "0";
playerCreator.scores[0].innerHTML = "0";
playerCreator.scores[1].innerHTML = "0";
},
popUpMode(mode) {
if (mode === "popUpVsMode") {
modeSelector.constants[2].innerHTML = "Insert Player 1 name";
} else if (mode === "popUpCPUMode") {
modeSelector.constants[2].innerHTML = "Insert Player name";
}
modeSelector.constants[2].style.marginLeft = "130px";
modeSelector.constants[4].remove();
modeSelector.constants[5].remove();
let p1NameBar = document.createElement("input");
p1NameBar.id = "p1NameBar";
p1NameBar.maxLength = "6";
modeSelector.constants[3].appendChild(p1NameBar);
let p1NameOk = document.createElement("h2");
p1NameOk.class = "popUpButton";
p1NameOk.type = "button";
p1NameOk.id = "popUpP1NameOk";
p1NameOk.innerHTML = "OK";
modeSelector.constants[3].appendChild(p1NameOk);
p1NameOk.addEventListener("click", () => {
if (mode === "popUpVsMode") {
playerCreator.names[0].innerHTML = p1NameBar.value;
modeSelector.constants[2].innerHTML = "Insert Player 2 name";
modeSelector.constants[2].style.marginLeft = "130px";
p1NameBar.remove();
p1NameOk.remove();
let p2NameBar = document.createElement("input");
p2NameBar.id = "p2NameBar";
p2NameBar.maxLength = "6";
modeSelector.constants[3].appendChild(p2NameBar);
let p2NameOk = document.createElement("h2");
p2NameOk.className = "popUpButton";
p2NameOk.type = "button";
p2NameOk.id = "popUpP2NameOk";
p2NameOk.innerHTML = "OK";
modeSelector.constants[3].appendChild(p2NameOk);
p2NameOk.addEventListener("click", () => {
playerCreator.names[1].innerHTML= p2NameBar.value;
document.body.removeChild(modalOverlay);
modeSelector.gameMode("vsPlayerTwoMode");
});
} else if (mode === "popUpCPUMode") {
playerCreator.names[0].innerHTML = p1NameBar.value;
document.body.removeChild(modalOverlay);
modeSelector.gameMode("vsCPUMode");
}
});
},
inGameMode(mode) {
modeSelector.reset()
let inGameOverlay = document.createElement("div");
inGameOverlay.id = "inGameOverlay";
inGameOverlay.className = "modal-overlay";
document.body.appendChild(inGameOverlay);
let inGameWindow = document.createElement("div");
inGameWindow.className = "modal-window";
inGameWindow.id = "inGameWindow";
inGameOverlay.appendChild(inGameWindow);
let inGameTitleBar = document.createElement("div");
inGameTitleBar.className = "modal-titlebar";
inGameTitleBar.id = "inGameTitleBar";
inGameWindow.appendChild(inGameTitleBar);
let inGameTitle = document.createElement("span");
inGameTitle.className = "modal-title";
inGameTitle.id = "inGameTitle";
if (mode === "VSP2") {
inGameTitle.innerHTML = "VS Player 2 Mode";
inGameTitle.style.marginLeft = "160px";
inGameTitleBar.appendChild(inGameTitle);
let inGameContent = document.createElement("div");
inGameContent.className = "modal-content";
inGameContent.id = "inGameContent";
inGameContent.innerHTML = "Insert Player 1 name";
inGameContent.style.marginLeft = "120px";
inGameWindow.appendChild(inGameContent);
let inGameButtons = document.createElement("div");
inGameButtons.className = "modal-buttons";
inGameButtons.id = "inGameButtons";
inGameWindow.appendChild(inGameButtons);
let inGameP1NameBar = document.createElement("input");
inGameP1NameBar.id = "p1NameBar";
inGameP1NameBar.maxLength = "6";
inGameButtons.appendChild(inGameP1NameBar);
let inGameP1NameOk = document.createElement("h2");
inGameP1NameOk.className = "popUpButton";
inGameP1NameOk.type = "button";
inGameP1NameOk.id = "popUpP1NameOk";
inGameP1NameOk.innerHTML = "OK";
inGameButtons.appendChild(inGameP1NameOk);
inGameP1NameOk.addEventListener("click", () => {
playerCreator.names[0].innerHTML = inGameP1NameBar.value;
inGameContent.innerHTML = "Insert Player 2 name";
inGameContent.style.marginLeft = "130px";
inGameP1NameBar.remove();
inGameP1NameOk.remove();
let inGameP2NameBar = document.createElement("input");
inGameP2NameBar.id = "p2NameBar";
inGameP2NameBar.maxLength = "6";
inGameButtons.appendChild(inGameP2NameBar);
let inGameP2NameOk = document.createElement("h2");
inGameP2NameOk.className = "popUpButton";
inGameP2NameOk.type = "button";
inGameP2NameOk.id = "popUpP2NameOk";
inGameP2NameOk.innerHTML = "OK";
inGameButtons.appendChild(inGameP2NameOk);
inGameP2NameOk.addEventListener("click", () => {
playerCreator.names[1].innerHTML= inGameP2NameBar.value;
document.body.removeChild(inGameOverlay);
modeSelector.gameMode("vsPlayerTwoMode");
})
});
} else if (mode === "VSCPU") {
inGameTitle.innerHTML = "VS CPU Mode";
inGameTitle.style.marginLeft = "210px";
inGameTitleBar.appendChild(inGameTitle);
let inGameContent = document.createElement("div");
inGameContent.className = "modal-content";
inGameContent.id = "inGameContent";
inGameContent.innerHTML = "Insert Player 1 name";
inGameContent.style.marginLeft = "120px";
inGameWindow.appendChild(inGameContent);
let inGameButtons = document.createElement("div");
inGameButtons.className = "modal-buttons";
inGameButtons.id = "inGameButtons";
inGameWindow.appendChild(inGameButtons);
let inGameP1NameBar = document.createElement("input");
inGameP1NameBar.id = "p1NameBar";
inGameP1NameBar.maxLength = "6";
inGameButtons.appendChild(inGameP1NameBar);
let inGameP1NameOk = document.createElement("h2");
inGameP1NameOk.className = "popUpButton";
inGameP1NameOk.type = "button";
inGameP1NameOk.id = "popUpP1NameOk";
inGameP1NameOk.innerHTML = "OK";
inGameButtons.appendChild(inGameP1NameOk);
inGameP1NameOk.addEventListener("click", () => {
playerCreator.names[0].innerHTML = inGameP1NameBar.value;
document.body.removeChild(inGameOverlay);
modeSelector.gameMode("vsCPUMode");
});
}
let inGameInfo = document.createElement("div");
inGameInfo.id = "modal-info";
inGameInfo.innerHTML = "You can reset the game mode during the match by clicking on any of the buttons to the right";
inGameWindow.appendChild(inGameInfo);
},
};
还有一些用于“点击”的 addEventListeners 在不同的按钮中实现上述代码,但我不想添加更多代码,所以我也分享了完整的事情在 GitHub:
https://github.com/roznerx/tic_tac_toe
提前致谢,再次抱歉,如果我问错了!
如果我们首先以 vsPlayerTwoMode
模式开始,那么 movements.movement()
会为棋盘上的每个框添加一个事件侦听器。单击一个框时,它会检查它是否为空,并根据轮到谁(基于 playerCreator.turns[0]
和 playerCreator.turns[1]
的值)将 gameBoard.board[i].innerHTML
设置为 X
或 O
.
现在让我们切换到vsCPUMode
模式。板上的每个框现在都附加了原始事件侦听器(来自 movements.movement()
),以及来自 movements.vsCpuMovement()
的新事件侦听器。单击框时,它将首先评估上段中的逻辑(如 movements.movement()
事件侦听器中定义的),然后是 movements.vsCpuMovement()
函数中的逻辑(值得注意的是,检查是否 gameBoard.board[i].innerHTML == ""
).
但是,由于 movements.movement()
事件在 movements.vsCpuMovement()
事件之前调用,因此 gameBoard.board[i].innerHTML
将被设置为 X
或 O
取决于 playerCreator.turns[0]
和 playerCreator.turns[1]
的先前值。然后,movements.vsCpuMovement()
检查 gameBoard.board[i].innerHTML
是否为空字符串,事实并非如此,因此函数 returns.
重要的是,当模式为vsCPUMode
启动时,movements.movement()
事件侦听器永远不会被注册,所以无论值是多少都没有关系playerCreator.turns[0]
或 playerCreator.turns[1]
是。
我们如何解决它?一种选择是重置 playerCreator.turns[...]
的值,以便在调用 movements.movement()
事件时,它只是忽略依赖于这些值的逻辑( 有点等价 以 vsCPUMode
模式开始游戏)。也就是说,在line 215:
playerCreator.turns[0] = ""
playerCreator.turns[1] = ""
有没有更好的方法解决问题?你打赌!我建议在添加新的侦听器之前将您的代码发布到 Code Review and asking people for suggestions. If you are only interested in solving this immediate problem, I would keep track of all the event listeners you add to the gameboard boxes, and if you change the modes, remove 任何现有的侦听器上。