基于javascript canvas实现五子棋游戏

 更新时间:2020年07月08日 08:37:32   作者:X W F  
这篇文章主要介绍了基于javascript canvas实现的五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了基于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>

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

C++经典小游戏汇总

python经典小游戏汇总

python俄罗斯方块游戏集合

JavaScript经典游戏 玩不停

javascript经典小游戏汇总

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

相关文章

  • js实现权限树的更新权限时的全选全消功能

    js实现权限树的更新权限时的全选全消功能

    上一篇发了添加权限时的权限树JS源码,下面把更新时的也发给大家借鉴一下,因为更新时候牵扯到判断已有权限等,所以,还要麻烦一些。
    2009-02-02
  • JavaScript中清空数组的方法总结

    JavaScript中清空数组的方法总结

    本文给大家总结了三种js清空数组的方法,每种方法都与众不同,非常不错,具有参考借鉴价值,感兴趣的朋友一起看看吧
    2016-12-12
  • 在js文件中写el表达式取不到值的原因及解决方法

    在js文件中写el表达式取不到值的原因及解决方法

    在js文件中写el表达式取不到值,百度一下,将经验总结如下,有类似情况的朋友可以参考下
    2013-12-12
  • 微信小程序实战之打卡时钟的绘制

    微信小程序实战之打卡时钟的绘制

    这篇文章主要介绍了如何利用微信小程序制作一个打卡时钟,分为工作和休息两种状态,用户可以设置相应的时间,所有的时钟记录都会被保存下来,感兴趣的可以了解一下
    2022-04-04
  • Ant Design Pro 下实现文件下载的实现代码

    Ant Design Pro 下实现文件下载的实现代码

    这篇文章主要介绍了Ant Design Pro 下实现文件下载的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • weakMap为什么是弱引用原理

    weakMap为什么是弱引用原理

    这篇文章主要为大家介绍了weakMap为什么是弱引用原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • 利用js+canvas实现扫雷游戏

    利用js+canvas实现扫雷游戏

    这篇文章主要为大家详细介绍了利用js+canvas实现扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • 一个JavaScript用逗号分割字符串实例

    一个JavaScript用逗号分割字符串实例

    分割字符串的方法有很多,这篇文章主要介绍了一个JavaScript用逗号分割字符串实例,需要的朋友可以参考下
    2014-09-09
  • uniapp实现全局设置字体大小(小中大的字体切换)

    uniapp实现全局设置字体大小(小中大的字体切换)

    随着UniApp的流行,越来越多的开发者选择使用它来构建跨平台应用程序,下面这篇文章主要给大家介绍了关于uniapp实现全局设置字体大小(小中大的字体切换)的相关资料,需要的朋友可以参考下
    2023-06-06
  • 自己编写的支持Ajax验证的JS表单验证插件

    自己编写的支持Ajax验证的JS表单验证插件

    创建一个JavaScript表单验证插件,可以说是一个繁琐的过程,涉及到初期设计、开发与测试等等环节。实际上一个优秀的程序员不仅是技术高手,也应该是善假于外物的。本文介绍的这个不错的JavaScript表单验证插件,支持ajax验证,有需要的小伙伴可以参考下
    2015-05-05

最新评论