基于HTML5实现的中国象棋游戏
程序员文章站
2022-07-05 23:42:48
...
HTML5实现中国象棋游戏
http://www.w2bc.com/article/20596
http://www.html5tricks.com/html5-zgxq.html
https://gist.github.com/siongui/7958813
https://blog.csdn.net/itlwei/article/details/7635984
https://github.com/baxinfangkai/ChinaChess-html5
-
http://www.w2bc.com/article/20596
http://www.html5tricks.com/html5-zgxq.html
https://gist.github.com/siongui/7958813
https://blog.csdn.net/itlwei/article/details/7635984
https://github.com/baxinfangkai/ChinaChess-html5
<!DOCTYPE HTML> <html> <head> <meta http - equiv = "Content-Type" content = "text/html; charset=utf-8" /> <title> 象棋 </title> <style> canvas.middle { border: 1 px solid# dddddd; cursor: crosshair; </style> </head> <body> <canvas width = "600px" height = "600px" id = "middle" class = "middle" ></canvas> <script type = "text/javascript"> var mycanvas = document.getElementById("middle"); var stepCount = 0; ctx = mycanvas.getContext("2d"); var layout = { offsetWidth: 600, //canvas 中用于作为绘图面板的总宽度 offsetHeight: 600, cell: 50, padding: 30, middleHeight: 80 }; var style = { board: { bgColor: "rgb(255,200,100)", border: "rgb(100,255,200)", lineWidth: 2, middle_bound: { fontColor: "rgba(0,255,0,1)", fontSize: 18, fontName: "Arial" } }, qizi: { radius: 16, //半径 bgColor: "rgba(200,200,200,1)", sideColor: "rgba(200,180,220,1)", red_fontColor: "rgba(255,0,0,1)", black_fontColor: "rgba(0,0,0,1)", fontSize: 14, fontName: "Arial", goColor: "rgb(255,0,0)" } }; function getPosToPanel(xIndex, yIndex) { //获取棋盘上qizi[yIndex][xIndex]处棋子的中心位置 var temp = { x: xIndex, y: yIndex }; temp.x = layout.padding + xIndex * layout.cell; temp.y = layout.padding + yIndex * layout.cell; if (yIndex >= 5) { temp.y += layout.middleHeight - layout.cell; } return temp; } function getXY(evt) { // get click pos base on <canvas>, so(0,0) is at the left-top of <canvas> var clientX = evt.clientX, clientY = evt.clientY; var temp = { x: 0, y: 0 }; var parObj = mycanvas; var offset = mycanvas.offsetLeft; while (parObj = parObj.offsetParent) { offset += parObj.offsetLeft; } temp.x = clientX - offset; var parObj = mycanvas; var offset = mycanvas.offsetTop; while (parObj = parObj.offsetParent) { offset += parObj.offsetTop; } temp.y = clientY - offset; return temp; } function getQiziClickIndex(evt) { //根据点击事件,返回点击范围所在处属于哪个索引的棋子,返回值为0-89,-1表示错误值 var temp = getXY(evt); temp.x = temp.x - layout.padding; temp.y = temp.y - layout.padding; var i, j; i = Math.round(temp.x / layout.cell); if (temp.y <= layout.cell * 4 + style.qizi.radius) { j = Math.round(temp.y / layout.cell); //求出距离第i行,j列最近 } else if (temp.y >= layout.cell * 4 + layout.middleHeight - style.qizi.radius) { //在楚河汉界的下方 j = Math.round((temp.y - (layout.cell * 4 + layout.middleHeight)) / layout.cell) + 5; } else { return -1; } if (i >= 9 || j >= 10 || i < 0 || j < 0) { return -1; } var pos = getPosToPanel(i, j); pos.x -= layout.padding; pos.y -= layout.padding; if (Math.pow(temp.x - pos.x, 2) + Math.pow(temp.y - pos.y, 2) < style.qizi.radius * style.qizi.radius) { //在棋子范围内 return i + j * 9; } return -1; // 不在棋子范围内 } var qiziIndex = new Array(90); var qiziyanse = new Array(90); function initQiziArray() { for (var i = 0; i < qiziIndex.length; ++i) { qiziIndex[i] = ""; qiziyanse[i] = 0; //-1 red, 1 black, 0 none } qiziIndex[0] = qiziIndex[8] = "车"; qiziIndex[1] = qiziIndex[7] = "马"; qiziIndex[2] = qiziIndex[6] = "相"; qiziIndex[3] = qiziIndex[5] = "士"; qiziIndex[4] = "将"; qiziIndex[19] = qiziIndex[25] = "炮"; qiziIndex[27] = qiziIndex[29] = qiziIndex[31] = qiziIndex[33] = qiziIndex[35] = "兵"; qiziyanse[0] = qiziyanse[8] = qiziyanse[1] = qiziyanse[7] = qiziyanse[2] = qiziyanse[6] = qiziyanse[3] = qiziyanse[5] = qiziyanse[4] = qiziyanse[19] = qiziyanse[25] = qiziyanse[27] = qiziyanse[29] = qiziyanse[31] = qiziyanse[33] = qiziyanse[35] = 1; qiziIndex[81] = "车"; qiziIndex[89] = "车"; qiziIndex[82] = "马"; qiziIndex[88] = "马"; qiziIndex[83] = "相"; qiziIndex[87] = "相"; qiziIndex[84] = qiziIndex[86] = "士"; qiziIndex[85] = "将"; qiziIndex[64] = "炮"; qiziIndex[70] = "炮"; qiziIndex[54] = qiziIndex[56] = qiziIndex[58] = qiziIndex[60] = qiziIndex[62] = "兵"; qiziyanse[81] = qiziyanse[89] = qiziyanse[82] = qiziyanse[88] = qiziyanse[83] = qiziyanse[87] = qiziyanse[84] = qiziyanse[85] = qiziyanse[86] = qiziyanse[64] = qiziyanse[70] = qiziyanse[54] = qiziyanse[56] = qiziyanse[58] = qiziyanse[60] = qiziyanse[62] = -1; //qiziIndex[10] = "相";qiziyanse[10]=1; } initQiziArray(); function drawQizi(name, index, red_black) { //在指定的棋子位置,画出指定的棋子 if (red_black != -1 && red_black != 1 || index > 89 || index < 0) { return; } var pos = getPosToPanel(index % 9, Math.floor(index / 9)); var x = pos.x; var y = pos.y; ctx.fillStyle = style.qizi.bgColor; //定义演示 ctx.strokeStyle = style.qizi.sideColor; ctx.lineWidth = style.board.lineWidth; ctx.beginPath(); //从新开始画,防止冲突重叠 ctx.arc(x, y, style.qizi.radius, Math.PI * 0, Math.PI * 2, true); //x坐标,y坐标,直径,始,终,时针方向 ctx.closePath(); //结束画布,防止冲突重叠 ctx.fill(); //结束渲染 ctx.font = "Normal " + style.qizi.fontSize + "px " + style.qizi.fontName; ctx.fillStyle = ((red_black == -1) ? style.qizi.red_fontColor : style.qizi.black_fontColor); //定义演示 ctx.fillText(name, x, y); ctx.stroke(); qiziyanse[index] = red_black; qiziIndex[index] = name; } function drawChess() { //在棋盘上画出所有棋子 var i = 0; for (i = 0; i < 90; ++i) { drawQizi(qiziIndex[i], i, qiziyanse[i]); } } function canJump(srcIndex, dstIndex) { // 判断srcIndex的棋子是否可以吃掉dstIndex的棋子,或者srcIndex 是否可以跳到dstIndex处 if (srcIndex < 0 || srcIndex >= 90 || dstIndex < 0 || dstIndex >= 90 //棋子不在棋盘内 || qiziyanse[srcIndex] == qiziyanse[dstIndex] || qiziyanse[srcIndex] == 0 || qiziyanse[srcIndex] == -1 && stepCount % 2 == 1 || qiziyanse[srcIndex] == 1 && stepCount % 2 == 0) { //空子或者同色棋子不可以发生 吃子或走棋 行为 return false; } var xIndex = {}; var yIndex = {}; xIndex.src = srcIndex % 9; xIndex.dst = dstIndex % 9; yIndex.src = Math.floor(srcIndex / 9); yIndex.dst = Math.floor(dstIndex / 9); switch (qiziIndex[srcIndex]) { case "车": var existMiddleQizi = false; var increase = 0; if (xIndex.src == xIndex.dst) { increase = 9; } else if (yIndex.src == yIndex.dst) { increase = 1; } if (increase > 0) { var min = srcIndex, max = dstIndex; if (srcIndex > dstIndex) { min = dstIndex; max = srcIndex; } for (var i = min + increase; i < max; i += increase) { if (qiziyanse[i] != 0) { existMiddleQizi = true; break; } } return !existMiddleQizi; } else { return false; } case "马": return Math.abs(xIndex.src - xIndex.dst) * Math.abs(yIndex.src - yIndex.dst) == 2 && (Math.abs(xIndex.src - xIndex.dst) == 1 && qiziIndex[xIndex.src + (yIndex.src + yIndex.dst) / 2 * 9] == "" || Math.abs(yIndex.src - yIndex.dst) == 1 && qiziIndex[yIndex.src * 9 + (xIndex.src + xIndex.dst) / 2 % 9] == ""); //成 ”日" 且不能 别着 马腿 case "炮": var min = srcIndex, max = dstIndex; var increase = 0; if (xIndex.src == xIndex.dst) { increase = 9; } else if (yIndex.src == yIndex.dst) { increase = 1; } else { return false; } var middleQiziCount = 0; if (srcIndex > dstIndex) { min = dstIndex; max = srcIndex; } for (var i = min + increase; i < max && middleQiziCount < 2; i += increase) { if (qiziyanse[i] != 0) { ++middleQiziCount; } } return qiziyanse[srcIndex] != qiziyanse[dstIndex] && qiziyanse[dstIndex] != 0 && middleQiziCount == 1 || qiziyanse[dstIndex] == 0 && middleQiziCount == 0; case "兵": case "卒": return Math.abs(xIndex.dst - xIndex.src) == 1 && yIndex.src == yIndex.dst && (yIndex.src - 4.5) * qiziyanse[srcIndex] > 0 || xIndex.src == xIndex.dst && qiziyanse[srcIndex] * (dstIndex - srcIndex) == 9; case "相": case "象": return Math.abs(xIndex.src - xIndex.dst) == 2 && Math.abs(yIndex.src - yIndex.dst) == 2 && qiziIndex[(srcIndex + dstIndex) >> 1] == ""; case "将": case "帅": return (Math.abs(xIndex.src - xIndex.dst) + Math.abs(yIndex.src - yIndex.dst) == 1) && Math.abs(xIndex.dst - 4) <= 1 && (qiziyanse[srcIndex] == -1 ? Math.abs(yIndex.dst - 8) <= 1 : Math.abs(yIndex.dst - 1) <= 1); case "士": return (Math.abs(xIndex.src - xIndex.dst) == 1 && Math.abs(yIndex.src - yIndex.dst) == 1) && Math.abs(xIndex.dst - 4) <= 1 && (qiziyanse[srcIndex] == -1 ? Math.abs(yIndex.dst - 8) <= 1 : Math.abs(yIndex.dst - 1) <= 1); default: return false; } } function drawChessPanel() { // draw bgColor ctx.fillStyle = style.board.bgColor; ctx.beginPath(); ctx.rect(0, 0, layout.offsetWidth, layout.offsetHeight); ctx.closePath(); ctx.fill(); // prepare to draw lines var p = layout.padding, s = layout.cell, w = layout.cell * 8, h = layout.cell * 4; m = layout.middleHeight; ctx.strokeStyle = style.board.border; ctx.lineWidth = style.board.lineWidth; ctx.beginPath(); // horizonal lines for (var i = 0; i <= 4; i++) { ctx.moveTo(p, s * i + p + 0.5); ctx.lineTo(w + p, s * i + p + 0.5); } var fixL = p + h + m; for (var i = 5; i <= 9; i++) { ctx.moveTo(p, s * (i - 5) + fixL + 0.5); ctx.lineTo(w + p, s * (i - 5) + fixL + 0.5); } // vertical lines ctx.moveTo(p + 0.5, p); ctx.lineTo(p + 0.5, 2 * h + m + p); ctx.moveTo(w + p + 0.5, p); ctx.lineTo(w + p + 0.5, 2 * h + m + p); for (var i = 1; i < 8; i++) { ctx.moveTo(s * i + p + 0.5, p); ctx.lineTo(s * i + p + 0.5, s * 4 + p); ctx.moveTo(s * i + p + 0.5, h + p + m); ctx.lineTo(s * i + p + 0.5, h * 2 + m + p); } //"X" shapes ctx.moveTo(s * 3 + p, p); ctx.lineTo(s * 5 + p, s * 2 + p); ctx.moveTo(s * 5 + p, 0 + p); ctx.lineTo(s * 3 + p + 0.5, s * 2 + p); ctx.moveTo(s * 3 + p + 0.5, h + s * 2 + m + p); ctx.lineTo(s * 5 + p + 0.5, h + s * 4 + m + p); ctx.moveTo(s * 5 + p + 0.5, h + s * 2 + m + p); ctx.lineTo(s * 3 + p, h + s * 4 + m + p); ctx.closePath(); ctx.stroke(); ctx.font = "Normal " + style.board.middle_bound.fontSize + "px " + style.board.middle_bound.fontName; ctx.fillStyle = style.board.middle_bound.fontColor; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText("楚河", p + s * 2, p + s * 4 + layout.middleHeight / 2); ctx.fillText("漢界", p + s * 6, p + s * 4 + layout.middleHeight / 2); ctx.stroke(); } drawChessPanel(); drawChess(); function drawClearQizi(xIndex, yIndex) { var pos; pos = getPosToPanel(xIndex, yIndex); var old = {}; old.bgColor = style.qizi.bgColor; //保存棋子的样式设置 old.sideColor = style.qizi.sideColor; old.red_fontColor = style.qizi.red_fontColor; old.black_fontColor = style.qizi.black_fontColor; old.radius = style.qizi.radius; style.qizi.bgColor = style.board.bgColor; //使用背景设置 style.qizi.sideColor = style.board.bgColor; style.qizi.red_fontColor = style.board.bgColor; style.qizi.black_fontColor = style.board.bgColor; style.qizi.radius = style.qizi.radius + 1; // 还没搞清为何这个地方要增加一个才行 drawQizi("", xIndex + yIndex * 9, qiziyanse[yIndex * 9 + xIndex]); //用背景色的圆恢复棋盘颜色 style.qizi.bgColor = old.bgColor; //还原棋子的样式设置 style.qizi.sideColor = old.sideColor; style.qizi.red_fontColor = old.red_fontColor; style.qizi.black_fontColor = old.black_fontColor; style.qizi.radius = old.radius; ctx.strokeStyle = style.board.border; ctx.lineWidth = style.board.lineWdith; ctx.beginPath(); var lineTop = Math.max(pos.y - style.qizi.radius - style.board.lineWidth, layout.padding); var lineBottom = Math.min(pos.y + style.qizi.radius + style.board.lineWidth, layout.middleHeight + 8 * layout.cell + layout.padding); if (yIndex == 4) { // 楚河汉界 的边界棋子绘制 lineBottom = layout.padding + layout.cell * 4; if (xIndex == 0 || xIndex == 8) { lineBottom += style.qizi.radius + style.board.lineWidth; } } else if (yIndex == 5) { lineTop = layout.padding + layout.cell * 4 + layout.middleHeight; if (xIndex == 0 || xIndex == 8) { lineTop -= style.qizi.radius + style.board.lineWidth; } } ctx.moveTo(pos.x + 0.5, lineTop); ctx.lineTo(pos.x + 0.5, lineBottom); ctx.moveTo(Math.max(pos.x - style.qizi.radius - style.board.lineWidth, layout.padding), pos.y + 0.5); ctx.lineTo(Math.min(pos.x + style.qizi.radius + style.board.lineWidth, layout.padding + layout.cell * 8), pos.y + 0.5); //绘制将帅的斜线 var r_sqrt2 = Math.ceil(style.qizi.radius / Math.sqrt(2)) + 1; if (xIndex == 3 && (yIndex == 0 || yIndex == 7)) { ctx.moveTo(pos.x, pos.y); ctx.lineTo(pos.x + r_sqrt2, pos.y + r_sqrt2); } else if (xIndex == 3 && (yIndex == 2 || yIndex == 9)) { ctx.moveTo(pos.x, pos.y); ctx.lineTo(pos.x + r_sqrt2, pos.y - r_sqrt2); } else if (xIndex == 4 && (yIndex == 1 || yIndex == 8)) { ctx.moveTo(pos.x, pos.y); ctx.lineTo(pos.x - r_sqrt2, pos.y - r_sqrt2); ctx.moveTo(pos.x, pos.y); ctx.lineTo(pos.x + r_sqrt2, pos.y - r_sqrt2); ctx.moveTo(pos.x, pos.y); ctx.lineTo(pos.x - r_sqrt2, pos.y + r_sqrt2); ctx.moveTo(pos.x, pos.y); ctx.lineTo(pos.x + r_sqrt2, pos.y + r_sqrt2); } else if (xIndex == 5 && (yIndex == 0 || yIndex == 7)) { ctx.moveTo(pos.x, pos.y); ctx.lineTo(pos.x - r_sqrt2, pos.y + r_sqrt2); } else if (xIndex == 5 && (yIndex == 2 || yIndex == 9)) { ctx.moveTo(pos.x, pos.y); ctx.lineTo(pos.x - r_sqrt2, pos.y - r_sqrt2); } //结束将帅斜线的绘制 //显示图形 ctx.closePath(); ctx.stroke(); qiziIndex[yIndex * 9 + xIndex] = ""; //更新棋盘 qiziyanse[yIndex * 9 + xIndex] = 0; } function drawFourCross(xIndex, yIndex, color) { var oldStyle = ctx.strokeStyle; color ? ctx.strokeStyle = color : ctx.strokeStyle = style.qizi.goColor; var pos = getPosToPanel(xIndex, yIndex); ctx.beginPath(); ctx.moveTo(pos.x - style.qizi.radius, pos.y - style.qizi.radius); ctx.lineTo(pos.x - style.qizi.radius, pos.y - style.qizi.radius / 2); ctx.moveTo(pos.x - style.qizi.radius, pos.y - style.qizi.radius); ctx.lineTo(pos.x - style.qizi.radius / 2, pos.y - style.qizi.radius); ctx.moveTo(pos.x - style.qizi.radius, pos.y + style.qizi.radius); ctx.lineTo(pos.x - style.qizi.radius, pos.y + style.qizi.radius / 2); ctx.moveTo(pos.x - style.qizi.radius, pos.y + style.qizi.radius); ctx.lineTo(pos.x - style.qizi.radius / 2, pos.y + style.qizi.radius); ctx.moveTo(pos.x + style.qizi.radius, pos.y - style.qizi.radius); ctx.lineTo(pos.x + style.qizi.radius / 2, pos.y - style.qizi.radius); ctx.moveTo(pos.x + style.qizi.radius, pos.y - style.qizi.radius); ctx.lineTo(pos.x + style.qizi.radius, pos.y - style.qizi.radius / 2); ctx.moveTo(pos.x + style.qizi.radius, pos.y + style.qizi.radius); ctx.lineTo(pos.x + style.qizi.radius, pos.y + style.qizi.radius / 2); ctx.moveTo(pos.x + style.qizi.radius, pos.y + style.qizi.radius); ctx.lineTo(pos.x + style.qizi.radius / 2, pos.y + style.qizi.radius); ctx.closePath(); ctx.stroke(); ctx.strokeStyle = oldStyle; } function drawLastGo(xIndex, yIndex, color) { //drawClearQizi(xIndex, yIndex); drawFourCross(xIndex, yIndex); //drawFourCross(xIndex, yIndex, "rgb(0,0,255)"); } function clearLastGo(xIndex, yIndex) { drawFourCross(xIndex, yIndex, style.board.bgColor); } var isDown = false; var timer = null; var g_num_down = -1; var g_num_up = -1; mycanvas.onmousedown = function(evt) { g_num_down = getQiziClickIndex(evt); if (g_num_down != -1) { var oldColor = style.qizi.bgColor; style.qizi.bgColor = "rgba(200,170,190,1.0)"; drawQizi(qiziIndex[g_num_down], g_num_down, qiziyanse[g_num_down]); style.qizi.bgColor = oldColor; } isDown = true; }; var g_last_go = -1; var g_last_go2 = -1; mycanvas.onmouseup = function(evt) { if (!isDown) { return; } g_num_up = getQiziClickIndex(evt); if (g_num_up != -1 && g_num_down != -1 && canJump(g_num_down, g_num_up)) { if (g_last_go != -1) { clearLastGo(g_last_go % 9, Math.floor(g_last_go / 9)); } if (g_last_go2 != -1) { clearLastGo(g_last_go2 % 9, Math.floor(g_last_go2 / 9)); } var oldColor = style.qizi.bgColor; var whowin = 0; if (qiziIndex[g_num_up] == "将") { whowin = qiziyanse[g_num_down]; } drawQizi(qiziIndex[g_num_down], g_num_up, qiziyanse[g_num_down]); style.qizi.bgColor = oldColor; drawClearQizi(g_num_down % 9, Math.floor(g_num_down / 9)); g_last_go = g_num_down; g_last_go2 = g_num_up; drawLastGo(g_num_down % 9, Math.floor(g_num_down / 9)); drawFourCross(g_num_up % 9, Math.floor(g_num_up / 9)); stepCount += 1; if (whowin == -1) alert("红方胜利"); else if (whowin == 1) alert("黑方胜利"); } else if (g_num_down != -1) { drawQizi(qiziIndex[g_num_down], g_num_down, qiziyanse[g_num_down]); } isDown = false; } </script> </body> </html>
-