【从零开始学Skynet】实战篇《球球大作战》(十三):场景代码设计(下)

这篇具有很好参考价值的文章主要介绍了【从零开始学Skynet】实战篇《球球大作战》(十三):场景代码设计(下)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、主循环

        《球球大作战》是一款服务端运算的游戏,一般会使用主循环程序结构,让服务端处理战斗逻辑。如下图所示,图中的 balls foods代表服务端的状态,在循环中执行 食物生成”“位置更新碰撞检 测” 等功能,从而改变服务端的状态。 scene 启动后,会开启定时器,每隔一段时间(0.2 秒)执行一次循环,在循环中会处理食物生成、位置更新等功能。
【从零开始学Skynet】实战篇《球球大作战》(十三):场景代码设计(下)

 service/scene/init.lua中新增的内容:

function update(frame)
    food_update()
    move_update()
    eat_update()
    --碰撞略
    --分裂略
end

         现在思考一个问题,怎样开启稳定的定时器?可以开启一个死循环协程,协程中调用update,最后用skynet.sleep让它等待一小段时间。定义服务初始化方法init

s.init = function()
    skynet.fork(function()
        --保持帧率执行
        local stime = skynet.now()
        local frame = 0
        while true do
            frame = frame + 1
            local isok, err = pcall(update, frame)
            if not isok then
                skynet.error(err)
            end
            local etime = skynet.now()
            local waittime = frame*20 - (etime - stime)
            if waittime <= 0 then
                waittime = 2
            end
            skynet.sleep(waittime)
        end
    end)
end
  • 它会调用skynet.fork开启一个协程,协程的代码位于匿名函数中。
  • pcall是为安全调用update而引入的,它的功能可以参照前面的xpcall
  • waittime 代表每次循环后需等待的时间。
  • 由于程序有可能卡住,我们很难保证“ 每隔 0.2 秒调用一次 update” 是精确的。
  • update 方法也需要一定的执行时间,等待时间waittime 的实际值应为 0.2减去执行时间,如下左图所示,图中 update 前的竖直黑线代表 update 的执行时间。
  • 若某次执行时间超过间隔(如下右图 0.2 秒执行的 update ),则程序需要加快执行,只能给很短的间隔时间。使得运行较长时间后,最终会在第N 秒执行 N×5 update
    【从零开始学Skynet】实战篇《球球大作战》(十三):场景代码设计(下)

2、移动逻辑 

   服务端要处理的第一项业务功能是球的移动,现在实现 move_update 方法:
function move_update()
    for i, v in pairs(balls) do
        v.x = v.x + v.speedx * 0.2
        v.y = v.y + v.speedy * 0.2
        if v.speedx ~= 0 or v.speedy ~= 0 then
            local msg = {"move", v.playerid, v.x, v.y}
            broadcast(msg)
        end
    end
end

         由于主循环会每隔0.2秒调用一次move_update,因此它只需遍历场景中的所有球,根据路程 速度 × 时间计算出每个球的新位置,再广播move协议通知所有客户端即可。

3、生成食物 

服务端会每隔一小段时间放置一个新食物,定义 food_update 方法来实现该功能:
function food_update()
    if food_count > 50 then
        return
    end

    if math.random( 1,100) < 98 then
        return
    end

    food_maxid = food_maxid + 1
    food_count = food_count + 1
    local f = food()
    f.id = food_maxid
    foods[f.id] = f

    local msg = {"addfood", f.id, f.x, f.y}
    broadcast(msg)
end
这段代码做了如下几件事情:
  • 判断食物总量:场景中最多能有50个食物,多了就不再生成;
  • 控制生成时间:计算一个 0 100 的随机数,只有大于等于 98 才往下执行,即往下执行的概率是1/50 。由于主循环每 0.2 秒调用一次 food_update,因此平均下来每 10 秒会生成一个食物。
  • 生成食物:创建 food 类型对象 f ,把它添加到 foods 列表中,并广播addfood 协议。生成食物时,会更新食物总量 food_count 和食物最大标识food_maxid

 4、吞下食物

编写吃食物的 eat_update 方法:
function eat_update()
    for pid, b in pairs(balls) do
        for fid, f in pairs(foods) do
            if (b.x-f.x)^2 + (b.y-f.y)^2 < b.size^2 then
                b.size = b.size + 1
                food_count = food_count - 1
                local msg = {"eat", b.playerid, fid, b.size}
                broadcast(msg)
                foods[fid] = nil --warm
            end
        end
    end
end
        它会遍历所有的球和食物,并根据两点间距离公式(见下图)判断小球是否和食物发生了碰撞。如果发生碰撞,即视为吞下食物,服务端会广播eat 协议,并让食物消失(设置 foods 对应值为 nil )。
【从零开始学Skynet】实战篇《球球大作战》(十三):场景代码设计(下)

 代码中变量名的含义如下:

  • pid:即playerid,指遍历到的小球对应的玩家id
  • b:遍历到的ball对象。
  • fid:遍历到的食物id
  • f :遍历到的 food 对象。

 说明:本篇的场景服务代码更多的是为了演示如何使用框架, 没有很多性能考究。比如在eat_update代码中,双重嵌套for循环的计算量较大。在实际项目中,往往会使用一些简化的计算方法(后面会有简单的描述)。

 至此,完成了场景服务的所有代码。

5、主服务修改

        假设服务端启动时就开启了多个战场。 现在修改主服务,让它开启scene服务。 新增的内容
如下代码 示:
--scene (sid->sceneid)
for _, sid in pairs(runconfig.scene[mynode] or {}) do
     local srv = skynet.newservice("scene", "scene", sid)
     skynet.name("scene"..sid, srv)
end
说明: 为简单起见,演示程序会开启固定数量的场景服务。在 实际项目中,可以仿照agent 动态开启场景服务。

完整项目地址:​​​​​https://gitee.com/frank-yangyu/ball-server文章来源地址https://www.toymoban.com/news/detail-417405.html

到了这里,关于【从零开始学Skynet】实战篇《球球大作战》(十三):场景代码设计(下)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【从零开始学Skynet】基础篇(三):服务模块常用API

              Skynet提供了开启服务和发送消息的API,必须要先掌握它们。列出了Skynet中8个最重要的API,PingPong程序会用到它们。 Lua API 说明 newservice(name, ...) 启动一个名为 name 的新服务,并返回服务的地址。 start(func)         用 func 函数初始化服务,并将消息处理函数注

    2023年04月12日
    浏览(50)
  • 【从零开始学Skynet】工具篇(二):虚拟机文件的复制粘贴

            大家在Linux系统下开发的时候肯定会遇到虚拟机与主机间无法复制粘贴的问题,现在我们就来解决这样的问题,方便我们的开发。 我们可以系统界面的菜单栏点击“控制”,然后打开“设置”;  也可以在VirtualBox界面打开“设置”,效果都是一样的;  打开“设

    2023年04月19日
    浏览(28)
  • Python球球大作战

    安装pygame的命令: 《球球大作战》是一款简单易上手、充满趣味性和竞技性的休闲手游。游戏的核心玩法可以用一句话概括:“大球吃小球,努力生存并成为最大的球。” 游戏规则与操作 : 在《球球大作战》的世界里,每位玩家操控一个可自由移动的小球球。通过滑动屏幕

    2024年04月17日
    浏览(23)
  • 从零开始:手写 JavaScript 代码应用于实际场景

    ​🌈个人主页:前端青山 🔥系列专栏:JavaScript篇 🔖 人终将被年少不可得之物困其一生 依旧 青山 ,本期给大家带来JavaScript篇专栏内容:JavaScript-场景应用 目录 三、场景应用 1. 循环打印红黄绿 (1)用 callback 实现 (2)用 promise 实现 (3)用 async/await 实现 2. 实现每隔一秒打

    2024年02月03日
    浏览(49)
  • 【C++/C 实现球球大作战】

    这篇文章主要为大家详细介绍了C语言实现——《球球大作战项目》,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。 游戏介绍: 这是一个大球吃小球的世界,玩家的目标是要努力吃成最大的球球。在游戏一开始,玩家出现在地图上随机

    2024年02月09日
    浏览(21)
  • 基于C++的简易版《球球大作战》游戏设计

    全套资料下载地址:https://download.csdn.net/download/sheziqiong/85602628 全套资料下载地址:https://download.csdn.net/download/sheziqiong/85602628 《球球大作战》虽然在玩法上类似于大球吃小球的模式看起来很单薄。但是在游戏过程中会出现无数种意外情况,这就需要玩家运用一系列策略来达到

    2024年02月10日
    浏览(29)
  • 球球大作战 旋转合球脚本 - 用于蓝蝶模拟器(blueStacks5)

    键位截图 JS代码 下面是生成好的蓝蝶脚本代码,仅供参考

    2024年02月12日
    浏览(82)
  • 【从零开始学习JAVA | 第三十三篇】File类

    目录 前言: File类: 构造方法: 常见成员方法: 总结:         本文我们将为大家介绍JAVA中一个比较使用的类:File类,他为我们提供了存储数据的功能,使得程序的数据不至于在运行结束之后就丢失,是一个很好的类。         File类是Java标准库中用于操作文件和目录

    2024年02月15日
    浏览(31)
  • 【从零开始学习JAVA | 第二十三篇】集合体系结构

    目录 前言: 单列集合:      set与list的区别: 双列集合: map的特点: 总结:                   JAVA中为我们提供了很多集合,这些集合都有自己很独特的特点,因此我们要学习所有的集合,但是在学习所有的集合之前,我们还是先为大家介绍一下JAVA的集合体系结构,这

    2024年02月16日
    浏览(43)
  • 【区块链 | 预言机】从零开始使用Chainlink预言机(2)- 智能合约中使用更安全的随机数-代码实战

    Chainlink最近推出一款革命性的产品,VRF—Verifiable Random Function可验证随机数,给智能合约带来了真正安全的随机数。本文我们就来介绍一下如何在智能合约中使用VRF吧。 我们先简要介绍一下Chainlink VFR的工作流程。 首先,智能合约应用,也就是我们的Dapp,需要先发起一个获取

    2024年02月02日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包