html5的canvas实现中国象棋

最近有了一个写中国象棋程序的想法,就根据canvas实现了一下。下面是最终效果:

首先,分析页面布局。主要的是有一个显示图像的区域,左下角是显示当前选中的棋子的<p>标签,右下角是两个按钮。

对于图像区域的布局,首先为了让棋子的移动,红圈的移动,和棋盘之间不会互相影响。那我们就要创建三个图层,也就是用三个<canvas>根据相对布局放在同一个位置。

在css设定z-index的值来确定图层的上下。棋盘图层应该放到最下面,棋子图层由于要对点击事件进行相应,于是放在最上层。其余就是JavaScript功能的实现。

注意几点:

  1. 棋子的图片应该是一个透明背景图,这样呈现的效果才会真实(为了更加真实,棋子图片是我的3D渲染图);
  2. 在网页刚打开时会调用init()方法,但是图片可能会没有加载出来,会造成棋盘上棋子显示不全的情况。这时只需刷新几次网页就好了。
  3. 在之后的棋子移动过程中可能也会有棋子显示不出来的情况(但是,目前还没有遇到),如果遇到这种情况就需要点击“刷新”按钮。
  4. 悔棋目前不支持多步,只能悔棋一步。若想改成多步,可能需要用几个数组来存储棋子走过的位置等一些信息。
  5. 没有写对于胜利的判断,因为我觉得象棋的胜利已经很明显了。若想要添加,可以写一个win()方法,在每一次Remove()方法调用后都判断一次。

所以整个的代码如下:

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>中国象棋</title><style type="text/css">* {padding: 0;margin: 0;}#id1 {position: relative;}#canvasp {position: absolute;top: 0px;left: 0px;z-index: 2;}#btn1 {position: absolute;width: 50px;height: 30px;left: 450px;}#btn3 {position: absolute;width: 50px;height: 30px;left: 380px;}#id3 {position: absolute;top: 0px;left: 0px;z-index: 1;}</style></head><body><div id="id1"><div id="canvasp"><canvas id="myCanvas" width="500" height="470" style="border:1px solid #d3d3d3;" onmousedown="show_coords(event)">Your browser does not support the HTML5 canvas tag.</canvas></div><div id="id2"><canvas id="canvas" width="500" height="470"></canvas></div><div id="id3"><canvas id="canvas3" width="500" height="470"></canvas></div></div><div id="id2"><button id="btn1">刷新</button><button id="btn3">悔棋</button><p id="checkedItem">选中了啥</p></div><script>var c = document.getElementById("myCanvas");var ctx = c.getContext("2d");//图片var c2 = document.getElementById("canvas");var canvas = c2.getContext("2d");//提示方框var c3 = document.getElementById("canvas3");var canvas3 = c3.getContext("2d");//选中var checkedItem = document.getElementById("checkedItem");var img = new Image();img.src = "img/chess/象棋棋盘2.png";img.onload = imgfn; //图片加载完在执行var img2 = new Image();var qizi = ["红車", "红马", "红相", "红仕", "红帅","红炮", "红兵", "黑車", "黑马", "黑象", "黑士","黑将", "黑炮", "黑卒"]init();function changImgPath(size) {var imgapath = "img/chess/象棋" + qizi[size] + ".gif";img2.src = imgapath;}function imgfn() {canvas.drawImage(img, 0, 0, 500, 480)}function imgfn2(x, y) {ctx.drawImage(img2, x, y, 50, 50)}function imgfn3(x, y) {canvas3.drawImage(img, x, y, 70, 70)}var pre_x = 0;var pre_y = 0;var victory = false;var Pre_isChecked = false;var Pre_checkedItem = 0;var Now_checkedItem = -2; //默认选择空var Now_team = true; //true表示黑方var Pre_team = true; //true表示黑方var Red_runed = false; //红方走过了没有var Black_runed = false; //黑方走过了没有var qizi_remember = -2; //默认为没有var Remove_successed = false; //上一步走了没var pre_pre_index = [0, 0]; //记录悔棋var index = new Array([7, 8, 9, 10, 11, 10, 9, 8, 7], [-2, -2, -2, -2, -2, -2, -2, -2, -2], [-2, 12, -2, -2, -2, -2, -2, 12, -2], [13, -2, 13, -2, 13, -2, 13, -2, 13], [-2, -2, -2, -2, -2, -2, -2, -2, -2], [-2, -2, -2, -2, -2, -2, -2, -2, -2], [6, -2, 6, -2, 6, -2, 6, -2, 6], [-2, 5, -2, -2, -2, -2, -2, 5, -2], [-2, -2, -2, -2, -2, -2, -2, -2, -2], [0, 1, 2, 3, 4, 3, 2, 1, 0])function repeat(x, y) {return index[y][x] >= 0;}function show_coords(event) {if(victory == false) {x = event.clientXy = event.clientYvar qp_x = Math.round((x - 25) / 55);var qp_y = Math.round((y - 25) / 48);Now_checkedItem = index[qp_y][qp_x];Now_team = Now_checkedItem > 6;changImgPath(Pre_checkedItem)if(Pre_isChecked && (Now_team != Pre_team || Now_checkedItem == -2)) {//                            alert(Now_team+"xxx"+Pre_team)pre_pre_index[0] = pre_x;pre_pre_index[1] = pre_y;Remove(qp_x, qp_y, Pre_checkedItem, Now_checkedItem);}canvas3.clearRect(0, 0, 500, 500);pre_x = qp_x;pre_y = qp_y;x = qp_x * 50 + 25;y = qp_y * 46 + 9;canvas3.strokeStyle = 'red';canvas3.font = "50px Georgia";canvas3.strokeText("⚪", x - 7, y + 42);checkedItem.innerHTML = qizi[index[qp_y][qp_x]]Pre_isChecked = repeat(qp_x, qp_y)Pre_checkedItem = index[qp_y][qp_x];Pre_team = Pre_checkedItem > 6;} else {alert("请重新开局。");}}var btn1 = document.getElementById('btn1');var btn3 = document.getElementById("btn3");function clear(x, y) {x = x * 50 + 25;y = y * 46 + 9;ctx.clearRect(x, y + 3, 50, 47);}btn1.onclick = function() {imgfn2(pre_x * 50 + 25, pre_y * 46 + 9)}btn3.onclick = function() {if(!Remove_successed)returnx = pre_pre_index[0];y = pre_pre_index[1];clear(pre_x, pre_y);imgfn2(x * 50 + 25, y * 46 + 9);if(qizi_remember != -2) {changImgPath(qizi_remember);setTimeout("imgfn2(" + pre_x + "*50+25," + pre_y + "*46+9)", 30)}index[pre_y][pre_x] = qizi_remember;index[y][x] = Pre_checkedItem;Pre_checkedItem = -2;if(Red_runed) {Red_runed = false;Black_runed = true;//                 alert("调用了"+Red_runed)} else if(Black_runed) {Black_runed = false;Red_runed = true;}}function Remove(x, y, Pre_checkedItem, Now_checkedItem) {if(Red_runed) {if(Pre_checkedItem <= 6) {Remove_successed = false;return;}}if(Black_runed) {if(Pre_checkedItem > 6) {Remove_successed = false;return;}}if(!rule(x, y, Pre_checkedItem)) {Remove_successed = false;return;}Remove_successed = true;clear(pre_x, pre_y);if(Now_checkedItem != -2) {clear(x, y);}imgfn2(x * 50 + 25, y * 46 + 9)setTimeout("imgfn2(" + x + "*50+25," + y + "*46+9)", 15)qizi_remember = index[y][x]; //记录被吃掉的棋子或空白index[pre_y][pre_x] = -2;index[y][x] = Pre_checkedItem;if(Pre_checkedItem > 6) {Black_runed = true;Red_runed = false;}if(Pre_checkedItem <= 6) {Red_runed = true;Black_runed = false;}}function rule(x, y, Pre_checkedItem) {switch(Pre_checkedItem) {case 0:case 7:if(x == pre_x || y == pre_y) {if(x == pre_x) {var max_y = (y > pre_y) ? y : pre_y;var min_y = (y > pre_y) ? pre_y : y;for(var i = min_y + 1; i < max_y; i++) {if(index[i][x] != -2) {return false;}}}if(y == pre_y) {var max_x = (x > pre_x) ? x : pre_x;var min_x = (x > pre_x) ? pre_x : x;for(var i = min_x + 1; i < max_x; i++) {if(index[y][i] != -2) {return false;}}}return true;} else {return false;}break;case 1:case 8:if((Math.abs(x - pre_x) == 1 && Math.abs(y - pre_y) == 2) ||(Math.abs(x - pre_x) == 2 && Math.abs(y - pre_y) == 1)) {if((y - pre_y == 2 && index[pre_y + 1][pre_x] != -2) ||(y - pre_y == -2 && index[pre_y - 1][pre_x] != -2) ||(x - pre_x == 2 && index[pre_y][pre_x + 1] != -2) ||(x - pre_x == -2 && index[pre_y][pre_x - 1] != -2)) {return false;}return true;} else {return false;}case 2:case 9:if((Math.abs(x - pre_x) == 2 && Math.abs(y - pre_y) == 2)) {if((Pre_checkedItem > 6 && y <= 4) || (Pre_checkedItem <= 6 && y > 4)) {if((y > pre_y && x > pre_x && index[pre_y + 1][pre_x + 1] != -2) ||(y < pre_y && x > pre_x && index[pre_y - 1][pre_x + 1] != -2) ||(y > pre_y && x < pre_x && index[pre_y + 1][pre_x - 1] != -2) ||(y < pre_y && x < pre_x && index[pre_y - 1][pre_x - 1] != -2)) {return false;}return true;}return false;} else {return false;}case 3:case 10:if((Math.abs(x - pre_x) == 1 && Math.abs(y - pre_y) == 1)) {if((x >= 3 && x <= 5) && (y < 3 || y > 6)) {return true;}return false;} else {return false;}case 4:case 11:if((Math.abs(x - pre_x) == 1 && y == pre_y) ||(Math.abs(y - pre_y) == 1 && x == pre_x)) {if((x >= 3 && x <= 5) && (y < 3 || y > 6)) {return true;}return false;} else {return false;}case 5:case 12:if((x == pre_x || y == pre_y)) {var count2 = 0;if(x == pre_x) {var max_y = (y > pre_y) ? y : pre_y;var min_y = (y > pre_y) ? pre_y : y;for(var i = min_y + 1; i < max_y; i++) {if(index[i][x] != -2) {count2++;if(count2 > 1)return false;}}}if(y == pre_y) {var max_x = (x > pre_x) ? x : pre_x;var min_x = (x > pre_x) ? pre_x : x;for(var i = min_x + 1; i < max_x; i++) {if(index[y][i] != -2) {count2++;if(count2 > 1)return false;}}}if((count2 == 0 && Now_checkedItem == -2) ||(count2 == 1 && Now_checkedItem >= 0)) {return true;} else {return false;}return true;} else {return false;}break;case 6:case 13:var passRaiver = false;if(Pre_checkedItem > 6) { //黑色棋子passRaiver = pre_y > 4if(passRaiver) {if((Math.abs(x - pre_x) == 1 && y == pre_y) ||(Math.abs(y - pre_y) == 1 && x == pre_x)) {if(y - pre_y < 0) {return false;}return true;} else {return false;}} else {if(y - pre_y == 1 && x == pre_x) {return true;} else {return false;}}return true;} else {passRaiver = pre_y < 5if(passRaiver) {if((Math.abs(x - pre_x) == 1 && y == pre_y) ||(Math.abs(y - pre_y) == 1 && x == pre_x)) {if(y - pre_y > 0) {return false;}return true;} else {return false;}} else {if(y - pre_y == -1 && x == pre_x) {return true;} else {return false;}}return false;}default:alert("default了");return true;break;}}function init() {changImgPath(0)setTimeout("imgfn2(0*50+25,9*46+9)", 30)setTimeout("imgfn2(8*50+25,9*46+9)", 30)setTimeout("changImgPath(1)", 50)setTimeout("imgfn2(1*50+25,9*46+9)", 70)setTimeout("imgfn2(7*50+25,9*46+9)", 70)setTimeout("changImgPath(2)", 90)setTimeout("imgfn2(2*50+25,9*46+9)", 110)setTimeout("imgfn2(6*50+25,9*46+9)", 110)setTimeout("changImgPath(3)", 130)setTimeout("imgfn2(3*50+25,9*46+9)", 150)setTimeout("imgfn2(5*50+25,9*46+9)", 150)setTimeout("changImgPath(4)", 170)setTimeout("imgfn2(4*50+25,9*46+9)", 190)setTimeout("changImgPath(5)", 210)setTimeout("imgfn2(1*50+25,7*46+9)", 230)setTimeout("imgfn2(7*50+25,7*46+9)", 230)setTimeout("changImgPath(6)", 250)setTimeout("imgfn2(0*50+25,6*46+9)", 270)setTimeout("imgfn2(2*50+25,6*46+9)", 270)setTimeout("imgfn2(4*50+25,6*46+9)", 270)setTimeout("imgfn2(6*50+25,6*46+9)", 270)setTimeout("imgfn2(8*50+25,6*46+9)", 270)setTimeout("changImgPath(13)", 290)setTimeout("imgfn2(0*50+25,3*46+9)", 310)setTimeout("imgfn2(2*50+25,3*46+9)", 310)setTimeout("imgfn2(4*50+25,3*46+9)", 310)setTimeout("imgfn2(6*50+25,3*46+9)", 320)setTimeout("imgfn2(8*50+25,3*46+9)", 320)setTimeout("changImgPath(12)", 330)setTimeout("imgfn2(1*50+25,2*46+9)", 350)setTimeout("imgfn2(7*50+25,2*46+9)", 350)setTimeout("changImgPath(11)", 370)setTimeout("imgfn2(4*50+25,0*46+9)", 390)setTimeout("changImgPath(10)", 410)setTimeout("imgfn2(3*50+25,0*46+9)", 430)setTimeout("imgfn2(5*50+25,0*46+9)", 430)setTimeout("changImgPath(9)", 450)setTimeout("imgfn2(2*50+25,0*46+9)", 470)setTimeout("imgfn2(6*50+25,0*46+9)", 470)setTimeout("changImgPath(8)", 490)setTimeout("imgfn2(1*50+25,0*46+9)", 510)setTimeout("imgfn2(7*50+25,0*46+9)", 510)setTimeout("changImgPath(7)", 530)setTimeout("imgfn2(0*50+25,0*46+9)", 550)setTimeout("imgfn2(8*50+25,0*46+9)", 550)}</script></body></html>

棋子图片和棋盘的图片已经上传到了我的百度网盘上了,链接如下:

链接:https://pan.baidu.com/s/1HwurAERgQiBt82WlH7L4IA 
提取码:bddb 
复制这段内容后打开百度网盘手机App,操作更方便哦

html5的canvas实现中国象棋相关推荐

  1. canvas实现中国象棋(未判断绝杀)

    中国象棋 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8 ...

  2. canvas绘制中国象棋棋盘

    棋盘 board.html <!doctype html> <html><head><meta charset="gb2312"/> ...

  3. HTML5中国象棋游戏(自定义象棋难度)源码下载

    棋类游戏在桌面游戏中已经非常成熟,中国象棋的版本也非常多.今天这款基于HTML5技术的中国象棋游戏非常有特色,我们不仅可以选择中国象棋的游戏难度,而且可以切换棋盘的样式.程序写累了,喝上一杯咖啡,和电 ...

  4. Html5+javascript中国象棋 制作过程中用到的一些AI算法

    心烦意乱睡不着,随便写点教程吧,不知道这类东西发哪个板块比较合适,先发这吧,哪位管理大大看着不顺眼再移吧. 声明一下啊,本人觉得这个不适合新手看,本人表达能力有限,别把你给误导喽,罪过啊. 象棋的预览 ...

  5. h5使用canvas模拟制作的中国象棋实现残局走子

    <!DOCTYPE html> <html> <head><meta charset="UTF-8"><meta http-e ...

  6. java象棋人机代码_中国象棋人机对弈Java版源码

    [实例简介] 中国象棋人机对弈Java版源码,包含人工智能实现(含多个难度级别,采用α-β迭代搜索算法) [实例截图] [核心代码] 中国象棋人机对弈Java版源码 ├── boards │   ├─ ...

  7. 用 Python 的 tkinter 模块编写一个好看又强大的中国象棋

    继上次我的第一版的<中国象棋>程序之后,我又编写了第二版的<中国象棋>程序,关注我的粉丝知道,我在第一篇<中国象棋>的文章末尾说了,我会出第二版的,对第一版感兴趣的 ...

  8. Android中国象棋自绘简单实现

    中国象棋(引用自百度百科) 中国象棋是起源于中国的一种棋戏,属于二人对抗性游戏的一种,在中国有着悠久的历史.由于用具简单,趣味性强,成为流行极为广泛的棋艺活动. 中国象棋是中国棋文化也是中华民族的文化 ...

  9. Java课程设计—中国象棋(源代码及视频)

    你好,我是罡罡同学! 代码谱第一页忘掉心上人,最后一页...... 打赏一点钱,帮我买包辣条,继续创作,谢谢大家! 大家关注微信公众号 罡罡同学 回复中国象棋 就可以免费获得压缩包啦!! 压缩包里面内 ...

最新文章

  1. squid,nginx,lighttpd反向代理的区别
  2. const和static readonly 区别
  3. pgsql,mysql case when
  4. 2.4.2 死锁的处理策略-预防死锁
  5. Mysql 和oracle的区别
  6. 排序算法之冒泡排序(C/C++)
  7. sox处理mp3_SoX 音频处理工具使用方法
  8. Linux内核驱动如何编写?我们先从字符驱动入门开始
  9. python-面向对向-实例方法的继承
  10. Fiddler笔记(3)接口测试
  11. 【POJ2888】Magic Bracelet Burnside引理+欧拉函数+矩阵乘法
  12. 《JSP程序设计》手机销售网
  13. linux 使用rpm命令安装和卸载软件的使用方法
  14. c语言语法错误标识符,error C2061: 语法错误: 标识符“std”
  15. 输入一行字符,分别统计出其中英文字母、空格、数字和其他字符的个数。
  16. 很重要,padding margin百分比按照父元素width作为参照物
  17. python 生成器、列表/字典/集合解析式区别
  18. LINUX内核内存屏障
  19. 什么是Cookie?怎样设置和读取Cookie?
  20. APP被工信部下架了怎么办?重新上架流程分享

热门文章

  1. JS实现延时3秒刷新
  2. 2019届华为秋招面试
  3. Find My资讯|苹果 Find My 找到因交通事故坠崖的一名女子
  4. 比 Navicat 还要好用,功能还很强大的数据库管理工具!
  5. 【迷失岛游戏框架开发个人每集总结(第三期)】
  6. 在 WPF 中使用 Prism DryIOC 加载应用程序时导航到默认视图
  7. 【UVA11478】Halum (最短路解差分约束)
  8. c语言other用法,初中英语other的用法介绍
  9. 密码学笔记1-信息安全的基本属性(机密性、认证、完整性、不可否认性)
  10. 十大排序算法(C++)(时间复杂度O(nlogn)篇:希尔排序、堆排序、快速排序、归并排序)