javascript - 如何仅使用 context.save/context.restore、if 语句、画布和动画制作井字游戏?
问题描述
如何仅使用 context.save/context.restore、if 语句、画布和动画制作井字游戏?我也在努力做到这一点,如果图像 X 显示在框 1 中,图像 O 不能显示在同一个框中,所以你不能作弊。
我不知道如何防止有人将图像 O 放在图像 X 上,反之亦然。请有人告诉我一种方法来防止人们将 O 放在 X 上,反之亦然。
这是我到目前为止所拥有的
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="U1TS.css">
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<br>
<button onclick="Restart()">Restart</button>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var c1 = 1
var c2 = 1
var c3 = 1
var c4 = 1
var c5 = 1
var c6 = 1
var c7 = 1
var c8 = 1
var c9 = 1
var cup1 = 2
var cup2 = 2
var cup3 = 2
var cup4 = 2
var cup5 = 2
var cup6 = 2
var cup7 = 2
var cup8 = 2
var cup9 = 2
//Line horizontale et verticale
context.beginPath();
context.moveTo(40,145);
context.lineTo(360,145);
context.lineWidth = 5
context.lineCap = 'round';
context.stroke();
context.beginPath();
context.moveTo(40,260);
context.lineTo(360,260);
context.lineCap = 'round';
context.stroke();
context.beginPath();
context.moveTo(260,40);
context.lineTo(260,360);
context.lineCap = 'round';
context.stroke();
context.beginPath();
context.moveTo(140,40);
context.lineTo(140,360);
context.lineCap = 'round';
context.stroke();
context.font = "italic bold 30pt Calibri"
context.fillText("1", 75, 325);
context.fillText("2", 190, 325);
context.fillText("3", 305, 325);
context.fillText("4", 75, 215);
context.fillText("5", 190, 215);
context.fillText("6", 305, 215);
context.fillText("7", 75, 105);
context.fillText("8", 190, 105);
context.fillText("9", 305, 105);
function Restart(){
document.location.reload(true);
}
document.onkeydown = Nombre;
Nombreup1 = 49; Nombreup2 = 50; Nombreup3 = 51;
Nombreup4 = 52; Nombreup5 = 53; Nombreup6 = 54;
Nombreup7 = 55; Nombreup8 = 56; Nombreup9 = 57;
Nombre7 = 103; Nombre8 = 104; Nombre9 = 105;
Nombre4 = 100; Nombre5 = 101; Nombre6 = 102;
Nombre3 = 99; Nombre2 = 98; Nombre1 = 97;
function Nombre(e){
toucheCourante = e.keyCode;
if (toucheCourante == Nombre7){
lettreO7();
} else if (toucheCourante == Nombre8){
lettreO8();
} else if (toucheCourante == Nombre9){
lettreO9();
} else if (toucheCourante == Nombre6){
lettreO6();
} else if (toucheCourante == Nombre5){
lettreO5();
} else if (toucheCourante == Nombre4){
lettreO4();
} else if (toucheCourante == Nombre3){
lettreO3();
} else if (toucheCourante == Nombre2){
lettreO2();
} else if (toucheCourante == Nombre1){
lettreO1();
}
/////////////////////////////////////////
if (toucheCourante == Nombreup7){
lettreX7();
} else if (toucheCourante == Nombreup8){
lettreX8();
} else if (toucheCourante == Nombreup9){
lettreX9();
} else if (toucheCourante == Nombreup6){
lettreX6();
} else if (toucheCourante == Nombreup5){
lettreX5();
} else if (toucheCourante == Nombreup4){
lettreX4();
} else if (toucheCourante == Nombreup3){
lettreX3();
} else if (toucheCourante == Nombreup2){
lettreX2();
} else if (toucheCourante == Nombreup1){
lettreX1();
}
}
function lettreO1()
{
lettreO = new Image();
lettreO.src = 'O.jpg';
lettreO.onload = function(){
context.drawImage(lettreO, 40, 265,95,93);
}
}
function lettreX1()
{
lettreX = new Image();
lettreX.src = 'X.PNG';
lettreX.onload = function(){
context.drawImage(lettreX, 40, 265,95,93);
}
}
function lettreO2()
{
lettreO = new Image();
lettreO.src = 'O.jpg';
lettreO.onload = function(){
context.drawImage(lettreO, 145, 265,110,93);
}
}
function lettreX2()
{
lettreX = new Image();
lettreX.src = 'X.PNG';
lettreX.onload = function(){
context.drawImage(lettreX, 145, 265,110,93);
}
}
function lettreO3()
{
lettreO = new Image();
lettreO.src = 'O.jpg';
lettreO.onload = function(){
context.drawImage(lettreO, 265, 265,95,93);
}
}
function lettreX3()
{
lettreX = new Image();
lettreX.src = 'X.PNG';
lettreX.onload = function(){
context.drawImage(lettreX, 265, 265,95,93);
}
}
function lettreO4()
{
lettreO = new Image();
lettreO.src = 'O.jpg';
lettreO.onload = function(){
context.drawImage(lettreO, 40,149,95,107);
}
}
function lettreX4()
{
lettreX = new Image();
lettreX.src = 'X.PNG';
lettreX.onload = function(){
context.drawImage(lettreX, 40,149,95,107);
}
}
function lettreO5()
{
lettreO = new Image();
lettreO.src = 'O.jpg';
lettreO.onload = function(){
context.drawImage(lettreO, 145,149,110,107);
}
}
function lettreX5()
{
lettreX = new Image();
lettreX.src = 'X.PNG';
lettreX.onload = function(){
context.drawImage(lettreX, 145,149,110,107);
}
}
function lettreO6()
{
lettreO = new Image();
lettreO.src = 'O.jpg';
lettreO.onload = function(){
context.drawImage(lettreO, 265,149,95,107);
}
}
function lettreX6()
{
lettreX = new Image();
lettreX.src = 'X.PNG';
lettreX.onload = function(){
context.drawImage(lettreX, 265,149,95,107);
}
}
function lettreO7()
{
lettreO = new Image();
lettreO.src = 'O.jpg';
lettreO.onload = function(){
context.drawImage(lettreO, 40,40,95,101);
}
}
function lettreX7()
{
lettreX = new Image();
lettreX.src = 'X.PNG';
lettreX.onload = function(){
context.drawImage(lettreX, 40,40,95,101);
}
}
function lettreO8()
{
lettreO = new Image();
lettreO.src = 'O.jpg';
lettreO.onload = function(){
context.drawImage(lettreO, 145,40,110,101);
}
}
function lettreX8()
{
lettreX = new Image();
lettreX.src = 'X.PNG';
lettreX.onload = function(){
context.drawImage(lettreX, 145,40,110,101);
}
}
function lettreO9()
{
lettreO = new Image();
lettreO.src = 'O.jpg';
lettreO.onload = function(){
context.drawImage(lettreO, 265,40,95,101);
}
}
function lettreX9()
{
lettreX = new Image();
lettreX.src = 'X.PNG';
lettreX.onload = function(){
context.drawImage(lettreX, 265,40,95,101);
}
}
</script>
</body>
</html>
解决方案
我们在聊天中进行了交谈,但由于我不知道我们何时会同时在 SO 上,所以我发布了一个解决方案。如果你愿意,我仍然可以一步一步地帮助你。
首先,我清理并简化了您的代码的某些部分以避免大量工作:
- 我将所有用于绘制网格的代码放在一个
drawGrid(context)
函数中:
从:
// Line horizontale et verticale
至:
context.fillText("9", 305, 105);
- 然后,我重写了
function Nombre(e) {...}
函数。
我使用了键盘映射:
var KEYBOARD = {
NUMBER_UP_1: 49,
...
NUMBER_UP_9: 57,
NUMBER_1: 97,
...
NUMBER_9: 105,
};
我重命名了 function function onKeyDown(e) {...}
,因为Nombre(e)
它不是很明确并且可能与Number(n)
function 混淆。
我从 keyCode 中推断出这封信。这是一个X
if the keyCode
is in [49, ..., 57],或者一个O
if the keyCode
is in [97, ..., 105]。
然后,计算keyCode - {firstKeyCodeForCurrentLetter} - 1
会为您提供按下的键上的数字。例如,如果您按50,您有:50 - 49 + 1 = 2
,并且根据键盘映射,50与键UP_2相关联。
然后,每当按下数字键(0 除外)时,我都会检查是否有玩家在这里玩过。我创建了一个letterAt(memoryContext, position)
函数,如果玩家已经在该位置上场,则返回 true,否则返回 false。如果玩家没有,那么我使用在memorizeMove(memoryContext, letter, position)
中绘制的a 保存移动,然后通过在其上绘制 an或 a来memoryCanvas
更新主画布。X
O
最后,我确定是否有一个获胜者,该winOrLoss(memoryContext)
函数返回一个字母:'O'
或,如果还没有获胜者,则返回'X'
一个空字符串。''
我没有处理平局,也没有处理每个玩家必须等待轮到他玩的事实。所以一个玩家可以连续玩两次。但这是你可以解决的问题。也没有任何适当的游戏结束:如果玩家获胜,则会发出警报,仅此而已,之后游戏仍然可以继续。
但是restart()
工作:我在这个函数中初始化了我们需要的一切,所以每次调用它时,它都会清除画布并初始化变量。
我还重写了lettreX1()
等lettreO3()
函数,因为:无需每次绘制时都加载相同的图像。加载一次并根据需要多次使用。然后,您只需将x,y
位置分配给一个函数即可在您想要的位置绘制图像,将您的 18 个函数减少到只有一个。
- 为了保存游戏的状态,您不想使用变量(例如数组或矩阵来知道已经玩过哪些动作),因此我们同意使用辅助画布。此画布大小为 3x3。每次玩家玩,如果允许移动,那么我们在这个画布上绘制一个像素,这表明该位置不再是空的。一个球员一个颜色。我使用以下
memorizeMove(memoryContext, letter, position)
功能做到了这一点:
function memorizeMove(memoryContext, letter, position) {
memoryContext.fillStyle = letter === `O` ? 'red' : 'blue';
var coords = getCoordinatesFromPosition(position);
memoryContext.fillRect(coords.x, coords.y, 1, 1);
}
它根据玩家的字母设置颜色(O -> red, X -> blue),从网格中的位置获取x,y坐标,然后在这个位置绘制一个像素,也就是一个1x1的矩形用设定的颜色。
- 为了检查是否允许移动,我使用了
letterAt(memoryContext, position)
将像素颜色(红色、蓝色或空白)转换为字母或空字符串的函数。我本可以只返回 true 或 false,但我需要winOrLoss(memoryContext)
函数中的字母,并且我认为稍后知道哪个玩家在这里玩过(如果有的话)也可能很有用。
function letterAt(memoryContext, position) {
var color = getPixelAt(memoryContext, position);
return color === 'red'
? 'O'
: color === 'blue'
? 'X'
: '';
}
它使用 a返回指定 的第二个画布getPixelAt(memoryContext, position)
上的像素颜色,如一起看到的。它将 转换为坐标,然后获取 处的像素,获取其RGBA颜色并返回其颜色。memoryContext
position
position
x,y
x,y
function getPixelAt(memoryContext, position) {
var coords = getCoordinatesFromPosition(position);
var pixel = memoryContext.getImageData(coords.x, coords.y, 1, 1);
var data = pixel.data;
var red = data[0];
var blue = data[2];
var color = '';
if (red === 255) {
color = 'red';
} else if (blue === 255) {
color = 'blue';
}
return color;
}
- 我写
getCoordinatesFromPosition(position)
函数的时候有点懒……事实上,你应该使用%和/的组合,但是由于你的网格是倒置的(左上角是 7,而不是 1),我认为它可能比预期的要复杂,所以我做了一些非常简单的东西,只使用 ifs。
function getCoordinatesFromPosition(position) {
var x = [1, 4, 7].includes(position)
? 0
: [2, 5, 8].includes(position)
? 1
: 2;
var y = position < 4
? 2
: position < 7
? 1
: 0;
return { x: x, y: y };
}
- 最后,对于
winOrLoss(memoryContext)
函数,我使用函数读取画布letterAt(memoryContext, i)
并将它们存储在数组中。然后我比较了彼此之间的字母,水平、垂直和对角线,寻找 3 个相同的字母。true
如果条件满足则返回,false
否则返回。
function winOrLoss(memoryContext) {
var letters = [];
for (var i = 1; i <= 9; i++) {
letters.push(letterAt(memoryContext, i));
}
if (letters[0] === letters[1] && letters[1] === letters[2] && letters[0] !== ''
|| letters[3] === letters[4] && letters[4] === letters[5] && letters[3] !== ''
|| letters[6] === letters[7] && letters[7] === letters[8] && letters[6] !== ''
|| letters[0] === letters[3] && letters[3] === letters[6] && letters[0] !== ''
|| letters[1] === letters[4] && letters[4] === letters[7] && letters[1] !== ''
|| letters[2] === letters[5] && letters[4] === letters[8] && letters[2] !== ''
|| letters[0] === letters[4] && letters[4] === letters[8] && letters[0] !== ''
|| letters[2] === letters[4] && letters[4] === letters[7] && letters[2] !== ''
) {
return letters[0];
}
}
像往常一样,这是小提琴:https ://jsfiddle.net/nmerinian/2h87Ltr9/75/
推荐阅读
- sql - 将多个表中的行值合并到一个结果单元格中
- python - 如何删除 Pandas Dataframe 列中所有值的字符串的最后一个字符?
- react-native - 反应导航堆栈共享导航选项
- replace - 使用 xquery 替换元素中的部分数据
- python - Union 中 io.TextIOBase 的类型检查问题
- node.js - Npm 安装在 run-rs 上失败
- java - 有没有办法在 pom.xml 中排除额外的 AWS Maven 依赖项?
- java - 线程“主”java.lang.IllegalAccessError 中的异常:访问类失败
- firebase - GS Firebase 功能无法设置偏移量?
- postgresql - 在 AWS Aurora 上还原快照时,如何修复“引擎不支持数据库集群”?