基于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下写一个事件队列操作函数
Jul 19 Javascript
基于jquery的lazy loader插件实现图片的延迟加载[简单使用]
May 07 Javascript
关于javascript event flow 的一个bug详解
Sep 17 Javascript
一个简单的jQuery计算器实现了连续计算功能
Jul 21 Javascript
浅谈JavaScript中定义变量时有无var声明的区别
Aug 18 Javascript
关于JS中prototype的理解
Sep 07 Javascript
JavaScript 对象详细整理总结
Sep 29 Javascript
Angular.Js的自动化测试详解
Dec 09 Javascript
js时间戳与日期格式之间相互转换
Dec 11 Javascript
Vue中的无限加载vue-infinite-loading的方法
Apr 08 Javascript
JavaScript实现的开关灯泡点击切换特效示例
Jul 08 Javascript
关于element-ui表单中限制输入纯数字的解决方式
Sep 08 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
晶体管来复再生式二管收音机
2021/03/02 无线电
解析php类的注册与自动加载
2013/07/05 PHP
php 批量添加多行文本框textarea一行一个
2014/06/03 PHP
WordPress开发中的get_post_custom()函数使用解析
2016/01/04 PHP
ThinkPHP实现图片上传操作的方法详解
2017/05/08 PHP
Javascript this指针
2009/07/30 Javascript
autoPlay 基于jquery的图片自动播放效果
2011/12/07 Javascript
jQuery布局插件UI Layout简介及使用方法
2013/04/03 Javascript
JavaScript提高性能知识点汇总
2016/01/15 Javascript
从零学习node.js之文件操作(三)
2017/02/21 Javascript
jQuery 实现鼠标画框并对框内数据选中的实例代码
2017/08/29 jQuery
小程序点击图片实现自动播放视频
2020/05/29 Javascript
JS实现获取自定义属性data值的方法示例
2018/12/19 Javascript
js实现金山打字通小游戏
2020/07/24 Javascript
jquery实现简易验证插件封装
2020/09/13 jQuery
Js跳出两级循环方法代码实例
2020/09/22 Javascript
[01:10]3.19DOTA2发布会 三代刀塔人第一代
2014/03/25 DOTA
[00:36]DOTA2勇士令状莱恩声望物品——冥晶之厄展示
2018/05/25 DOTA
python类定义的讲解
2013/11/01 Python
零基础写python爬虫之抓取百度贴吧并存储到本地txt文件改进版
2014/11/06 Python
PyQt5利用QPainter绘制各种图形的实例
2017/10/19 Python
将pandas.dataframe的数据写入到文件中的方法
2018/12/07 Python
Python生成器的使用方法和示例代码
2019/03/04 Python
在Python中如何传递任意数量的实参的示例代码
2019/03/21 Python
html5配合css3实现带提示文字的输入框(摆脱js)
2013/03/08 HTML / CSS
html5 更新图片颜色示例代码
2014/07/29 HTML / CSS
HTML5在手机端实现视频全屏展示方法
2020/11/23 HTML / CSS
COS美国官网:知名服装品牌
2019/04/08 全球购物
乌克兰第一的珠宝网上商店:Gold.ua
2019/11/29 全球购物
Marlies Dekkers内衣荷兰官方网店:荷兰奢侈内衣品牌
2020/03/27 全球购物
给同学的道歉信
2014/01/16 职场文书
小学教师读书活动总结
2014/07/08 职场文书
关于感恩的素材句子(38句)
2019/11/11 职场文书
详解 TypeScript 枚举类型
2021/11/02 Javascript
「睡美人」爱洛公主粘土人开订
2022/03/22 日漫
Java界面编程实现界面跳转
2022/06/16 Java/Android