使用canvas制作五子棋游戏
要制作JS五子棋的话我们可以一开始来理清一下思路,这样对我们后来的编程是有好处的
1、棋盘使用canvas制作。canvas用来做这种不用太过复杂的图形的时候是很有用处的,下图是我制作的一个五子棋棋盘
2、确定你是想做PC端的还是做移动端的
3、点击的棋子是放在棋盘上,还是另建一个canvas画布
对于这个问题,我选择了新建一个canvas画布,如果不新建的话,如果想有撤回按钮(我这边没放上去),不太好操作,因为使用API删除会不干净,所以我使用的是存下棋子数组,每一次下棋子,存入数组后,清空棋盘,重新绘制,那每次还要重新绘制一个棋盘,所以我把棋盘作为了一个固定的canvas。还有一点,棋盘的绘制,如果棋盘和canvas画布一样大小的话,下在最旁边的棋子是会有一部分看不见的,所以要么这个canvas大一部分,要么另起一个只放置棋子的画布。
HTML:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
- <meta name="viewport" content="target-densitydpi=320,width=640,user-scalable=no">
- <link rel="stylesheet" href="./CSS/reset.css">
- <link rel="stylesheet" href="./CSS/index.css">
- <script type="text/javascript">
- window.onresize = function () {
- resetPage();
- }
- function resetPage() {
- var deviceWidth = document.documentElement.clientWidth || document.body.clientWidth;
- var deviceHeight = document.documentElement.clientHeight || document.body.clientHeight;
- var scale = deviceWidth / 480;
- deviceHeight = deviceHeight / scale;
- document.body.style.zoom = scale;
- document.body.style.height = deviceHeight + 'px';
- }
- </script>
- <title>Document</title>
- </head>
- <body>
- <canvas id="canvas_0" width="560px" height="560px"></canvas>
- <canvas id="canvas_1" width="600px" height="600px"></canvas>
- <div id="shadowBox"></div>
- <div id="back1">后退</div>
- <div id="back2">后退</div>
- <script type="text/javascript" src="./JS/index.js"></script>
- </body>
- </html>
canvas_0是棋盘canvas
canvas_1是棋子canvas
shadowBox是外面的边框(可以优化到canvas_0里面去)
后退按钮做了,不过没有放上去,在JS中功能有做出来。
CSS
- #canvas_0 {
- box-sizing: border-box;
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- border: 1px solid black;
- background-color: #FFD75B;
- z-index:;
- }
- #canvas_1 {
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- z-index:;
- }
- #shadowBox{
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- border: 20px solid #FFD75B;
- }
- #back1{
- position: absolute;
- top: 10%;
- left: 50%;
- transform: translateX(-50%);
- width: 50px;
- height: 50px;
- line-height: 50px;
- border-radius: 50%;
- font-size: 20px;
- background-color: red;
- color: white;
- }
- #back2{
- position: absolute;
- bottom: 10%;
- left: 50%;
- transform: translateX(-50%);
- width: 50px;
- height: 50px;
- line-height: 50px;
- border-radius: 50%;
- font-size: 20px;
- background-color: red;
- color: white;
- }
这里面没有什么需要注意的,因为本身canvas里面的东西和CSS就没多大关系
JavaScript代码有很多,我分开讲
JS => 起始部分
- var Board = document.getElementById('canvas_0');
- var BoardToGraw = document.getElementById('canvas_1');
- var shadowBox = document.getElementById('shadowBox');
- var back = document.getElementById('back1');
- var back = document.getElementById('back2');
- var windowWidth = document.documentElement.clientWidth || document.body.clientWidth;//拿到当前浏览器可视宽度
- var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;//拿到当前浏览器可视高度
- Board.style.width = windowWidth * 0.9 + "px";//棋盘宽度为当前浏览器可视宽度的90%
- Board.style.height = windowWidth * 0.9 + "px";//棋盘高度为当前浏览器可视宽度的90%
- BoardToGraw.style.width = windowWidth * 0.9 + 40 + "px";//棋子canvas宽度为当前浏览器可视宽度的90% + 左右各20px
- BoardToGraw.style.height = windowWidth * 0.9 + 40 + "px";//棋子canvas高度为当前浏览器可视宽度的90% + 上下各20px
- shadowBox.style.width = windowWidth * 0.9 + "px";//边框宽度为当前浏览器可视宽度的90%
- shadowBox.style.height = windowWidth * 0.9 + "px";//边框高度为当前浏览器可视宽度的90%
JS => 棋盘部分
- var piecesList = [];//棋子数组
- // 15×15
- if (Board.getContext) {
- var ctx0 = Board.getContext('2d'); /*获取上下文,或者说绘制工具箱ctx*/
- /*1、构造函数*/
- var LineChart = function (ctx0) {
- /*获取绘图工具*/
- this.ctx0 = ctx0 || document.getElementById('canvas_0').getContext('2d');
- /*画布的大小*/
- this.canvasWidth = 560;//这里是算过了,560/14 = 20 , 每个格子20
- this.canvasHeight = 560;
- }
- /*2、行为方法 */
- LineChart.prototype.init = function () {
- this.drawGrid();
- // 画四个点
- let LineTotal = 13;
- let EmptyWidth = this.canvasWidth / (LineTotal + 1);
- this.DrawCircle(EmptyWidth * 3, EmptyWidth * 3, 5, "#000");
- this.DrawCircle(this.canvasWidth - EmptyWidth * 3, EmptyWidth * 3, 5, "#000");
- this.DrawCircle(EmptyWidth * 3, this.canvasHeight - EmptyWidth * 3, 5, "#000");
- this.DrawCircle(this.canvasWidth - EmptyWidth * 3, this.canvasHeight - EmptyWidth * 3, 5, "#000");
- }
- /*绘制网格*/
- LineChart.prototype.drawGrid = function () {
- /*x方向的线*/
- let LineTotal = 13;
- let EmptyWidth = this.canvasWidth / (LineTotal + 1);
- //画X轴方向
- for (let i = 0; i < LineTotal; i++) {
- this.ctx0.beginPath();
- this.ctx0.moveTo(0, EmptyWidth * (i + 1));
- this.ctx0.lineTo(this.canvasWidth, EmptyWidth * (i + 1));
- this.ctx0.strokeStyle = '#000';
- this.ctx0.closePath();
- this.ctx0.stroke();
- }
- /*y方向的线*/
- for (let i = 0; i < LineTotal; i++) {
- this.ctx0.beginPath();
- this.ctx0.moveTo(EmptyWidth * (i + 1), 0);
- this.ctx0.lineTo(EmptyWidth * (i + 1), this.canvasHeight);
- this.ctx0.strokeStyle = '#000';
- this.ctx0.closePath();
- this.ctx0.stroke();
- }
- }
- LineChart.prototype.DrawCircle = function (start, end, r, color) {
- this.ctx0.beginPath();
- this.ctx0.moveTo(start - r, end);
- this.ctx0.arc(start, end, r, 2 * Math.PI, 0, true);
- this.ctx0.strokeStyle = color;
- this.ctx0.closePath();
- this.ctx0.fillStyle = color;
- this.ctx0.fill();
- }
- var lineChart = new LineChart();
- lineChart.init();
- } else {
- console.log("error!!!");
- }
由于棋盘是14 × 14的,所以一共要画13条宽,13条高,其中棋盘宽高的1/14就是一个格子的宽度,我这边设置成了20
- if (BoardToGraw.getContext) {
- var ctx0 = BoardToGraw.getContext('2d'); /*获取上下文,或者说绘制工具箱ctx*/
- /*1、构造函数*/
- var LineChart2 = function (ctx0) {
- /*获取绘图工具*/
- this.ctx0 = ctx0 || document.getElementById('canvas_1').getContext('2d');
- /*画布的大小*/
- this.canvasWidth = 600;
- this.canvasHeight = 600;
- }
- //绘制整个棋子数组的函数
- LineChart2.prototype.DrawCircleList = function (circleList) {
- let r = 18;
- for(circle of circleList){
- this.ctx0.beginPath();
- this.ctx0.moveTo(circle.X * 40 + 20 - r, circle.Y);
- this.ctx0.arc(circle.X * 40 + 20, circle.Y * 40 + 20, r, 2 * Math.PI, 0, true);
- this.ctx0.strokeStyle = circle.color;
- this.ctx0.closePath();
- this.ctx0.fillStyle = circle.color;
- this.ctx0.fill();
- }
- }
- var LineChart2 = new LineChart2();
- } else {
- console.log("error!!!");
- }
棋子部分的canvas代码就很简单了,因为只需要获取棋子数组,然后画出来就OK,所以只有一个绘制函数
JS => 触摸事件部分,以左上角小黑点为例,写了很详细的注释
- BoardToGraw.addEventListener('click', (event) => {
- //每click一次,清除一次canvas,数组中添加当前棋子,重绘
- let x = event.offsetX;
- let y = event.offsetY;
- //棋子排位位置
- let rankingX, rankingY;
- //最终画出的位置
- let endX, endY;
- var data = {};//用于储存单个棋子信息
- var color = (piecesList.length % 2) == 1 ? "white" : "black";//从黑开始交替下子
- rankingX = Math.round((x - 20) / 40);//比如如果是左上角的小黑点位置的棋子,rankingX = 3
- rankingY = Math.round((y - 20) / 40);//比如如果是左上角的小黑点位置的棋子,rankingY = 3
- //rankingX,rankingY可能为-0
- rankingX == -0 ? rankingX = 0 : rankingX = rankingX;//如果是-0,转化为0
- rankingY == -0 ? rankingY = 0 : rankingY = rankingY;//如果是-0,转化为0
- endX = rankingX * 40 + 20;//真正应该画在的地方,endX = 140
- endY = rankingY * 40 + 20;//真正应该画在的地方,endY = 140
- //封装进piecesList的棋子排位对象
- data.X = rankingX;
- data.Y = rankingY;
- data.color = color;
- //data = {X:3,Y:3,color:"black"}
- for (pieces of piecesList) {//如果此次下的棋子位置与之前的棋子数组中的发生重复,那么退出这个函数
- if (pieces.X == data.X && pieces.Y == data.Y) {
- return;
- }
- }
- clearCanvas();//清除整个棋子canvas
- piecesList.push(data);//下棋成功,push进棋子数组
- LineChart2.DrawCircleList(piecesList);//将push后的棋子数组传入绘制函数
- checkFiveLink(piecesList);//重绘后,判断是否有胜利者。
- })
JS => 判断是否有胜利者
这里每次下棋只会判断当前棋子color的所有者会不会胜利,因为只有最后一个棋子,才有可能胜利,之前的棋子都是已经判断过的。
由于水平,垂直,倾斜的都可能成功连成五子,所以其实一共有8个方向 => 左、右、上、下、左下、左上、右下、右上。
而有可能我会下在两个棋子的中间,所以每次应该同时判断两个方向 => 左右、上下、左上及右下、左下及右上。
- //用于判断是否有五子相连的函数
- var checkFiveLink = function (piecesList) {
- let nowPrices = piecesList[piecesList.length - 1];
- let bolleanLr = lrCheck(piecesList, nowPrices);
- let bolleanTb = tbCheck(piecesList, nowPrices);
- let bolleanRtLb = rtLbCheck(piecesList, nowPrices);
- let bolleanLtRb = ltRbCheck(piecesList, nowPrices);
- if (bolleanLr || bolleanTb || bolleanRtLb || bolleanLtRb) {
- alert(`${nowPrices.color} : success !!!`);
- clearCanvas();
- }
- }
- //水平
- var lrCheck = function (piecesList, nowPrices) {
- var count = 1;
- var count2 = 1;
- //右
- for (let i = 0; i < 4; i++) {
- let obj = {};
- obj.X = nowPrices.X + i + 1;
- obj.Y = nowPrices.Y;
- obj.color = nowPrices.color;
- let staticNum = count;
- for (piece of piecesList) {
- if (piece.X == obj.X && piece.Y == obj.Y && piece.color == obj.color) {
- count++;
- }
- }
- if (staticNum == count) {
- break;
- }
- }
- for (let i = 0; i < 4; i++) {
- let obj = {};
- obj.X = nowPrices.X - i - 1;
- obj.Y = nowPrices.Y;
- obj.color = nowPrices.color;
- let staticNum = count2;
- for (piece of piecesList) {
- if (piece.X == obj.X && piece.Y == obj.Y && piece.color == obj.color) {
- count2++;
- }
- }
- if (staticNum == count2) {
- break;
- }
- }
- let Link = count + count2 - 1;
- if (Link >= 5) {
- return true;
- }
- else {
- return false;
- }
- }
- //竖直
- var tbCheck = function (piecesList, nowPrices) {
- var count = 1;
- var count2 = 1;
- //上
- for (let i = 0; i < 4; i++) {
- let obj = {};
- obj.X = nowPrices.X;
- obj.Y = nowPrices.Y + i + 1;
- obj.color = nowPrices.color;
- let staticNum = count;
- for (piece of piecesList) {
- if (piece.X == obj.X && piece.Y == obj.Y && piece.color == obj.color) {
- count++;
- }
- }
- if (staticNum == count) {
- break;
- }
- }
- for (let i = 0; i < 4; i++) {
- let obj = {};
- obj.X = nowPrices.X;
- obj.Y = nowPrices.Y - i - 1;
- obj.color = nowPrices.color;
- let staticNum = count2;
- for (piece of piecesList) {
- if (piece.X == obj.X && piece.Y == obj.Y && piece.color == obj.color) {
- count2++;
- }
- }
- if (staticNum == count2) {
- break;
- }
- }
- let Link = count + count2 - 1;
- if (Link >= 5) {
- return true;
- }
- else {
- return false;
- }
- }
- //右上至左下
- var rtLbCheck = function (piecesList, nowPrices) {
- var count = 1;
- var count2 = 1;
- //右上
- for (let i = 0; i < 4; i++) {
- let obj = {};
- obj.X = nowPrices.X + i + 1;
- obj.Y = nowPrices.Y + i + 1;
- obj.color = nowPrices.color;
- let staticNum = count;
- for (piece of piecesList) {
- if (piece.X == obj.X && piece.Y == obj.Y && piece.color == obj.color) {
- count++;
- }
- }
- if (staticNum == count) {
- break;
- }
- }
- for (let i = 0; i < 4; i++) {
- let obj = {};
- obj.X = nowPrices.X - i - 1;
- obj.Y = nowPrices.Y - i - 1;
- obj.color = nowPrices.color;
- let staticNum = count2;
- for (piece of piecesList) {
- if (piece.X == obj.X && piece.Y == obj.Y && piece.color == obj.color) {
- count2++;
- }
- }
- if (staticNum == count2) {
- break;
- }
- }
- let Link = count + count2 - 1;
- if (Link >= 5) {
- return true;
- }
- else {
- return false;
- }
- }
- //左上至右下
- var ltRbCheck = function (piecesList, nowPrices) {
- var count = 1;
- var count2 = 1;
- //左上
- for (let i = 0; i < 4; i++) {
- let obj = {};
- obj.X = nowPrices.X - i - 1;
- obj.Y = nowPrices.Y + i + 1;
- obj.color = nowPrices.color;
- let staticNum = count;
- for (piece of piecesList) {
- if (piece.X == obj.X && piece.Y == obj.Y && piece.color == obj.color) {
- count++;
- }
- }
- if (staticNum == count) {
- break;
- }
- }
- for (let i = 0; i < 4; i++) {
- let obj = {};
- obj.X = nowPrices.X + i + 1;
- obj.Y = nowPrices.Y - i - 1;
- obj.color = nowPrices.color;
- let staticNum = count2;
- for (piece of piecesList) {
- if (piece.X == obj.X && piece.Y == obj.Y && piece.color == obj.color) {
- count2++;
- }
- }
- if (staticNum == count2) {
- break;
- }
- }
- let Link = count + count2 - 1;
- if (Link >= 5) {
- return true;
- }
- else {
- return false;
- }
- }
JS = > 其他部分
- back1.addEventListener('click',(event)=>{
- backStep();
- })
- back2.addEventListener('click',(event)=>{
- backStep();
- })
- //清除canvas画布
- function clearCanvas() {
- var c = document.getElementById("canvas_1");
- c.height = c.height;
- }
- //后退一步
- function backStep() {
- var c = document.getElementById("canvas_1");
- c.height = c.height;
- piecesList.pop();
- LineChart2.DrawCircleList(piecesList);
- }
这个小网页我放在了我的服务器上,大家可以通过链接http://www.jobsofferings.cn/五子棋/index.html进行访问,谢谢大家
使用canvas制作五子棋游戏的更多相关文章
- 原生JS+Canvas实现五子棋游戏
一.功能模块 先看下现在做完的效果: 线上体验:https://wj704.github.io/five_game.html 主要功能模块为: 1.人机对战功能 2.悔棋功能 3.撤销悔棋功能 二.代 ...
- 用Canvas制作小游戏——贪吃蛇
今天呢,主要和小伙伴们分享一下一个贪吃蛇游戏从构思到实现的过程~因为我不是很喜欢直接PO代码,所以只copy代码的童鞋们请出门左转不谢. 按理说canvas与其应用是老生常谈了,可我在准备阶段却搜索不 ...
- 怎样用HTML5 Canvas制作一个简单的游戏
原文连接: How To Make A Simple HTML5 Canvas Game 自从我制作了一些HTML5游戏(例如Crypt Run)后,我收到了很多建议,要求我写一篇关于怎样利用HTML ...
- Vue+WebSocket+ES6+Canvas 制作「你画我猜」小游戏
Vue+WebSocket+ES6+Canvas 制作「你画我猜」小游戏 转载 来源:jrainlau 链接:https://segmentfault.com/a/1190000005804860 项 ...
- [译]怎样用HTML5 Canvas制作一个简单的游戏
这是我翻译自LostDecadeGames主页的一篇文章,原文地址:How To Make A Simple HTML5 Canvas Game. 下面是正文: 自从我制作了一些HTML5游戏(例如C ...
- 自定义View实现五子棋游戏
成功的路上一点也不拥挤,因为坚持的人太少了. ---简书上看到的一句话 未来请假三天顺带加上十一回家结婚,不得不说真是太坑了,去年婚假还有10天,今年一下子缩水到了3天,只能赶着十一办事了. 最近还在 ...
- Android实训案例(八)——单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局
Android实训案例(八)--单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局 阿法狗让围棋突然就被热议了,鸿洋大神也顺势出了篇五子棋单机游戏的视频,我看到了就像膜拜膜拜,就 ...
- 使用CocosSharp制作一个游戏 - CocosSharp中文教程
注:本教程翻译自官方<Walkthrough - Building a game with CocosSharp>,官方教程有很多地方说的不够详细,或者代码不全,导致无法继续,本人在看了G ...
- 用Canvas制作简单的画图工具
今天用Canvas制作了一个画图工具,非常简单,功能也不是很多,主要有背景网格,画线,画圆,画矩形和画圆角矩形,也用到了canvas的一些基本知识,在这里一一列举. 1.线段的绘制: 如何绘制真正的1 ...
随机推荐
- 鼠标右键新建Markdown文档
首先放一张github某项目中.md文件中的内容图片 Windows系统下,使用 Typora 软件来进入Markdown文档的编写非常容易,而且入门门槛非常的低 存在的问题: 习惯了使用Markdo ...
- OAuth2.0概念以及实现思路简介
一.什么是OAuth? OAuth是一个授权规范,可以使A应用在受限的情况下访问B应用中用户的资源(前提是经过了该用户的授权,而A应用并不需要也无法知道用户在B应用中的账号和密码),资源通常以REST ...
- Windows安装EMQ服务器(mqtt)
先去EMQ官网下载安装包 https://www.emqx.io/downloads#broker 注意:此处一定不能下错成企业版的,不然EMQ会由于缺少企业license无法启动服务 解压到任意路径 ...
- docker启动报错 (iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport
今天修改完docker宿主机的防火墙文件 vim /etc/sysconfig/iptables 停止容器再启动时 报如下错误 (iptables failed: iptables --wait -t ...
- SparkStreaming-Kafka集成
SparkStreaming-Kafka集成 参考链接: Spark Streaming + Kafka Integration Guide 文章基本是官方的翻译, 最多再加入了一小部分自己的思考在内 ...
- 数字任意组合 - gcd
链接:https://www.nowcoder.com/acm/contest/160/A来源:牛客网 题目描述有一个计数器,计数器的初始值为0,每次操作你可以把计数器的值加上a1,a2,...,an ...
- Windows10内嵌Ubuntu子系统初始化设置
第一次启动 重启ubuntu Since Windows 10 version 1803, closing all WSL terminal windows won't kill background ...
- python 找到项目使用的所有组件和版本
1.下载模块 pip3 install -i https://pypi.douban.com/simple pipreqs 2.生成文件 pipreqs ./ --encoding=utf-8
- Egret学习-TiledMap使用
环境说明: 引擎版本:5.2.4 Egret Wing 4.1.6 1.下载依赖,下载地址https://github.com/egret-labs/egret-game-library/tree/m ...
- [洛谷P4178] Tree (点分治模板)
题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\) \(n \leq 40000\) 算法 首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它 ...