五子棋是规则简单明了的策略型游戏,先形成五子连线者获胜。
本课程习作采用两人在线对弈的方式进行比赛,拿着手机在上下班路上玩特别合适。

整个过程在众触低代码应用平台进行,使用表达式描述游戏逻辑(高度简化版JS)。
本课程重点学习websocket实时消息的发送与接收处理。

两人在线下棋演示

先动手玩一玩:https://gobang.zc-app.cn
因为是在线游戏,需要登录,可以用手机和邮箱分别注册,用电脑和手机自己跟自己玩。
URL后面加/z就进入开发模式:https://gobang.zc-app.cn/z

详尽的的教学请移步哔哩哔哩视频:【众触课程】五子棋_哔哩哔哩_bilibili

棋盘结构

$v.棋盘 = array(14, array(14, ""))

用嵌套数据组件使用14 * 14的二维数组渲染而成,即图中画黑线的格子。

方阵结构

$v.方阵 = array(15, array(15, ""))

用嵌套数据组件使用15 * 15的二维数组渲染而成,即图中黑线交叉的点,鼠标hover在组件上时高亮的圆圈。

棋手状态

undefined、邀请中、对方出棋、己方出棋
默认就是没有值,表示还没开始下棋或者结束了(胜负已分)。对方出棋的时候己方不能落子。

账号登录

既然是在线玩的,就要求登录。可以用手机或邮箱注册。
登录后马上打开连接,有玩家上线了,有玩家邀请了,对方落子了都是通过此连接socket即时通知的。

打开连接socket:onLogin

$socket.open($c.exp, { channels: ["比赛"], onOnline: true, onOffline: true, allowMultiLogin: true })

第一个参数$c.exp是个对象,可以包含onConnect, onData, onReconnect, onError,前两个是必须的。

第二个参数是option选项,channels数组里放你需关注的频道,onOnline表示有人上线时是否要通知到你,onOffline则是有人下线是要否通知,allowMultiLogin表示同一个账号能否能在多个地方登录而不强制前面登录的账号下线。

连上后:onConnect

$socket.onlines(["比赛"])
$v.onlines = $r.比赛.filter('$x !== $c.me._id')
$v.onlines.forEach('$user.get($x)')
render()

连上后查询一下关注"比赛"频道的在线玩家,排除自己后放到$v.onlines列表后依次获取用户信息。

消息格式

下面有多个on开头的表达式都是只收到socket消息。它们都有共同的格式:type是消息类型,x是消息体,from是消息发送人。消息接受人to和发送时间d在此案例中未使用到。

有人上线了:onOnline

$v.onlines.push(x)
$v.onlines = $v.onlines.unique()
$user.get(x)

把上线的人放入上面的$v.onlines中,并去重。

有人断线了:onOffline

$v.对手 === x ? alert("对方断线了") : ""
$v.onlines.splice($v.onlines.indexOf(x), 1)

断线了就把他/她从$v.onlines移除。如果刚好是正在跟你对弈的棋手则抛出一个警告通知。

收到数据后:onData

stopIf($c.me._id == from)
$c.exp[type].exc()
render()

先要排除是自己发出的数据,因为socket是广播消息的,自己也能收到。
然后再根据消息类型执行对应的表达式,可能的类型有:on被邀、on拒邀、on受邀、on落子。

当其他人登录时,【对手】右边的问号圆圈就会闪烁,点击它会弹出在线玩家列表,从中选择一个可发出对弈邀请。

发出对弈邀请

$socket.send($x, "on被邀", "邀请")
$v.状态 = "邀请中"
info("邀请已发出,请等待对方接受邀请")

收到消息:on被邀

stopIf($v.状态, '$socket.send(from, "on拒邀", "对方正在下棋")')
$user.get(from)
$v.对手 = from
$v.pop = "选棋子"

如果自己正在下棋就直接发出"on拒邀"消息,拒绝邀请。
获取对方用户信息,弹出模态窗口提示接受要是拒绝邀请。

收到消息:on拒邀

$v.状态 = undefined
warn(x || "对方拒绝你的邀请")

把前面的”邀请中“的状态置空,弹出对方发来的拒邀消息

选子

$v.己方 = "白" // "黑"
$c.exp.受邀.exc()

接受邀请:受邀

$socket.send($v.对手, "on受邀", $v.己方)
$v.方阵 = array(15, array(15, ""))
$v.pop = undefined
$v.对方 = ($v.己方 === "黑" ? "白" : "黑")
$v.状态 = "己方出棋"
info("请出棋")

给对方发送“on被邀“消息,捎上自己选的子。
清空方阵,准备出棋。

收到消息:on被邀

$v.方阵 = array(15, array(15, ""))
$v.对手 = from
$v.对方 = x
$v.己方 = (x === "黑" ? "白" : "黑")
$v.状态 = "对方出棋"
info("对方已接受邀请,请等待对方先出棋")

from是对手用户ID,x是对方选的子,自己就只能选另一种子了。

落子

stopIf($v.状态 !== "己方出棋" || $v.方阵[$parent.$index][$index] || $v.连续棋子.length > 4)
$v.落子点 = [$parent.$index, $index]
$socket.send($v.对手, "on落子", $v.落子点)
$("." + $v.己方 + "子声音").play()
$v.方阵[$parent.$index][$index] = $v.己方
$v.检查方向.forEach($c.exp.落_是否胜出)
$v.状态 = "对方出棋"

如果不是己方出棋的状态,或者落子位置不在方阵内,或者已经组成4个以上连续棋子都不可落子。
发出"on落子"消息,捎上刚才的落子点坐标轴。
播放落子声音,并把己方棋子放在方阵的落子点上,并通过动态类名发出光晕。

$v.落子点[0] === $parent.$index && $v.落子点[1] === $index ? "光晕" : ""

检查刚才的落子能否胜出。

检查胜出(形成五子连线)

要判断胜负只需落子时从落子点 [y, x] 以四种连线的正反方向分别查看,累计4个以上连续同色棋子为声。

$v.检查方向

[[[-1, 0],[1, 0]],[[0, -1],[0, 1]],[[1, -1],[-1, 1]],[[-1, -1],[1, 1]]
]

-1表示往后检查,0表示不动,1表示往前检查。比如[-1, 0]是是X轴上往负值方向检查,即正西方向;[1, -1]表示先往X轴正方向检查再往Y轴负方向检查,即东北方向。

落子是否胜出

$v.连续棋子 = [$v.落子点]
$l.方向 = $x[0]
$l.非连续 = false
$v.循环4次.forEach($c.exp.落_相邻同色)
$l.方向 = $x[1]
$l.非连续 = false
$v.循环4次.forEach($c.exp.落_相邻同色)
stopIf($v.连续棋子.length > 4, 'info(($v.状态 === "己方出棋" ? $v.己方 : $v.对方) + "子赢了"); $v.状态 = undefined;')

先把当前落子位置作为第一个连续棋子,先往$v.检查方向提供的一对方向的第一个方向试探移动4次(即循环4遍)看是否有相邻同色子,再往另一个方向也试探4次。
如果试探得到的$v.连续棋子大于4个,那当前落子方胜出。

检查与落子相邻的同色子

$l.y = $v.落子点[0] + $l.方向[0] * $x
$l.x = $v.落子点[1] + $l.方向[1] * $x
!$l.非连续 && $v.方阵[$l.y][$l.x] === ($v.状态 === "己方出棋" ? $v.己方 : $v.对方) ? $v.连续棋子.push([$l.y, $l.x]) : $l.非连续 = true

一个试探方向包括X轴方向和Y轴方向,有-1、0、1三种移法,分别移动一下坐标,检查新坐标在方阵中的棋子,如果坐标上有子,并且现在是己方出棋而且这个子正好是己方颜色,那这个子就是连续棋子的一部分。其它情况都不能算连续同色子,比如坐标上没有子,或者是对方的子,再或者是以前就已经非连续了,这次就没必要继续检查了。

胜出的连续5个棋子也要发出光晕。前面新落的子已经通过动态类名发出光晕,现在要找出连续棋子的其它棋子。

$v.连续棋子.length > 4 && $v.连续棋子.find('$x[0] === $ext.$parent.$index && $x[1] === $ext.$index') ? "光晕" : ""

我们从连续棋子里面找,看看里面是否有一个棋子的坐标跟当前检查的坐标位置相同。$x[0]是连续棋子X坐标,$x[1]是Y坐标。注意,这里是嵌套数据组件里作为动态类名的,$index是当前数据组件的下标,$parent.$index是上一层数据组件的下标。但由于它们是放在find()函数里面的,需要在前面添加$ext.表示它们函数外面上下文提供的数据,如果没有$ext.,那就成了find()函数提供给的上下文数据了。

准备深入研究的同学请到五子棋在线对弈页面后,点击右侧的【克隆】按钮,把整个游戏复制一份随意玩弄更改。

更多教学视频请移步哔哩哔哩空间:众触应用平台的个人空间_哔哩哔哩_Bilibili,里面不仅有各种前端可视化案例演示和讲解,还有多个完整功能的网站应用案例的开发过程演示和讲解。

从零开始完整开发基于websocket的在线对弈游戏【五子棋】,只用几十行代码完成全部逻辑。相关推荐

  1. 如何用GameMakerStudio开发基于物理引擎的平台游戏 | Lynda教程 中文字幕

    GameMakerStudio教程之如何用GML开发基于物理引擎的平台游戏 | Lynda教程 中文字幕 Building a Physics-Based Platformer in GameMake ...

  2. python 游戏开发框架_Python开发 基于python实现坦克大战游戏

    这篇文章主要为大家详细介绍了基于python实现坦克大战游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本文实例为大家分享了python实现坦克大战游戏的具体代码, ...

  3. 基于WebSocket的在线聊天室

    1.什么是WebSocket HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议.它基于TCP传输协议,并复用HTTP的握手通道.WebSocket是一种通信协议,可在单个 ...

  4. .NET Core 实现基于Websocket的在线聊天室

    什么是Websocket 我们在传统的客户端程序要实现实时双工通讯第一想到的技术就是socket通讯,但是在web体系是用不了socket通讯技术的,因为http被设计成无状态,每次跟服务器通讯完成后 ...

  5. websocket一直无法链接_.NET Core 实现基于Websocket的在线聊天室

    什么是Websocket 我们在传统的客户端程序要实现实时双工通讯第一想到的技术就是socket通讯,但是在web体系是用不了socket通讯技术的,因为http被设计成无状态,每次跟服务器通讯完成后 ...

  6. 用Unity开发基于Oculus Rift的体验游戏时遇到天空盒重影问题的解决方法

    大家好我是天睿Tera,目前专注于开发OculusRift沉浸式体验演示项目并且在建立一个开发者交流的论坛 www.vr-x.cn. 我会把在开发电梯惊魂DEMO的时候遇到的问题和怎么解决的拿出来给大 ...

  7. 前端实现俄罗斯方块小游戏1(在单人版基础上,实现基于websocket的双人版游戏)

    修改单机版游戏代码,并对其进行逻辑处理和初始化 更改单机版页面结构,实现用户进入后,单数用户显示需要等待另一个玩家,双数的客户进入后,可以开始游戏~ HTML中加入div remote.js中绑定按钮 ...

  8. 基于html的策略类游戏开发,基于HTML5的即时战略游戏的设计与实现

    摘要: 随着近年Html5技术的逐渐兴起,Web技术变得越来越强大,能做的事情也越来越多.以前Web技术主要运用在建设网站等方面,现在随着Canvas和WebGL技术的出现,越来越多的开发者开始运用H ...

  9. 基于HTML5的棋盘游戏开发,基于HTML5的网页围棋游戏的开发

    0引言从2008年1月22日,第一份HTML5草案公布后,HTML5作为一种下一代web标准的趋势,受到人们的广泛关注,各大浏览器厂商开始纷纷支持HTML5,目前,大多数的浏览器,如chrome.fi ...

最新文章

  1. 在.net中如何禁用或启用DropDownList的Items
  2. Crawler:爬虫之基于https+parse库实现爬取国内某知名招聘网上海、北京关于区块链职位的求职信息
  3. phpcms mysql配置文件_PhpCms系统设置:config.inc.php文件配置说明
  4. ad network
  5. Hello Blazor:(2)集成Tailwind CSS续——nuget包方式
  6. 万级 K8S 集群背后,etcd 如何保持稳定性?
  7. Swing 学习小记
  8. 1.13 编程基础之综合应用 10 判决素数个数 python
  9. 54 SD配置-定价配置-分配条件类型到条件排斥组
  10. 无限极业绩_2019中国保健品行业典型企业分析——无限极、康宝莱、汤臣倍健...
  11. IOS 创建渐变图层
  12. macos安装盘第三方工具制作_MacOS平台的磁盘镜像制作工具DMG Canvas for mac怎么样?...
  13. C++引用(作为函数参数和返回值)
  14. 如何对接VOLVO EDI系统?
  15. 阿辉DirectX 11学习笔记一
  16. 同学早已年薪百万 为何你却还在朋友圈集赞?
  17. 论文解读《ResRep: Lossless CNN Pruning via Decoupling Remembering and Forgetting》
  18. FastRule: Efficient Flow Entry Updates for TCAM-based OpenFlow Switches(一)
  19. Vue项目History模式404问题解决
  20. CS144课程实验详解-lab0-第一部分

热门文章

  1. 东北大学考研二叉树相关试题
  2. 计算机路由表更新命令,计算机cmd命令之route,查看路由表,或配置一个更有效的路由...
  3. 年、月、周、日数据统计
  4. 无法删除的软件,如何删除
  5. HyperMate Pro硬件钱包全体验
  6. 音画俱佳的极米H3S、NEW Z6X、Z6X Pro,电影爱好者不能错过的投影仪
  7. 笔仙 (惊悚,推理)
  8. CorelDraw插件开发-VBA-常用功能-添加1000个样例用户到安全组-cdr插件
  9. Laravel 5.0 框架查看执行过的SQL语句
  10. 我相信中国经济形势一片大好