欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于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


基于HTML5实现的中国象棋游戏
            
    
    博客分类: javaScript html5游戏 



基于HTML5实现的中国象棋游戏
            
    
    博客分类: javaScript 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>




-
  • 基于HTML5实现的中国象棋游戏
            
    
    博客分类: javaScript html5游戏 
  • 大小: 90 KB
  • 基于HTML5实现的中国象棋游戏
            
    
    博客分类: javaScript html5游戏 
  • 大小: 55.5 KB
相关标签: html5 游戏