背景介绍

  因为之前用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 游戏相关推荐

  1. js canvas游戏初级demo-上下左右移动

    大概流程就是 监听状态变化 擦除画布 重绘 由于js监听时间变化的函数addEventListener只能达到每秒触发20次左右,也就是每秒20帧,看起来有点卡卡的 所以用定时器搞到每秒30帧 按上下 ...

  2. html5+php调用android手机图片,html5+exif.js+canvas+php实现手机上传图片,图片损坏无法打开...

    上传图片,图片损坏无法打开,图片路径也是正确的, function selectFileImage(fileObj) { var file = fileObj.files['0']; //图片方向角 ...

  3. php 设计五子棋游戏,基于js+canvas实现五子棋小游戏

    本文实例为大家分享了js+canvas实现五子棋小游戏的具体代码,供大家参考,具体内容如下 效果展示: 源码展示: 五子棋 * { margin: 0; padding: 0; } body { ma ...

  4. 五子棋人机对战_原生JS+Canvas实现五子棋游戏

    原生JS+Canvas实现五子棋游戏 效果图 主要功能模块为: 1.人机对战功能 2.悔棋功能 3.撤销悔棋功能 二.代码详解 2.1 人机对战功能实现 从效果图可以看到,棋盘的横竖可以放的位置为15 ...

  5. html五子棋悔棋,原生 JS + Canvas 实现五子棋游戏

    原标题:原生 JS + Canvas 实现五子棋游戏 || 一.功能模块 先看下现在做完的效果: 线上体验: https://wj704.github.io/five_game.html 主要功能模块 ...

  6. 使用原生JS+Canvas实现五子棋游戏

    布局+样式部分代码 : <style type='text/css'>canvas {display: block;margin: 50px auto;box-shadow: -2px - ...

  7. 打砖块小游戏php程序,利用原生js实现html5打砖块小游戏(代码示例)

    本篇文章给大家通过代码示例介绍一下利用原生js实现html5打砖块小游戏的方法.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. 前言 PS:本次项目中使用了大量 es6 语法,故对于 ...

  8. js小游戏——五子棋人机大战

    五子棋小游戏,可能会有bug请各位大佬多多指教 代码如下: css样式: canvas {display: block;margin: 50px auto;box-shadow: -2px -2px ...

  9. JS小游戏——五子棋

    制作流程: 绘制棋盘.棋子. 下棋及其基本需求--棋子不叠加,点击后棋子落在最近棋盘交叉点,黑白棋交替落点,棋面记录. 游戏胜负判断. 棋面清洗,实现重复游戏. HTML: <!DOCTYPE ...

最新文章

  1. 机器人科迪的天空_机器人科迪的天空游戏评测:我要跳的更高
  2. TJOI2018Party
  3. mysql 查询两张表结构相同的数据库_利用反射处理多个表结构相同的数据的查询和数据库表的关联...
  4. oracle大作业_最累人7大专业
  5. CentOS7下Nginx 安装 Lua 支持
  6. DIV+CSS常见问题的14条原因分享
  7. hdoj1116【欧拉回路】
  8. Easy-rules使用介绍
  9. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_06 Properties集合_2_Properties集合中的方法store...
  10. 计算机辅助英语教学电子版,计算机辅助英语教学探究.pdf
  11. python颜色识别demo
  12. 2022年电子商务概论(农)之形考作业三
  13. CAD卸载不干净不能重新安装(恶心死我了)
  14. 双系统切换后系统时间错乱问题解决
  15. 男人养肾按摩运动更可取
  16. 小甲鱼python入门笔记(三)
  17. 方框加对勾怎么输入_Word与Excel中,如何在方框中打对勾?
  18. mongo connect error no reachable servers
  19. 纯干货!视频控件VideoCapX的使用指南和常见问题合集
  20. 远程连接服务器软件——十大常见的服务器管理软件

热门文章

  1. FILE类型转换成String的方法
  2. OpenGL3.3-细分着色器
  3. SIGCOMM 历年最佳论文汇总Topic推荐-AMiner
  4. 极光推送ios证书配置
  5. 老友逢共话区块链落地,杭州首个区块链周首日精彩瞬间
  6. 软件项目客户迟迟不肯验收怎么办?
  7. 目3路考总结-海驾贴吧上的经验汇总
  8. 基于BP神经网络的手写数字识别
  9. ZOJ:P1127KKT数组404美人松的高度1
  10. 从本质(信号分析角度)理解卷积