基于javascript canvas实现五子棋游戏


Posted in Javascript onJuly 08, 2020

本文实例为大家分享了基于canvas的五子棋的具体代码,供大家参考,具体内容如下

第一部分:核心类Gobang

属性:

this.box = box; // 存放五子棋的容器
this.canvas = null; // 画布
this.ctx = null;
this.size = 600; // 棋盘大小
this.cellNum = 20; // 单行棋格数量
this.padding = this.size/this.cellNum; // padding值
this.cellSize = (this.size-this.padding*2)/this.cellNum; // 棋格大小
this.pieceSize = this.cellSize*3/4; // 棋子大小
this.color = ["black", "#aaa"]; // 棋子颜色
this.myPieceType = null; // 玩家棋子类型
this.aiPieceType = null; // 电脑棋子类型
this.myPieces = []; // 玩家累计棋子
this.aiPieces = []; // 电脑累计棋子
this.isMyTurn = true; // 先手
this.curPos = [this.cellNum/2-1, this.cellNum/2-1]; // 当前点击位置
this.timeId = null; // 定时器id

方法:

init// 初始化方法,获取canvas设置宽高,获取ctx
createChessboard// 创建背景棋盘
drawPiece// 画一个棋子
clearPiece// 清除棋子
registClick// 注册鼠标点击事件,主要的逻辑函数
isIn// 判断否在所下的棋子里面
isInAll// 判断是否在所有下的棋子里面
isFull// 是否下满
aiPutPiece// 电脑落子,只是简单的实现了,获取玩家落子位子周围一格的随机位置
putPiece// 实现下棋的函数
isWin// 胜利判断,个人人为比较男一点点的算法
run// 运行,类的入口函数,里面调用了,·init·/createChessBoard/registClick方法

第二部分:源代码

Gobang.js

/** 五子棋 **/

function Gobang(box){
  this.box = box; // 存放五子棋的容器
  this.canvas = null; // 画布
  this.ctx = null;
  this.size = 600; // 棋盘大小
  this.cellNum = 20; // 单行棋格数量
  this.padding = this.size/this.cellNum; // padding值
  this.cellSize = (this.size-this.padding*2)/this.cellNum; // 棋格大小
  this.pieceSize = this.cellSize*3/4; // 棋子大小
  this.color = ["black", "#aaa"]; // 棋子颜色
  this.myPieceType = null; // 玩家棋子类型
  this.aiPieceType = null; // 电脑棋子类型
  this.myPieces = []; // 玩家累计棋子
  this.aiPieces = []; // 电脑累计棋子
  this.isMyTurn = true; // 先手
  this.curPos = [this.cellNum/2-1, this.cellNum/2-1]; // 当前点击位置
  this.timeId = null; // 定时器id
  
  // 初始化方法
  this.init = function(){
    // 创建canvas
    this.canvas = document.createElement("canvas");
    // 设置宽高
    this.canvas.width = this.canvas.height = this.size;
    // 加入到容器中
    this.box.appendChild(this.canvas);
    // 获取ctx
    this.ctx = this.canvas.getContext("2d");
  };
  // 创建背景棋盘
  this.createChessboard = function(){
    // ----------- 边框 -----------
    this.ctx.lineWidth = 10;
    this.ctx.lineJoin = "round";
    this.ctx.strokeRect(0, 0, this.size, this.size);
    // ----------- 创建棋盘 -----------
    this.ctx.lineWidth = 1;
    for (var i = 0; i <= this.cellNum; i++) {
      // 画横线
      this.ctx.beginPath();
      this.ctx.moveTo(this.padding, this.padding+i*this.cellSize);
      this.ctx.lineTo(this.size-this.padding, this.padding+i*this.cellSize);
      this.ctx.stroke();
      // 画竖线
      this.ctx.beginPath();
      this.ctx.moveTo(this.padding+i*this.cellSize, this.padding);
      this.ctx.lineTo(this.padding+i*this.cellSize, this.size-this.padding);
      this.ctx.stroke();
    }
  };
  // 画一个棋子
  this.drawPiece = (x, y, type=0) => {
    // 根据坐标计算出图中位置
    var posX, posY;
    posX = this.padding + x * this.cellSize;
    posY = this.padding + y * this.cellSize;
    // 创建渐变色
    var grd = this.ctx.createRadialGradient(posX, posY, this.pieceSize/18, posX, posY, this.pieceSize);
    // type: 0, 黑棋 1, 白棋
    grd.addColorStop(0, this.color[1-type]);
    grd.addColorStop(0, this.color[type]);
    this.ctx.fillStyle = grd;
    // 画圆
    this.ctx.beginPath(); this.ctx.arc(posX, posY, this.pieceSize/2, 0, 2*Math.PI); this.ctx.fill();
  };
  // 清除棋子
  this.clearPiece = (x, y) => {
    // 清除棋子所在位置的像素
    var posX, posY;
    posX = this.padding + x * this.cellSize - this.pieceSize/2;
    posY = this.padding + y * this.cellSize - this.pieceSize/2;
    this.ctx.clearRect(posX, posY, this.pieceSize, this.pieceSize);
    // 补上十字架
    this.ctx.lineWidth = 1;
    // 竖线
    this.ctx.beginPath(); this.ctx.moveTo(posX+this.pieceSize/2, posY); this.ctx.lineTo(posX+this.pieceSize/2, posY+this.pieceSize); this.ctx.stroke();
    // 横线
    this.ctx.beginPath(); this.ctx.moveTo(posX, posY+this.pieceSize/2); this.ctx.lineTo(posX+this.pieceSize, posY+this.pieceSize/2); this.ctx.stroke();
  };
  // 注册鼠标点击事件
  this.registClick = function(){
    this.canvas.addEventListener("click", (ev) => {
      // 将位置坐标,转换为点
      var x = Math.round((ev.clientX - this.padding)/this.cellSize);
      x = x <= 0 ? 0 : x; x = x > this.cellNum ? this.cellNum : x;
      var y = Math.round((ev.clientY - this.padding)/this.cellSize);
      y = y <= 0 ? 0 : y; y = y > this.cellNum ? this.cellNum : y;
      // 设置当前位置
      this.curPos = [x, y];
      // 玩家落子
      if(this.isMyTurn && !this.isInAll(this.curPos)){ // 判断是否轮到玩家,并且下的位置是否重复
        this.putPiece(this.myPieces, this.curPos);
      }
      else return; // 轮到玩家的时候才能落子
      // 判断输赢
      if(this.isWin(this.myPieces)) {setTimeout(function(){alert("you win!");}, 100); return;}
      // 电脑落子
      this.aiPutPiece();
      // 判断输赢
      if(this.isWin(this.aiPieces)) {setTimeout(function(){alert("robot win!");}, 100); return;}
      this.isMyTurn = true;
    });
  };
  // 判断否在所下的棋子里面
  this.isIn = (pos, arr) => {
    var len = arr.length;
    for(var i=0; i < len; i++){
      if(pos[0] == arr[i][0] && pos[1] == arr[i][1]) return true;
    }
    return false;
  };
  // 判断是否在所有下的棋子里面
  this.isInAll = (pos) => {
    return this.isIn(pos, this.myPieces.concat(this.aiPieces));
  }
  // 是否下满
  this.isFull = () => {
    return (this.myPieces.length + this.aiPieces.length) == (this.cellNum+1) * (this.cellNum+1);
  };
  // 电脑落子
  this.aiPutPiece = ()=>{
    var x, y;
    // 目前,制作了一点功能,就是在玩家刚刚落子的周围一格落子
    // 1. 获得随机的周围的坐标
    while(1){
      x = this.curPos[0] + Math.pow(-1, parseInt(Math.random()*2));
      y = this.curPos[1] + Math.pow(-1, parseInt(Math.random()*2));
      if(x >=0 && x <=20 && y >= 0 && y <=20 && !this.isInAll([x, y])) break;
    }
    // 2. 落子
    this.putPiece(this.aiPieces, [x, y], 1);
  }
  // 实现下棋的函数
  this.putPiece = (pieces, pos, type=0) => {
    this.drawPiece(pos[0], pos[1], type);
    pieces.push(pos);
  }
  // 胜利判断
  this.isWin = (pieces) => {
    /* 
    * 这里不用遍历棋盘来判断四个方向,只需要判断当前落子位置的四个方向。
    */
    var x, y, count = 0;

    // 处在水平线上 判断 
    x = this.curPos[0]-1; y = this.curPos[1];
    while(1) if(this.isIn([x, y], pieces)) {count++; x--;} else break; // 左边
    x = this.curPos[0]+1; y = this.curPos[1];
    while(1) if(this.isIn([x, y], pieces)) {count++; x++;} else break; // 右边
    if(count >= 4) return true; else /** 左右匹配失败 **/ count = 0;
    
    // 处在垂直线上 判断 比较四次
    x = this.curPos[0]; y = this.curPos[1]-1;
    while(1) if(this.isIn([x, y], pieces)) {count++; y--;} else break; // 上边
    x = this.curPos[0]; y = this.curPos[1]+1;
    while(1) if(this.isIn([x, y], pieces)) {count++; y++;} else break; // 下边
    if(count >= 4) return true; else /** 上下匹配失败 **/ count = 0;

    // 处在左对角线上的判断
    x = this.curPos[0]-1; y = this.curPos[1]-1;
    while(1) if(this.isIn([x, y], pieces)) {count++; x--; y--;} else break; // 左上
    x = this.curPos[0]+1; y = this.curPos[1]+1;
    while(1) if(this.isIn([x, y], pieces)) {count++; x++; y++;} else break; // 右下
    if(count >= 4) return true; else /** 左对角线匹配失败 **/ count = 0;

    // 处在右对角线上的判断
    x = this.curPos[0]+1; y = this.curPos[1]-1;
    while(1) if(this.isIn([x, y], pieces)) {count++; x++; y--;} else break; // 右上
    x = this.curPos[0]-1; y = this.curPos[1]+1;
    while(1) if(this.isIn([x, y], pieces)) {count++; x--; y++;} else break; // 左下
    if(count >= 4) return true; else /** 右对角线匹配失败 **/ return false;
  };
  // 运行
  this.run = function(){
    // 初始化方法
    this.init();
    // 创建棋盘
    this.createChessboard();
    // 注册点击事件
    this.registClick();
  }
}

五子棋.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>06-五子棋</title>
  <script src="../gobang.js"></script>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
  </style>
</head>
<body>
  <div id="box"></div>
  <script>
    var box = document.getElementById("box");
    var gobang = new Gobang(box);
    gobang.run();
  </script>
</body>
</html>

更多有趣的经典小游戏实现专题,分享给大家:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
用js判断浏览器是否是IE的比较好的办法
May 08 Javascript
js获取时间并实现字符串和时间戳之间的转换
Jan 05 Javascript
js实现div模拟模态对话框展现URL内容
May 27 Javascript
纯JS打造网页中checkbox和radio的美化效果
Oct 13 Javascript
JS函数修改html的元素内容,及修改属性内容的方法
Oct 28 Javascript
JS switch判断 三目运算 while 及 属性操作代码
Sep 03 Javascript
mongoose设置unique不生效问题的解决及如何移除unique的限制
Nov 07 Javascript
VUE 全局变量的几种实现方式
Aug 22 Javascript
微信小程序API—获取定位的详解
Apr 30 Javascript
js实现页面图片消除效果
Mar 24 Javascript
Vue 按照创建时间和当前时间显示操作(刚刚,几小时前,几天前)
Sep 10 Javascript
JS精髓原型链继承及构造函数继承问题纠正
Jun 16 Javascript
深度解读vue-resize的具体用法
Jul 08 #Javascript
详解React 条件渲染
Jul 08 #Javascript
webpack5 联邦模块介绍详解
Jul 08 #Javascript
实例讲解React 组件
Jul 07 #Javascript
JavaScript eval()函数定义及使用方法详解
Jul 07 #Javascript
详解React 元素渲染
Jul 07 #Javascript
JS数据类型判断的几种常用方法
Jul 07 #Javascript
You might like
windows环境下php配置memcache的具体操作步骤
2013/06/09 PHP
php实现的SESSION类
2014/12/02 PHP
php继承中方法重载(覆盖)的应用场合
2015/02/09 PHP
iOS自定义提示弹出框实现类似UIAlertView的效果
2016/11/16 PHP
javascript实现的listview效果
2007/04/28 Javascript
javascript 限制输入和粘贴(IE,firefox测试通过)
2008/11/14 Javascript
jQuery实现炫酷的鼠标轨迹特效
2015/02/01 Javascript
jquery实现LED广告牌旋转系统图片切换效果代码分享
2015/08/26 Javascript
JS基于ocanvas插件实现的简单画板效果代码(附demo源码下载)
2016/04/05 Javascript
JS阻止事件冒泡行为和闭包的方法
2016/06/16 Javascript
jQuery实现底部浮动窗口效果
2016/09/07 Javascript
将html页面保存成图片,图片写入pdf的实现方法(推荐)
2016/09/17 Javascript
js eval函数使用,js对象和字符串互转实例
2017/03/06 Javascript
详解微信小程序 template添加绑定事件
2017/06/23 Javascript
bootstrap select下拉搜索插件使用方法详解
2017/11/23 Javascript
JS实现简单的浮动碰撞效果示例
2017/12/28 Javascript
基于Vuex无法观察到值变化的解决方法
2018/03/01 Javascript
微信小程序顶部导航栏可滑动并选中放大
2019/12/05 Javascript
微信小程序停止其他视频播放当前视频的实例代码
2019/12/25 Javascript
Vue 图片压缩并上传至服务器功能
2020/01/15 Javascript
Vue 列表页带参数进详情页的操作(router-link)
2020/11/13 Javascript
[00:59]DOTA2英雄背景故事——上古巨神
2020/06/28 DOTA
[01:07:15]DOTA2-DPC中国联赛 正赛 DLG vs XG BO3 第二场 1月25日
2021/03/11 DOTA
Python 通过微信控制实现app定位发送到个人服务器再转发微信服务器接收位置信息
2019/08/05 Python
Python turtle绘画象棋棋盘
2019/08/21 Python
python selenium循环登陆网站的实现
2019/11/04 Python
Django ORM 查询表中某列字段值的方法
2020/04/30 Python
Python urllib2运行过程原理解析
2020/06/04 Python
css3 线性渐变和径向渐变示例附图
2014/04/08 HTML / CSS
简单介绍CSS3中Media Query的使用
2015/07/07 HTML / CSS
公司承诺书格式
2014/05/21 职场文书
导游词之大雁塔景区
2019/09/17 职场文书
导游词之青城山景区
2019/09/27 职场文书
java设计模式--七大原则详解
2021/07/21 Java/Android
一文简单了解MySQL前缀索引
2022/04/03 MySQL
利用 Python 的 Pandas和 NumPy 库来清理数据
2022/04/13 Python