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

news2024/11/27 0:48:57

1、主循环

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

 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

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 )。

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

  • 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/429097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习笔记 —— C++并行库OpenMP

ContentsInstallationImplement1、一个最简单的OpenMP代码&#xff1a;2、如何规定线程数2、如何设置OpenMP分配线程的schedule3、 冲突避免机制 --Reduction&#xff08;规约&#xff09;Discovery写在最前面&#xff1a; 并行化虽好&#xff0c;但并不是所有任务在并行化后都…

【MySQL学习】MySQL表的操作

目录一、表的创建1.1 创建表的语法1.2 案例二、查看表结构三、查看建表语句四、修改表4.1 修改表的语法4.2 修改案例五、删除表一、表的创建 1.1 创建表的语法 语法&#xff1a; CREATE TABLE table_name (field1 datatype,field2 datatype,field3 datatype ) character set…

透视Android系统AMS、PMS和WMS,了解开发中的重要角色

原理 在Android系统中&#xff0c;AMS&#xff08;Activity Manager Service&#xff09;、PMS&#xff08;PackageManager Service&#xff09;和WMS&#xff08;Window Manager Service&#xff09;是三个重要的系统服务&#xff0c;它们负责管理应用程序的生命周期、处理应…

Backblaze + Cloudflare + Picgo 打造免费顺畅的图床体验

本文xlog地址&#xff1a;https://x.cosine.ren/backblaze-cloudflare-picgo-imgbed hexo 地址&#xff1a;https://ysx.cosine.ren/backblaze-cloudflare-picgo-imgbed 同步发布 最近有用到oss存储的需求&#xff0c;跟群友调研了下国内 & 国外的 oss 后&#xff0c;深感找…

大爽pygame入门教程 第一节 基础知识

作者自我介绍&#xff1a;大爽歌, b站小UP主 &#xff0c;编程1对1辅导老师 本节掌握要点&#xff1a; 文本, 图形, 键鼠事件&#xff0c;动态展示。 一、实现基础窗口 0 - 新建文件 新建001.py文件&#xff0c;内容如下 import pygamepygame.init() # pygame 初始化&#x…

什么是远程桌面连接?如何操作远程桌面?

随着时代越来越信息化、智能化、自动化&#xff0c;越来越多的企业和个人开始使用远程办公软件进行办公。其中远程桌面连接是一种非常流行的办公方式。那么&#xff0c;什么是远程桌面连接?如何操作远程桌面? 一、什么是远程桌面连接? 远程桌面连接是一种远程访问计算机的…

nginx缓冲区关闭导致下载失败问题-方案篇

问题描述 导出操作。小于200k的excel正常下载&#xff0c;大于200K的下载失败&#xff0c;异常信息如下: Cannot forward to error page for request [/xx/xx] as the response has already been committed. As a result,the response may have the wrong status code. If you…

程序员工作久了,都不会好好说人话了...互联网人的....黑话

原来工作也是会被腌入味的 前段时间有位博主吐槽 工作太久都不会说人话了 这张口的互联网味儿 瞬间梦回自己的工位 而评论区的网友们表示 这不就是”世另我“吗 一场关于互联网黑话的"掰头" 就此开始了... 维护厨房 &#xff08;厨房秒变公司&#xff09; 新…

Bagging算法预测银行客户流失率

Bagging算法预测银行客户流失率 描述 为了防止银行的客户流失&#xff0c;通过数据分析&#xff0c;识别并可视化哪些因素导致了客户流失&#xff0c;并通过建立一个预测模型&#xff0c;识别客户是否会流失&#xff0c;流失的概率有多大。以便银行的客户服务部门更加有针对性…

【CSS】使用 CSS 实现三角形 ( 宽高设置为 0 | 设置四个边框宽度 / 样式 / 颜色值 | 兼容低版本浏览器 | 基本示例 | 对话框示例 )

文章目录一、使用 CSS 实现三角形二、使用 CSS 实现三角形代码示例三、使用 CSS 实现 对话框 代码示例一、使用 CSS 实现三角形 使用 CSS 实现三角形步骤 : 首先 , 宽度 / 高度 设置为 0 ; /* 宽高设置为 0 像素 */width: 0;height: 0;然后 , 设置 4 个边框 , 每个边框都要设置…

【软考备战·希赛网每日一练】2023年4月14日

文章目录一、今日成绩二、错题总结第一题第二题第三题第四题三、知识查缺题目及解析来源&#xff1a;2023年04月14日软件设计师每日一练 一、今日成绩 二、错题总结 第一题 解析&#xff1a; 具有 最优子结构 特点的问题可以使用 动态规划法 进行求解。计算m数组中每项的值&am…

日撸 Java 三百行day28-30

文章目录说明day28-30 Huffman 编码 (节点定义与文件读取)1.建树过程&#xff08;以图为例&#xff09;2.哈夫曼树特点3.分析代码过程3.1 抽象成员变量3.2结合文章梳理思路1.读文本2.解析文本内容&#xff1a;3.建树4.生成哈夫曼编码5.编码6.解码4.其他4.1 java 类型强转4.2 ja…

网络安全相关的知识

一、 什么是IDS&#xff1f; IDS是英文"Intrusion Detection Systems"的缩写&#xff0c;中文意思是"入侵检测系统"。专业上讲就是依照一定的安全策略&#xff0c;通过软、硬件&#xff0c;对网络、系统的运行状况进行监视&#xff0c;尽可能发现各种攻击…

TexMaker(Latex编辑器)软件的“文献引用”操作:Xelatex方式运行的操作方法

一、说明 1. 针对问题 本文主要讲解使用TexMaker进行**.bib的方法**的文献引用时&#xff0c;如何使用Xelatexpdf的方式完成文献引用。某些文章强调使用PDFlatex进行编译&#xff0c;但有时候会因为论文模板不同&#xff0c;无法运行padflatexPDF。所以&#xff0c;这里给出xe…

常用模块和模板引擎

私人博客 许小墨のBlog —— 菜鸡博客直通车 系列文章完整版&#xff0c;配图更多&#xff0c;CSDN博文图片需要手动上传&#xff0c;因此文章配图较少&#xff0c;看不懂的可以去菜鸡博客参考一下配图&#xff01; 系列文章目录 前端系列文章——传送门 后端系列文章——传送…

Android---导致OOM的常见原因

目录 内存溢出OOM 单应用可用的最大内存 导致 OOM 的常见原因 内存实时监控 内存溢出OOM 单应用可用的最大内存 dalvik.vm.heapstartsize&#xff0c;它表示堆分配的初始大小。 dalvik.vm.heapgrowthlimit&#xff0c;它表示单个进程内存限定值。 dalvik.vm.heapsize&#…

LeetCode每日一题 1023. 驼峰式匹配 --双指针

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

Vue UI组件库(Element UI库)

1 移动端常用 UI 组件库 1. Vant Vant 4 - 轻量、可定制的移动端组件库 (vant-ui.github.io) 2. Cube UI cube-ui Document (didi.github.io) 3. Mint UI Mint UI (mint-ui.github.io) 2.PC 端常用 UI 组件库 1.Element UI Element - 网站快速成型工具 2.IView UI iView / Vi…

SpringBoot集成WebSocket实现及时通讯聊天功能!!!

1&#xff1a;在SpringBoot的pom.xml文件里添加依赖: <!-- websocket --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency> 2&#xff1a;在配置中…

C++简单工厂模式

目录 什么是简单工厂模式 简单工厂模式的实现 总结 什么是简单工厂模式 简单工厂模式是一种创建型设计模式&#xff0c;它提供了一种创建对象的最佳方式。在软件开发中&#xff0c;我们经常需要创建各种各样的对象&#xff0c;但是直接使用 new 关键字来创建对象会使代码变得…