[教你做小游戏] 用86行代码写一个联机五子棋WebSocket后端

本文介绍了如何使用86行代码实现一个基于WebSocket的联机五子棋后端服务。通过需求分析、技术选型(选择WebSocket而非Http轮询或长轮询)、流程说明以及具体实现方案(采用daphne作为ASGI实现),展示了从创建房间、玩家连接、下棋交互到前端逻辑的配合。作者HullQin分享了完整的源码,并邀请读者关注其更多游戏开发技术分享。
摘要由CSDN通过智能技术生成

我是HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,发送加微信,交个朋友),转发本文前需获得作者HullQin授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费没广告。还开发了《Dice Crush》参加Game Jam 2022。喜欢可以关注我 HullQin 噢~我有空了会分享做游戏的相关技术。

背景

上篇文章《用177行代码写个体验超好的五子棋》,我们一起用177行代码实现了一个本地对战的五子棋游戏。

现在,如果我们要做一个联机五子棋,怎么办呢?

需求分析

首先,我们需要一个后端服务。2个不同的玩家,一起连接这个后端服务,把要下的棋告诉后端,后端再转发给另一个玩家即可。当然,如果有观战的,也要把当前期局转发给观战者。

此外,为了让2个玩家联机,还需要有「房间号」的概念,只有同一个房间的人才能联机对战。不同房间的人互不影响,允许同时有多个房间的人同时玩游戏。

流程

整个通信流程是这样的:

  1. 玩家A请求进入房间1。玩家A会执黑棋。
  2. 玩家B请求进入房间1。玩家B会执白棋。此时人已满,其他人进入将观战。
  3. 玩家C请求进入房间1。玩家C是观战者。
  4. 玩家A请求下棋,告诉坐标给服务器。
  5. 服务器通知玩家B、玩家C,告诉大家A下棋的坐标。
  6. 玩家B请求下棋,告诉坐标给服务器。
  7. 服务器通知玩家A、玩家C,告诉大家B下棋的坐标。

之后循环4-7步骤。

为了简化后端逻辑,把逻辑判断都放在前端。例如在前端判断是否游戏结束(五联珠),如果游戏结束,前端不允许再发任何请求。

技术选型

协议与方案

因为涉及到服务器主动给用户发送数据,所以有几种可选方案:

  • Http轮询:若在等待对方下棋,则前端每隔1s就发送一条请求,看看对方是否下棋。
  • Http长轮询:若在等待对方下棋,则前端每隔1s就发送一条请求,看看对方是否下棋。但是后台不会立即返回结果,要等到接口超过某个时间才返回结果。
  • WebSocket:建立好浏览器、服务器的连接,可随时主动向浏览器推送数据。

这里我们选择WebSocket,因为这种场景下Http协议确实有很大的资源浪费。而WebSocket虽然实现起来有点难度,但是节约了资源。

具体实现方案

只要某个编程语言/框架可以支持WebSocket就可以。

因为我以前经常用Django,用过Channels,对它的底层依赖daphne有所了解,所以我直接选择了daphne。它是ASGI标准的一种实现。

daphne是一个非常轻量的选择,不像Django+Channels这套框架提供了很重的解决方案。daphne只提供了基础的ASGI实现,没有其它冗余的功能。就好比:我开发五子棋前端时,使用了SVG + Dom API,没有用React框架一样。

开发

基础知识

daphne要求我们以这样的格式定义一个服务:

# server.py
async def application(scope, receive, send):
    # 处理websocket协议
    if scope['type'] == 'websocket':
        # 先接收第一个包,必须是建立连接的包(connect),否则拒绝服务
        event = await receive()
        if event['type'] != 'websocket.connect':
            return
        # 校验通过,发送accept,表明建立ws连接成功
        await send({
   'type': 'websocket.accept'})
        # 此后双方可以互相随时发消息。开启个无限循环
        while True:
            # 接收一个包
            event = await receive()
            # 如果是断开连接的请求,就结束循环
            if event['type'] == 'websocket.disconnect':
                break
            # 这种方式可以读取包的文本内容
            data = event['text']
            # 这种方式可以发送一个包给浏览器,这里是把浏览器发来的包原封不动传回去
            await send({
   'type': 'websocket.send', 'text': data})
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hull Qin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值