HTML5 五子棋 - JS/Canvas 游戏
因为之前用c#的winform中的gdi+,java图形包做过五子棋,所以做这个逻辑思路也就驾轻就熟,然而最近想温故html5的canvas绘图功能(公司一般不用这些),所以做了个五子棋,当然没参考之前的客户端代码,只用使用之前计算输赢判断算法和电脑AI(网络借取)的算法,当然现在html5做的五子棋百度一下非常多,但是自己实现一边总归是好事情,好了废话不多说了进入正题。^_^
目前界面功能:
主界面包含
1:人人、人机对战选项 2:棋子外观选择 3:棋盘背景选择 4:棋盘线条颜色选择
游戏界面包含
1:玩家名称 2:玩家棋子 3:当前由谁下棋背景定位 4:玩家比分 5:功能菜单区域(重新开始和无限悔棋) 6:棋盘区域 7.胜利后连环棋子连接 8.最后下棋位置闪烁显示 9.光标定位
游戏结束界面
1:胜利背景图 2:胜利玩家姓名 3:继续下一把按钮
可增加功能
1.返回主界面 2.保存棋局和相关数据 3.读取棋局和相关数据 4.交换角色 5.网络对战(2台机器)6.双方思考总时间记录
http://sandbox.runjs.cn/show/pl3fyuy4 (注意:没有加棋子图片下载提示,如果使用仿真棋子,出现下棋为空,请等待棋子图片下载完毕)
整体设计
下棋流程:玩家or电脑AI下棋 ---> 绘制棋子 ---> 设定棋子二维坐标值 ----> logic(逻辑判断) ----> (玩家)一方五子连环 ---> 获胜界面
↑ |
| ↓
<--------------------------------------------------------------------------------------------没有五子
悔棋流程(人人对战):一方玩家悔棋 ----> 弹出下棋记录堆栈并设定为它是最后一枚棋 ---> 清除最后一枚棋子图像 ---> 清除棋子二维坐标值---> 重新定位显示最后下棋位置并闪烁
悔棋流程(人机对战):玩方悔棋 ----> 弹出下棋记录堆栈2次,设定上一次电脑为最后一枚棋 ---> 清除弹出的2次记录图像 ---> 清除棋子2个棋子二维坐标值---> 重新定位显示最后下棋位置并闪烁
主代码介绍
主代码分为二块: 1.界面逻辑块 2.游戏主体块 (界面与游戏代码分离,逻辑清晰,分工明确)
模拟事件通知:游戏主体逻辑块,每次结果都会通知到界面层来进行交互(类似于c#或者java的委托或事件)
界面逻辑代码
1 <script type="text/javascript"> 2 var gb = null; 3 var infoboj = document.getElementsByClassName("info")[0]; 4 var pl1obj = document.getElementById("pl1"); 5 var pl2obj = document.getElementById("pl2"); 6 var plname1obj = document.getElementById("plname1"); 7 var plname2obj = document.getElementById("plname2"); 8 var chesstypeobj = document.getElementsByName("chesstype"); 9 var chesscolorobj = document.getElementsByName("chesscolor"); 10 var chessbgObj = document.getElementsByName("chessbg"); 11 var winerpnl = document.getElementById("winer"); 12 document.getElementById("startgame").addEventListener("click", function() { 13 14 function initParams() { 15 var chessTypeValue = 1; 16 if (chesstypeobj.length > 0) { 17 for (var i = 0; i < chesstypeobj.length; i++) { 18 if (chesstypeobj[i].checked) { 19 chessTypeValue = chesstypeobj[i].value; 20 break; 21 } 22 } 23 } 24 var linevalue = ""; 25 if (chesscolorobj.length > 0) { 26 for (var i = 0; i < chesscolorobj.length; i++) { 27 if (chesscolorobj[i].checked) { 28 linevalue = chesscolorobj[i].value; 29 break; 30 } 31 } 32 } 33 var bcorimgvalue = ""; 34 if (chessbgObj.length > 0) { 35 for (var i = 0; i < chessbgObj.length; i++) { 36 if (chessbgObj[i].checked) { 37 bcorimgvalue = chessbgObj[i].value; 38 break; 39 } 40 } 41 } 42 return { 43 lineColor: linevalue, 44 chessType: chessTypeValue, //1 色彩棋子 2 仿真棋子 45 playAName: plname1Input.value, 46 playBName: plname2Input.value, 47 backColorORImg: bcorimgvalue, 48 playAImg: "http://sandbox.runjs.cn/uploads/rs/62/nbqodq5i/playA.png", 49 playBImg: "http://sandbox.runjs.cn/uploads/rs/62/nbqodq5i/playB.png", 50 playerBIsComputer:openComputer.checked 51 }; 52 } 53 document.getElementById("cc").style.display = "block"; 54 gb = new gobang(initParams()); 55 /** 56 * 设置一些界面信息 57 * @param {Object} opt 58 */ 59 gb.info = function(opt) { 60 infoboj.style.visibility = "visible"; 61 document.getElementsByClassName("startpnl")[0].style.visibility = "hidden"; 62 plname1obj.innerHTML = opt.playAName; 63 plname2obj.innerHTML = opt.playBName; 64 if (opt.chessType == 1) { 65 var span1 = document.createElement("span"); 66 pl1obj.insertBefore(span1, plname1obj); 67 var span2 = document.createElement("span"); 68 pl2obj.insertBefore(span2, plname2obj); 69 } else { 70 var img1 = document.createElement("img"); 71 img1.src = opt.playAImg; 72 pl1obj.insertBefore(img1, plname1obj); 73 var img2 = document.createElement("img"); 74 img2.src = opt.playBImg; 75 pl2obj.insertBefore(img2, plname2obj); 76 } 77 } 78 /** 79 * 每次下棋后触发事件 80 * @param {Object} c2d 81 */ 82 gb.operate = function(opt, c2d) { 83 if (!c2d.winer || c2d.winer <= 0) { 84 pl1obj.removeAttribute("class", "curr"); 85 pl2obj.removeAttribute("class", "curr"); 86 if (c2d.player == 1) { 87 pl2obj.setAttribute("class", "curr"); 88 } else { 89 pl1obj.setAttribute("class", "curr"); 90 } 91 document.getElementById("backChessman").innerHTML="悔棋("+c2d.canBackTimes+")"; 92 } else { 93 var winname = c2d.winer == 1 ? opt.playAName : opt.playBName; 94 var str = "恭喜,【" + winname + "】赢了!" 95 alert(str); 96 winerpnl.style.display = "block"; 97 document.getElementById("winerName").innerHTML = "恭喜,【" + winname + "】赢了!"; 98 document.getElementById("pl" + c2d.winer).style.backgroundColor = "pink"; 99 document.getElementById("scoreA").innerHTML = c2d.playScoreA; 100 document.getElementById("scoreB").innerHTML = c2d.playScoreB; 101 } 102 } 103 gb.start(); 104 }); 105 106 document.getElementById("openComputer").addEventListener("change", function() { 107 if (this.checked) { 108 plname2Input.value = "电脑"; 109 plname2Input.disabled = "disabled"; 110 } else { 111 plname2Input.value = "玩家二"; 112 plname2Input.disabled = ""; 113 } 114 }); 115 116 //document.getElementById("openComputer").checked="checked"; 117 118 //重新开始 119 function restartgui() { 120 if (gb) { 121 winerpnl.style.display = "none"; 122 pl1obj.removeAttribute("class", "curr"); 123 pl2obj.removeAttribute("class", "curr"); 124 document.getElementById("pl1").style.backgroundColor = ""; 125 document.getElementById("pl2").style.backgroundColor = ""; 126 gb.restart(); 127 } 128 }; 129 </script>
游戏主体代码块(只包含函数声明代码)
// ========== // =name:gobang 游戏 // =anthor:jasnature // =last modify date:2016-04-13 // ========== (function(win) {var gb = function(option) {var self = this,canObj = document.getElementById("cc"),can = canObj.getContext("2d");self.contextObj = canObj;self.context = can;if (!self.context) {alert("浏览器不支持html5");return;};self.Opt = {lineColor: "green",chessType: 1, //1 色彩棋子 2 仿真棋子playAName: "play1",playBName: "play2",playAColor: "red",playBColor: "blue",playAImg: "img/playA.png",playBImg: "img/playB.png",backColorORImg: "default",playerBIsComputer: false};self.operate;//合并属性for (var a in option) {//console.log(opt[a]);self.Opt[a] = option[a];};//私有变量var my = {};my.enableCalcWeightNum = false; //显示AI分数my.gameover = false;//棋盘相关my.baseWidth = 30;my.lastFocusPoint = {}; //鼠标最后移动到的坐标点,计算后的my.cw = self.contextObj.offsetWidth; //棋盘宽my.ch = self.contextObj.offsetHeight; //高my.xlen = Math.ceil(my.cw / my.baseWidth); //行数my.ylen = Math.ceil(my.ch / my.baseWidth); //列my.chessRadius = 14; //棋子半径my.playerBIsComputer = false; //棋手B是否是电脑my.ComputerThinking = false; //电脑是否在下棋my.goBackC2dIsComputer = false; //最后下棋是否为电脑 my.switcher = 1; //由谁下棋了 1-a 2-b or computermy.winer = -1; //赢家,值参考my.switchermy.playScoreA = 0;my.playScoreB = 0;//x,y 正方形数量(20*20)my.rectNum = my.xlen;//存储已下的点my.rectMap = [];my.NO_CHESS = -1; //没有棋子标识my.goBackC2d = {}; //最后下的数组转换坐标my.downChessmanStackC2d = []; // 记录已下棋子的顺序和位置,堆栈 my.focusFlashInterval = null; //焦点闪烁线程my.focusChangeColors = ["red", "fuchsia", "#ADFF2F", "yellow", "purple", "blue"];my.eventBinded = false;my.currChessBackImg = null;my.currChessAImg = null;my.currChessBImg = null;my.currDrawChessImg = null;my.ChessDownNum = 0; //2个玩家 下棋总数/*** 开始游戏*/self.start = function() {};/*** 重新开始游戏*/self.restart = function() {};/*** 悔棋一步 ,清棋子,并返回上一次参数*/self.back = function() {}/*** 初始化一些数据*/function init() {}// self.paint = function() {// // //window.requestAnimationFrame(drawChessboard);// };/*** 游戏逻辑*/function logic(loc, iscomputer) {};/*** 判断是否有玩家胜出* @param {Object} c2d*/function isWin(c2d) {return false;}/*** 连接赢家棋子线* @param {Object} points*/function joinWinLine(points) {}/*** 画棋盘*/function drawChessboard() {};/*** 画棋子* @param {Object} loc 鼠标点击位置*/function drawChessman(c2d) {}function drawRect(lastRecord, defColor) {}/*** 闪烁最后下棋点*/function flashFocusChessman() {}/*** 清棋子* @param {Object} c2d*/function clearChessman() {}/*** @param {Object} loc* @return {Object} I 二维数组横点(),J二维数组纵点,IX 横点起始坐标,JY纵点起始坐标,player 最后下棋玩, winer 赢家*/function calc2dPoint(loc) {var txp = Math.floor(loc.x / my.baseWidth),typ = Math.floor(loc.y / my.baseWidth)dxp = txp * my.baseWidth, dyp = typ * my.baseWidth;loc.I = txp;loc.J = typ;loc.IX = dxp;loc.JY = dyp;return loc;}my.isChangeDraw = true;/*** 位置移动光标* @param {Object} loc*/function moveFocus(loc) {}/*** 绑定事件*/function bindEvent() {if (!my.eventBinded) {self.contextObj.addEventListener("touchstart", function(event) {//console.log(event);var touchObj = event.touches[0];eventHandle({s: "touch",x: touchObj.clientX - this.offsetLeft,y: touchObj.clientY - this.offsetTop})});self.contextObj.addEventListener("click", function(event) {//console.log("click event"); eventHandle({s: "click",x: event.offsetX,y: event.offsetY})});self.contextObj.addEventListener("mousemove", function(event) {//console.log("mousemove event"); moveFocus({x: event.offsetX,y: event.offsetY});});my.eventBinded = true;}function eventHandle(ps) {if (!my.gameover && !my.ComputerThinking) {logic(ps);if (my.playerBIsComputer && my.switcher == 2) {my.ComputerThinking = true;var pp = AI.analysis(my.goBackC2d.I, my.goBackC2d.J);logic({I: pp.x,J: pp.y}, true);my.ComputerThinking = false;}}event.preventDefault();event.stopPropagation();return false;}}};win.gobang = gb;})(window);
玩家OR电脑胜出算法
/*** 判断是否有玩家胜出* @param {Object} c2d*/function isWin(c2d) {//四个放心计数 竖 横 左斜 右斜var hcount = 0,vcount = 0,lbhcount = 0,rbhcount = 0,temp = 0;var countArray = [];//左-1for (var i = c2d.I; i >= 0; i--) {temp = my.rectMap[i][c2d.J];if (temp < 0 || temp !== c2d.player) {break;}hcount++;countArray.push({I: i,J: c2d.J});}//右-1for (var i = c2d.I + 1; i < my.rectMap.length; i++) {temp = my.rectMap[i][c2d.J];if (temp < 0 || temp !== c2d.player) {break;}hcount++;countArray.push({I: i,J: c2d.J});}if (countArray.length < 5) {countArray = [];//上-2for (var j = c2d.J; j >= 0; j--) {temp = my.rectMap[c2d.I][j];if (temp < 0 || temp !== c2d.player) {break;}vcount++;countArray.push({I: c2d.I,J: j});}//下-2for (var j = c2d.J + 1; j < my.rectMap[c2d.I].length; j++) {temp = my.rectMap[c2d.I][j];if (temp < 0 || temp !== c2d.player) {break;}vcount++;countArray.push({I: c2d.I,J: j});}}if (countArray.length < 5) {countArray = [];//左上for (var i = c2d.I, j = c2d.J; i >= 0, j >= 0; i--, j--) {if (i < 0 || j < 0) break;temp = my.rectMap[i][j];if (temp < 0 || temp !== c2d.player) {break;}lbhcount++;countArray.push({I: i,J: j});}//右下if (c2d.I < my.rectMap.length - 1 && c2d.I < my.rectMap[0].length - 1) {for (var i = c2d.I + 1, j = c2d.J + 1; i < my.rectMap.length, j < my.rectMap[0].length; i++, j++) {if (i >= my.rectMap.length || j >= my.rectMap.length) break;temp = my.rectMap[i][j];if (temp < 0 || temp !== c2d.player) {break;}lbhcount++;countArray.push({I: i,J: j});}}}if (countArray.length < 5) {countArray = [];//右上for (var i = c2d.I, j = c2d.J; i < my.rectMap.length, j >= 0; i++, j--) {if (i >= my.rectMap.length || j < 0) break;temp = my.rectMap[i][j];if (temp < 0 || temp !== c2d.player) {break;}rbhcount++;countArray.push({I: i,J: j});}//左下if (c2d.I >= 1 && c2d.J < my.rectMap[0].length - 1) {for (var i = c2d.I - 1, j = c2d.J + 1; i > 0, j < my.rectMap[0].length; i--, j++) {if (j >= my.rectMap.length || i < 0) break;temp = my.rectMap[i][j];if (temp < 0 || temp !== c2d.player) {break;}rbhcount++;countArray.push({I: i,J: j});}}}if (hcount >= 5 || vcount >= 5 || lbhcount >= 5 || rbhcount >= 5) {my.winer = c2d.player;my.gameover = true;joinWinLine(countArray);return true;}return false;}
算法简介:主要思路是搜索最后落下棋子的位置(二维坐标)计算 米 字形线坐标,看是否有连续5个或以上棋子出现。
连接赢家棋子线
/*** 连接赢家棋子线* @param {Object} points*/function joinWinLine(points) {points.sort(function(left, right) {return (left.I + left.J) > (right.I + right.J);});var startP = points.shift();var endP = points.pop();var poffset = my.baseWidth / 2;can.strokeStyle = "#FF0000";can.lineWidth = 2;can.beginPath();var spx = startP.I * my.baseWidth + poffset,spy = startP.J * my.baseWidth + poffset;can.arc(spx, spy, my.baseWidth / 4, 0, 2 * Math.PI, false);can.moveTo(spx, spy);var epx = endP.I * my.baseWidth + poffset,epy = endP.J * my.baseWidth + poffset;can.lineTo(epx, epy);can.moveTo(epx + my.baseWidth / 4, epy);can.arc(epx, epy, my.baseWidth / 4, 0, 2 * Math.PI, false);can.closePath();can.stroke();}
算法简介:根据赢家返回的连子位置集合,做坐标大小位置排序,直接使用lineto 连接 第一个棋子和最后一个
坐标换算
/*** 坐标换算* @param {Object} loc* @return {Object} I 二维数组横点(),J二维数组纵点,IX 横点起始坐标,JY纵点起始坐标,player 最后下棋玩, winer 赢家*/function calc2dPoint(loc) {var txp = Math.floor(loc.x / my.baseWidth),typ = Math.floor(loc.y / my.baseWidth)dxp = txp * my.baseWidth, dyp = typ * my.baseWidth;loc.I = txp;loc.J = typ;loc.IX = dxp;loc.JY = dyp;return loc;}
算法简介:这个比较简单,根据每个格子的宽度计算出实际坐标
电脑AI主要代码(修改来源于网络)
/*** AI棋型分析 */AI.analysis = function(x, y) {//如果为第一步则,在玩家棋周围一格随机下棋,保证每一局棋第一步都不一样if (my.ChessDownNum == 1) {return this.getFirstPoint(x, y);}var maxX = 0,maxY = 0,maxWeight = 0,i, j, tem;for (i = BOARD_SIZE - 1; i >= 0; i--) {for (j = BOARD_SIZE - 1; j >= 0; j--) {if (my.rectMap[i][j] !== -1) {continue;}tem = this.computerWeight(i, j, 2);if (tem > maxWeight) {maxWeight = tem;maxX = i;maxY = j;}if (my.enableCalcWeightNum) {can.clearRect(i * 30 + 2, j * 30 + 2, 24, 24);can.fillText(maxWeight, i * 30 + 5, j * 30 + 15, 30);}}}return new Point(maxX, maxY);};//下子到i,j X方向 结果: 多少连子 两边是否截断AI.putDirectX = function(i, j, chessColor) {var m, n,nums = 1,side1 = false, //两边是否被截断side2 = false;for (m = j - 1; m >= 0; m--) {if (my.rectMap[i][m] === chessColor) {nums++;} else {if (my.rectMap[i][m] === my.NO_CHESS) {side1 = true; //如果为空子,则没有截断 }break;}}for (m = j + 1; m < BOARD_SIZE; m++) {if (my.rectMap[i][m] === chessColor) {nums++;} else {if (my.rectMap[i][m] === my.NO_CHESS) {side2 = true;}break;}}return {"nums": nums,"side1": side1,"side2": side2};};//下子到i,j Y方向 结果AI.putDirectY = function(i, j, chessColor) {var m, n,nums = 1,side1 = false,side2 = false;for (m = i - 1; m >= 0; m--) {if (my.rectMap[m][j] === chessColor) {nums++;} else {if (my.rectMap[m][j] === my.NO_CHESS) {side1 = true;}break;}}for (m = i + 1; m < BOARD_SIZE; m++) {if (my.rectMap[m][j] === chessColor) {nums++;} else {if (my.rectMap[m][j] === my.NO_CHESS) {side2 = true;}break;}}return {"nums": nums,"side1": side1,"side2": side2};};//下子到i,j XY方向 结果AI.putDirectXY = function(i, j, chessColor) {var m, n,nums = 1,side1 = false,side2 = false;for (m = i - 1, n = j - 1; m >= 0 && n >= 0; m--, n--) {if (my.rectMap[m][n] === chessColor) {nums++;} else {if (my.rectMap[m][n] === my.NO_CHESS) {side1 = true;}break;}}for (m = i + 1, n = j + 1; m < BOARD_SIZE && n < BOARD_SIZE; m++, n++) {if (my.rectMap[m][n] === chessColor) {nums++;} else {if (my.rectMap[m][n] === my.NO_CHESS) {side2 = true;}break;}}return {"nums": nums,"side1": side1,"side2": side2};};AI.putDirectYX = function(i, j, chessColor) {var m, n,nums = 1,side1 = false,side2 = false;for (m = i - 1, n = j + 1; m >= 0 && n < BOARD_SIZE; m--, n++) {if (my.rectMap[m][n] === chessColor) {nums++;} else {if (my.rectMap[m][n] === my.NO_CHESS) {side1 = true;}break;}}for (m = i + 1, n = j - 1; m < BOARD_SIZE && n >= 0; m++, n--) {if (my.rectMap[m][n] === chessColor) {nums++;} else {if (my.rectMap[m][n] === my.NO_CHESS) {side2 = true;}break;}}return {"nums": nums,"side1": side1,"side2": side2};};/*** 计算AI下棋权重 * chessColor 玩家1为玩家2为AI*/AI.computerWeight = function(i, j, chessColor) {//基于棋盘位置权重(越靠近棋盘中心权重越大)var weight = 19 - (Math.abs(i - 19 / 2) + Math.abs(j - 19 / 2)),pointInfo = {}; //某点下子后连子信息//x方向pointInfo = this.putDirectX(i, j, chessColor);weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, true); //AI下子权重pointInfo = this.putDirectX(i, j, chessColor - 1);weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, false); //player下子权重//y方向pointInfo = this.putDirectY(i, j, chessColor);weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, true); //AI下子权重pointInfo = this.putDirectY(i, j, chessColor - 1);weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, false); //player下子权重//左斜方向pointInfo = this.putDirectXY(i, j, chessColor);weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, true); //AI下子权重pointInfo = this.putDirectXY(i, j, chessColor - 1);weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, false); //player下子权重//右斜方向pointInfo = this.putDirectYX(i, j, chessColor);weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, true); //AI下子权重pointInfo = this.putDirectYX(i, j, chessColor - 1);weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, false); //player下子权重return weight;};//权重方案 活:两边为空可下子,死:一边为空//其实还有很多种方案,这种是最简单的AI.weightStatus = function(nums, side1, side2, isAI) {var weight = 0;switch (nums) {case 1:if (side1 && side2) {weight = isAI ? 15 : 10; //一 }break;case 2:if (side1 && side2) {weight = isAI ? 100 : 50; //活二} else if (side1 || side2) {weight = isAI ? 10 : 5; //死二 }break;case 3:if (side1 && side2) {weight = isAI ? 500 : 200; //活三} else if (side1 || side2) {weight = isAI ? 30 : 20; //死三 }break;case 4:if (side1 && side2) {weight = isAI ? 5000 : 2000; //活四} else if (side1 || side2) {weight = isAI ? 400 : 100; //死四 }break;case 5:weight = isAI ? 100000 : 10000; //五break;default:weight = isAI ? 500000 : 250000;break;}return weight;};
AI分析:这个只是最简单的算法,其实很简单,计算每个没有下棋坐标的分数,也是按照 米 字形 计算,计算格子8个方向出现的 一个棋子 二个棋子 三个棋子 四个棋子,其中还分为是否被截断,其实就是边缘是否被堵死。
其实这个AI算法后续还有很多可以优化,比如 断跳 二活 其实就是2个交叉的 活二 , 因为是断掉的所以没有纳入算法权重计算,如果加入这个算法,估计很难下赢电脑了。
如符号图:
* *
* *
空位
下这里
因为不是连续的,所有没有纳入。
http://jasnature.github.io/gobang_html5/
有兴趣的可以下载修改并提交代码进来^_^
转载于:https://www.cnblogs.com/NatureSex/p/5390145.html
HTML5 五子棋 - JS/Canvas 游戏相关推荐
- js canvas游戏初级demo-上下左右移动
大概流程就是 监听状态变化 擦除画布 重绘 由于js监听时间变化的函数addEventListener只能达到每秒触发20次左右,也就是每秒20帧,看起来有点卡卡的 所以用定时器搞到每秒30帧 按上下 ...
- html5+php调用android手机图片,html5+exif.js+canvas+php实现手机上传图片,图片损坏无法打开...
上传图片,图片损坏无法打开,图片路径也是正确的, function selectFileImage(fileObj) { var file = fileObj.files['0']; //图片方向角 ...
- php 设计五子棋游戏,基于js+canvas实现五子棋小游戏
本文实例为大家分享了js+canvas实现五子棋小游戏的具体代码,供大家参考,具体内容如下 效果展示: 源码展示: 五子棋 * { margin: 0; padding: 0; } body { ma ...
- 五子棋人机对战_原生JS+Canvas实现五子棋游戏
原生JS+Canvas实现五子棋游戏 效果图 主要功能模块为: 1.人机对战功能 2.悔棋功能 3.撤销悔棋功能 二.代码详解 2.1 人机对战功能实现 从效果图可以看到,棋盘的横竖可以放的位置为15 ...
- html五子棋悔棋,原生 JS + Canvas 实现五子棋游戏
原标题:原生 JS + Canvas 实现五子棋游戏 || 一.功能模块 先看下现在做完的效果: 线上体验: https://wj704.github.io/five_game.html 主要功能模块 ...
- 使用原生JS+Canvas实现五子棋游戏
布局+样式部分代码 : <style type='text/css'>canvas {display: block;margin: 50px auto;box-shadow: -2px - ...
- 打砖块小游戏php程序,利用原生js实现html5打砖块小游戏(代码示例)
本篇文章给大家通过代码示例介绍一下利用原生js实现html5打砖块小游戏的方法.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. 前言 PS:本次项目中使用了大量 es6 语法,故对于 ...
- js小游戏——五子棋人机大战
五子棋小游戏,可能会有bug请各位大佬多多指教 代码如下: css样式: canvas {display: block;margin: 50px auto;box-shadow: -2px -2px ...
- JS小游戏——五子棋
制作流程: 绘制棋盘.棋子. 下棋及其基本需求--棋子不叠加,点击后棋子落在最近棋盘交叉点,黑白棋交替落点,棋面记录. 游戏胜负判断. 棋面清洗,实现重复游戏. HTML: <!DOCTYPE ...
最新文章
- 机器人科迪的天空_机器人科迪的天空游戏评测:我要跳的更高
- TJOI2018Party
- mysql 查询两张表结构相同的数据库_利用反射处理多个表结构相同的数据的查询和数据库表的关联...
- oracle大作业_最累人7大专业
- CentOS7下Nginx 安装 Lua 支持
- DIV+CSS常见问题的14条原因分享
- hdoj1116【欧拉回路】
- Easy-rules使用介绍
- 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_06 Properties集合_2_Properties集合中的方法store...
- 计算机辅助英语教学电子版,计算机辅助英语教学探究.pdf
- python颜色识别demo
- 2022年电子商务概论(农)之形考作业三
- CAD卸载不干净不能重新安装(恶心死我了)
- 双系统切换后系统时间错乱问题解决
- 男人养肾按摩运动更可取
- 小甲鱼python入门笔记(三)
- 方框加对勾怎么输入_Word与Excel中,如何在方框中打对勾?
- mongo connect error no reachable servers
- 纯干货!视频控件VideoCapX的使用指南和常见问题合集
- 远程连接服务器软件——十大常见的服务器管理软件