五子棋小游戏(JS+Node+Websocket)可分房间对战
主要通过js、canvas、node、websocket来实现五子棋游戏。
tip:如果你想清楚的了解怎么实现,请一步步看思路流程,文章最后有项目的gitee地址、对应B站视频,可直接食用。
首先搭建一个express服务:
const express = require('express')
const path = require('path')
const app = express()
//静态资源目录
app.use(express.static(path.join(__dirname, 'public')));
let port = 3003
app.get('/home', (req, res, next) => {res.writeHead(200, { 'Content-type': 'text/html;charset=utf-8' })res.end('欢迎来到express')next()
})const server = app.listen(port, () => { console.log('成功启动express服务,端口号是' + port) })
这个时候我们可以访问静态文件里面的文件了,如:
public下面的index.html在访问3003/的时候在浏览器渲染。
这也说明了我们的node服务启动成功,接口在3003端口上。
前端页面,里面包括css\html但是不包括js,只是引入js文件:
<!-- 2021/5/15 -->
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><link rel="icon" type="image/jpg" href="./ipc.jpg"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>五子棋</title><style>* {padding: 0;margin: 0;}html,body {width: 100%;height: 100%;overflow: hidden;}canvas {margin-top: 200px;margin-left: 300px;background-color: rgb(213, 176, 146);display: inline-block;border-radius: 8px;border: 1px solid black;}.resultBox {position: absolute;text-align: center;top: 200px;left: 760px;width: 200px;height: 450px;/* background-color: #ccc; */background-color: rgb(213, 176, 146);color: 38px;line-height: 60px;font-weight: bold;}</style>
</head><body><div class="box"><canvas id="canvas"></canvas><div class="resultBox"><p class="redP">白旗已下0</p><p class="blackP">黑旗已下0</p><p class="resultP"></p></div></div><!-- 通过script的方式引入 soctke.io --><script defer crossorigin="anonymous"integrity="sha512-PU5S6BA03fRv1Q5fpwXjg5nlRrgdoguZ74urFInkbABMCENyx5oP3hrDzYMMPh3qdLdknIvrGj3yqZ4JuU7Nag=="src="https://lib.baomitu.com/socket.io/4.1.3/socket.io.js"></script>//低版本 不再使用<!-- <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script> --><script defer src="./wuziqi.js"></script>
</body></html>
1:生成棋盘
2:生成棋子
3:棋子落点
4:五子成线 ?赢 :输
流程:
1.页面:渲染完成,输入房间号
2.选择白棋 、 黑棋
3.选择白棋后先下 黑棋有了白棋才能下
4.一方胜利,游戏结束。
页面加载后开始连接服务器。 控制台打印连接成功。输入房间号。
房间号里面只能容纳两个人,多余的人为观众,不可控制器盘的棋子
棋盘构造函数
//线条构造函数//线条颜色 x yfunction Line(color, x, y) {this.color = color;this.x = xthis.y = y}//画横线Line.prototype.getXLine = function () {ctx.lineWidth = 1;ctx.beginPath();ctx.moveTo(0, this.y);ctx.lineTo(this.x, this.y);ctx.strokeStyle = this.color;ctx.closePath();ctx.fill();ctx.stroke();}//画竖线Line.prototype.getYLine = function () {ctx.lineWidth = 1;ctx.beginPath();ctx.moveTo(this.x, 0);ctx.strokeStyle = this.color;ctx.lineTo(this.x, this.y);ctx.closePath();ctx.fill();ctx.stroke();}//线条相隔大小 后面 num += flaglet num = 0//线条随机颜色数组// let colorsList = ["#33B5E5", "#0099CC", "#AA66CC", "#9933CC", "#99CC00", "#669900", "#FFBB33", "#FF8800", "#FF4444", "#CC0000"]//循环画线for (let i = 0; i <= canvas.width; i += flag) {// let colorx = colorsList[Math.floor(Math.random() * 10)]// let colory = colorsList[Math.floor(Math.random() * 10)]let colorx, colorycolorx = colory = 'black'getXLineArr.push(new Line(colorx, canvas.width, num))getYLineArr.push(new Line(colory, num, canvas.width))num += flag}//画横线getXLineArr.map(item => {item.getXLine()})//画竖线getYLineArr.map(item => {item.getYLine()})
棋子构造函数
function Chessman(x, y, color) {this.x = xthis.y = ythis.color = color
}
Chessman.prototype.update = function () {ctx.save();ctx.beginPath()ctx.fillStyle = this.color// 背景颜色为白色ctx.arc(this.x, this.y, 20, 0, Math.PI * 2, false)ctx.fill()ctx.closePath()
}
棋子落在棋盘
选择白棋 黑棋,每点击一次棋盘会进行判断是否是该你下棋子
//当前点击的坐标 相对于canvas的坐标let arr = [e.clientX - MarginLeftNum, e.clientY - MarginTopNum]//当前点击坐标到 棋盘 0,0 的距离// let newArrLong = Math.sqrt((0 - arr[0]) * (0 - arr[0]) + (0 - arr[1]) * (0 - arr[1]))//25let newArrLong = flag / 2newARR = []//循环判断当前点击坐标到哪个棋盘坐标的距离最短,棋子放置到该坐标点lineXAndlineYArr.map((item, index) => {let newArrLongA = Math.sqrt((item[0] - arr[0]) * (item[0] - arr[0]) + (item[1] - arr[1]) * (item[1] - arr[1]))if (newArrLongA <= newArrLong) {newARR = item; newArrLong = newArrLongA}})
//看能不能落子
//白if (redOrBlackFlag === 1) {if (blackOrRedChessman % 2 !== 0) {return false}console.log("%c当前点击棋子坐标:", "color:red;font-size:20px;", newARR)} else {//黑if (blackOrRedChessman % 2 == 0) {return false}console.log("%c当前点击棋子坐标:", "color:red;font-size:20px;", newARR)}
随后查看该点是否已经有了棋子
//判断该点是否已经有棋子let hasYesOrNo = JSON.stringify(hasChessmanArrList).includes(JSONstringify(newARR))if (!hasYesOrNo) {//没有的话加入棋子数组hasChessmanArrList.push(newARR)}else {alert('已经有棋子')return}
棋子落子后触发服务器棋子位子更新
//lineXAndlineYArrRed 白棋
//lineXAndlineYArrBlack 黑棋
//lineXAndlineYArrBlack 黑棋
//blackOrRedChessman 棋子数量
const sendItemsArr = JSON.stringify({ lineXAndlineYArrRed, lineXAndlineYArrBlack, hasChessmanArrList, blackOrRedChessman })mySocket.emit('sendItemsArr', sendItemsArr)
服务器派发另一个人更新棋子位置
websocketObj.on('sendItemsArr', (sendItemsArr) => {itemsArr = sendItemsArr//触发所以的 sendFunEventCallBack 事件 让前端监听io.sockets.emit("getItemsArr", itemsArr);})
前端接受最新的棋子位置:
//websocket
mySocket.on('getItemsArr', (getItemsArr) => {const ItemsArr = JSON.parse(getItemsArr)lineXAndlineYArrRed = ItemsArr.lineXAndlineYArrRedlineXAndlineYArrBlack = ItemsArr.lineXAndlineYArrBlackhasChessmanArrList = ItemsArr.hasChessmanArrListblackOrRedChessman = ++ItemsArr.blackOrRedChessman// 判断这次点击棋子颜色//生成棋子 放置棋盘中lineXAndlineYArrRed.map(i => {new Chessman(i[0], i[1], color1).update()})lineXAndlineYArrBlack.map(i => {new Chessman(i[0], i[1], color2).update()})//改变页面上的信息redP.innerHTML = '白旗已下' + lineXAndlineYArrRed.lengthblackP.innerHTML = '黑旗已下' + lineXAndlineYArrBlack.length
})
再而判断下的这枚棋子,白棋或者黑棋棋子是否已经有了五个:
//判断棋子数量是否已经大于5 没到5 决对赢不了的 ~if (newlineXAndlineYArr.length >= 5) {//向右向左倾斜判断、横向纵向判断leftRightFangXiang()// //向右倾斜function leftRightFangXiang() {// 深拷贝一份数据let newlineXAndlineYArrR = JSON.parse(JSON.stringify(newlineXAndlineYArr))let newRightArrList = []for (let i = 0; i < 5; i++) {//xif (1) {newRightArrList = []for (let j = 0; j < i; j++) {newRightArrList.push([newARR[0] - flag * (j + 1), newARR[1]])}for (let k = i; k < 4; k++) {newRightArrList.push([newARR[0] + flag * (k - i + 1), newARR[1]])}if (rightOrRight(newRightArrList, newlineXAndlineYArrR, newARR) == 'win') {console.log("%c横向赢了哦~", "color:red;font-size:30px;");break}}//yif (1) {newRightArrList = []for (let j = 0; j < i; j++) {newRightArrList.push([newARR[0], newARR[1] - flag * (j + 1)])}for (let k = i; k < 4; k++) {newRightArrList.push([newARR[0], newARR[1] + flag * (k - i + 1)])}if (rightOrRight(newRightArrList, newlineXAndlineYArrR, newARR) == 'win') {console.log("%c纵向赢了哦~", "color:red;font-size:30px;");break}}// //左下 // 前 + - 张俊卿 - +if (1) {newRightArrList = []for (let j = 0; j < i; j++) {newRightArrList.push([newARR[0] + flag * (j + 1), newARR[1] - flag * (j + 1)])}for (let k = i; k < 4; k++) {newRightArrList.push([newARR[0] - flag * (k - i + 1), newARR[1] + flag * (k - i + 1)])}if (rightOrRight(newRightArrList, newlineXAndlineYArrR, newARR) == 'win') {console.log("%c左下赢了哦~", "color:red;font-size:30px;");break}}//右下 // 前 - - 张俊卿 + + 后if (1) {newRightArrList = []for (let j = 0; j < i; j++) {newRightArrList.push([newARR[0] - flag * (j + 1), newARR[1] - flag * (j + 1)])}for (let k = i; k < 4; k++) {newRightArrList.push([newARR[0] + flag * (k - i + 1), newARR[1] + flag * (k - i + 1)])}if (rightOrRight(newRightArrList, newlineXAndlineYArrR, newARR) == 'win') {console.log("%c右下赢了哦~", "color:red;font-size:30px;");break}}}}}
胜利
**有5个连成了一条线,服务器更新棋子位置 **
//初始化函数mySocket.emit('clearItemsArr')
node
websocketObj.on('clearItemsArr', () => {let clearItemsArr = JSON.parse(itemsArr)clearItemsArr.lineXAndlineYArrRed = []clearItemsArr.lineXAndlineYArrBlack = []clearItemsArr.hasChessmanArrList = []clearItemsArr.blackOrRedChessman = 0// websocketObj.emit('getItemsArr',itemsArr )//触发所以的 sendFunEventCallBack 事件 让前端监听io.sockets.emit("clearItemsArrAll", JSON.stringify(clearItemsArr));})
前端接受重置位置,页面重置:
//websocket
mySocket.on('clearItemsArrAll', (getItemsArr) => {const ItemsArr = JSON.parse(getItemsArr)lineXAndlineYArrRed = ItemsArr.lineXAndlineYArrRedlineXAndlineYArrBlack = ItemsArr.lineXAndlineYArrBlackhasChessmanArrList = ItemsArr.hasChessmanArrListblackOrRedChessman = ++ItemsArr.blackOrRedChessman//赢了resultP.innerHTML = blackOrRedChessman % 2 == 0 ? '黑棋子方胜利' : '白棋子方胜利'var r = window.confirm(resultP.innerHTML + ",是否重新开始!");if (r == true) {redP.innerHTML = '白旗已下0'blackP.innerHTML = '黑旗已下0'againInit()}
})
重置画布:
//重新开始
function againInit() {// window.history.go(0)//横线对象数组getXLineArr = []//竖线对象数组getYLineArr = []//偶数白色 基数 黑色blackOrRedChessman = 0//所有棋子数组hasChessmanArrList = []//坐标点数组//白旗坐标数组lineXAndlineYArrRed = []//黑棋坐标数组lineXAndlineYArrBlack = []ctx.clearRect(0, 0, canvas.width, canvas.height)init()
}
主要是使用html、js、node、websocket完成了一个可以分多个房间的双人五子棋游戏,其他人可以观战。
git地址:
五子棋分房间双人战斗
- git clone https://gitee.com/zhang745929987/gobang-room-two-fight.git
- cd 进去 npm i
- node或者nodemon test.js
完整代码在git上,有兴趣可以玩一玩,提出一些改进意见。
B站视频
javascript五子棋讲解
javascript五子棋演示
演示:
五子棋小游戏(JS+Node+Websocket)可分房间对战相关推荐
- 前端实现五子棋小游戏2(AI实现人机对战)
通过一个简单的算法,来实现AI智能对弈的五子棋小游戏 AI难点解析 赢法数组 赢法的统计数组 判断胜负 计算机的落子规则 代码实现 赢法数组 赢法种类的索引 横线赢法 竖线赢法 横线赢法 斜线赢法 反 ...
- 【Verilog】基于FPGA的五子棋小游戏(VGA显示、双人对战、胜负判别、附完整代码)
基于FPGA的五子棋小游戏 有一些说明: 1.本文是基于VGA的显示小游戏,主要为VGA显示的拓展应用: 2.为适应不同显示屏的分辨率,棋盘确定为10X10的黑线白底的方格: 3.下棋主要用棋格颜色变 ...
- Android Studio实现五子棋小游戏
项目目录 一.项目概述 二.开发环境 三.详细设计 1.布局设计 2.验证码 3.AI人机 4.背景音乐 四.运行演示 五.项目总结 六.源码获取 一.项目概述 五子棋是一种两人对弈的策略型棋类游戏, ...
- php 设计五子棋游戏,基于js+canvas实现五子棋小游戏
本文实例为大家分享了js+canvas实现五子棋小游戏的具体代码,供大家参考,具体内容如下 效果展示: 源码展示: 五子棋 * { margin: 0; padding: 0; } body { ma ...
- js实现五子棋小游戏
试玩 试玩网址:http://42.194.221.6:8014/ 效果 html及js <!DOCTYPE html> <html lang="en">& ...
- php五子棋,JS实现五子棋小游戏
这次给大家带来JS实现五子棋小游戏,JS实现五子棋小游戏的注意事项有哪些,下面就是实战案例,一起来看一下. 思路: 1.先用canvas画五子棋的棋盘 2.获取鼠标点击的位置 3.根据鼠标点击的位置判 ...
- JavaScript id_JavaScript实现五子棋小游戏_javascript技巧
更新时间:2020年10月26日 11:39:33 作者:布伽思索 这篇文章主要为大家详细介绍了JavaScript实现五子棋小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴 ...
- 基于flask的五子棋小游戏
基于flask的五子棋小游戏 前言 首先说明一下,本人方向是java后端,只因老师布置了一个作业,要用flask来做一个五子棋,没办法被逼上梁山,程序不太美观,但是应付作业还是够了的. 废话不 ...
- 前端实现五子棋小游戏1(本地双人对战)
运用canvas写一个本地五子棋小游戏 HTML部分 JS 部分 CSS 部分 实现效果 HTML部分 <!DOCTYPE html> <html lang="en&quo ...
- Java编写的五子棋小游戏
看书的时候看到一个不完整的Java编写的一个五子棋小游戏,为了恢复一下编程能力刚刚把这个小程序完成了. 实现的功能很简单,两人对下五子棋,程序自动回判断输赢.在ubuntu下搞得,没有装什么高端的输入 ...
最新文章
- 回望2018,展望2019
- 【JavaScript】 Webpack安装及文件打包
- 统计函数——汇总统计时间类数据
- audio 上一首 下一首 自定义样式_总有一首网易云,藏着你忘不掉的人。
- 服务器删除网站文章,如何一次性删除wordpress所有文章
- python函数注释,参数后面加冒号:,函数后面的箭头→是什么?
- Delphi动态数组详解
- 小a的计算器(牛客签到题A)-简单模拟
- 微信小程序——云服务环境的配置
- unity读取Text
- java.util接口_Java 8中java.util.function包中的谓词和使用者接口
- C++ STL 初步介绍01
- 目标检测论文阅读:Multi-scale Location-aware Kernel Representation for Object Detection(CVPR2018)
- jQuery版三级联动案例
- 对天敏电视精灵I老版播放器的修改和分析
- 【软件测试】学习路线资料整理摆脱迷茫,突破瓶颈(送给我迷茫的朋友)
- OS-练习题(10~13)
- 今日错题(10.6)
- 如何选择合适的CDN加速合作?关键在于这三个方面!
- idea项目相关错误与常用操作教程