我在用js写一个五子棋游戏,利用canvas画棋盘和棋子,为了实现悔棋功能,我用clearRect()清除了原来的棋子,再重新画被清除的部分棋盘,却总是出现了一个圆,请大神帮帮忙,谢谢!
<!DOCTYPE html>
<html lang="en">
<head>
<meter charset="UTF-8"></meter>
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, width=device-width">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>Chess by sheepbao</title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<!--width="450px" height="450px" -->
</head>
<body onbeforeunload="oneLeave()">
<canvas id="chess" width="450px" height="450px"></canvas>
<button onclick="gameover()">结束游戏</button>
<button id="undo">悔棋</button>
<script type="text/javascript">
var cell, half_cell;
var chess = document.getElementById('chess');
var context = chess.getContext('2d');
var undo = document.getElementById('undo');
function layout() {
var avaih = window.innerHeight,
avaiw = window.innerWidth;
var min = Math.min(avaih, avaiw);
/* chess.style.width = (min - 5) + 'px';
chess.style.height = (min - 5) + 'px';*/
var w = min - 5;
chess.width = w;
chess.height = w;
cell = Math.floor(w / 15);
half_cell = cell / 2;
console.log(w, cell, half_cell);
// context.strokeStyle = "#BFBFBF";
for (var i = 0; i < 15; i++) {
context.moveTo(half_cell, half_cell + (cell * i));
context.lineTo(w - half_cell, half_cell + (cell * i));
context.moveTo(half_cell + cell * i, half_cell);
context.lineTo(half_cell + cell * i, w - half_cell);
context.stroke();
}
}
layout();
//chesspiece
var oneStep = function(x, y, black) {
console.log("oneStep", x, y, black);
context.beginPath();
context.arc(half_cell + cell * x, half_cell + cell * y, half_cell * 0.8, 0, 2 * Math.PI);
context.closePath();
var gradient = context.createRadialGradient(half_cell + cell * x + 2, half_cell + cell * y - 2, 13, half_cell + cell * x + 2, half_cell + cell * y - 2, 0);
if (black) {
//black
gradient.addColorStop(0, "#0A0A0A");
gradient.addColorStop(1, "#636766");
} else {
gradient.addColorStop(0, "#D1D1D1");
gradient.addColorStop(1, "#F9F9F9");
}
context.fillStyle = gradient;
context.fill();
context.stroke();
}
function undoStep(x, y) {
console.log(chess.width, chess.height);
context.clearRect((x + 0.1) * cell, (y + 0.1) * cell, 0.8 * cell, 0.8 * cell);
console.log("undoStep:", x, y,
"rect:", (x + 0.1) * cell, (y + 0.1) * cell, 0.8 * cell, 0.8 * cell);
// context.globalCompositeOperation = "source-over";
context.moveTo(cell * (x + 0.1), (0.5 + y) * cell);
context.lineTo(cell * (x + 0.9), (0.5 + y) * cell);
context.moveTo((0.5 + x) * cell, cell * (y + 0.1));
context.lineTo((0.5 + x) * cell, cell * (y + 0.9));
context.stroke();
}
chess.onclick = function(e) {
var x = e.offsetX;
var y = e.offsetY;
meX = Math.floor(x / cell);
meY = Math.floor(y / cell);
console.log("click:", meX, meY);
oneStep(meX, meY, true);
}
undo.onclick = function(e) {
undoStep(meX, meY);
}
</script>
</body>
</html>
点击悔棋按钮之后,之所以会重绘上一次绘制的圆圈,是因为路径没有闭合的原因,
修改意见:你的undoStep()函数,擦除矩形后,在调用context.beginPath();开始一段新的路径,如下图:
另外,你擦除的区域和重绘的区域太小啦,你改了之后就能看见,太小了
只看了描述,没有看代码。
你的这个想法实现起来比较麻烦,简单的方法是重画整个画布,这样你只关注数据就可以了。
创建一个二维数组,用作棋盘的数据。
在每一回合里,下棋或者悔棋都操作这个数组。
操作完数据,把画布全清,重新用数据画一个棋盘。
看了你的代码,你的棋盘线跟棋子都是用path实现的, context.stroke(); 会把所有path stroke出来(就是描边的意思),而你悔棋的函数没有清除上一步棋对应的path,因此context.stroke();描画棋盘线的时候也把棋子描边出来了。ps:棋盘线因为是固定且不变的,所以其实可以通过另外的一个canvas作为背景去展示,这样可以优化重绘的性能。