Unity 完整的热更新方案和流程

在开发商业游戏时,热更新是一个很重要的模块,这里讲的热更新不是指仅仅修复Bug,而是进行游戏功能的更新。简单来讲,就是启动游戏后,跑个条,下载资源和代码,然后再进入游戏。本篇博客所写的内容并不是最优的解,只是完成了热更新这个事情而已,具体使用还需要使用者根据自己的项目来具体来看。 这里采用的方案是使用 AssetBundle 和 xLua。使用 AssetBundle 是为了资源的完全自主控制。而整个游戏的逻辑部分,则使用 xLua 来实现。当然,C# 的代码不可能一点没有,只是一些核心的功能模块,一般写好后就不会改变的东西,或者对性能要求很高的东西,放在 C# 就可以。 整个功能分为编辑器部分,和运行时部分。编辑器部分就是编 Bundle,生成版本文件等。而运行时部分就是从 CDN 下载版本文件,对比版本号及本地资源是否有要更新的,如果有,则更新,更新完后进入游戏。没有,则直接进入游戏。 编辑器部分 编辑器部分主要就是生成 Bundle 文件,首先,我是按目录来划分 Bundle 的,任何一个目录下的文件(不包括子目录)则会打成一个 Bundle。例如下面的目录结构 Res/ - ConfigBytes/ - UI/ - LuaScripts/ - Data/ - ItemsData/ - CharactersData/ 首先 Res 目录是资源的主目录,下面有各种子目录(Res 目录下不会有需要打 Bundle 的文件)。ConfigBytes 目录下的文件,会打成一个 Bundle。UI 目录下的文件会打成一个 Bundle。LuaScripts 目录下的文件会打成一个 Bundle。Data 目录下的 ItemsData 目录中的文件会打成一个 Bundle,Data 目录下的 CharactersData 目录会打成一个Bundle。如果 Data 目录下存在文件(非目录),则这些文件会打成一个 Bundle。简单来讲,就是会按文件夹来决定哪些文件打成一个Bundle,检查的时候只会取一个文件夹下的文件,而不会递归取这个文件夹下的子目录。 LuaScripts 目录在开发时会放在 Assets 目录外面,与其同级,在编 Bundle 时,会拷贝 LuaScripts 目录及下面的所有文件,按原有目录结构,拷贝到 Res 目录中,并且会将每一个 xxx.lua 文件的扩展名改为 xxx....

March 20, 2022 · 14 min · 猫猫

一个游戏兑换码生成及验证方案

在开发独立游戏《小镇危机:来自丧尸的问候》时,需要设计一个兑换码的功能,但是在网络上也没有找到合适的方案,所以这里就自己考虑了一种。这里会说明思路,具体的实现,可以按照自己的方式去定制。 我们的游戏中有两种资源可以兑换,一种是星星,一种是钻石。所以就需要在兑换码中通过某种方式表示出来。本质上就是将自己想兑换的数据,通过某种方式的变换,隐藏在兑换码中,然后服务器是知道解码方式的,通过解码,即可还原出玩家兑换的是什么,然后将兑换物品回给玩家。 我们的游戏兑换码为14位的,里面包含的信息有兑换类型,兑换数量,这两个信息,例如 LMA60XV7380QBH。 1. 兑换码生成和验证过程 兑换码由大写字母和数字组成,对于兑换码中的每一个字符,我们可以使用的字符为 [0, 9] 和 [A, Z]。 确定要表示的信息,所占用的字符数。对于我们的游戏来说,兑换类型只需要 1 个字符即可,而兑换数量,需要占用 4 个字符,到此,已经消耗掉 5 个字符。 兑换码的数据校验和,会占用2个字符,到此消耗掉 7 个字符。 剩下的 7 个字符,为唯一的随机字符串,用于填充验证码的。 根据上面的步骤,首先生成第 3 步所需要的 7 位随机字符串。由于我们每一位可用的字符数是36个,所以最终的排列组合有上百亿种,我们不需要那么多,几百万个足够了。这里要注保证唯一性。生成的字符串如下所示 DLDWVEQ WM8YB8M MNUP5RR 3RG7X8D VUBPD8J J3L3ZR1 1Y1ALB3 R6PRATR 然后表示出兑换码要兑换的数据,假设这里要兑换星星,并且兑换的数量为 10000 个。首先使用一个字符来表示星星,例如使用 S 来表示,当然,也可以将 36 个字符进行分组,然后从组中去随机一个,这样更不容易被破解。然后兑换的数量,可以转为 16 进制,或者 34 进制都行。假设这里使用 34 进制来表示,10000 转为 34 进制就是 8M4,不足4位,前面进行补0,也就是 08M4。进制转换的逻辑需要自己写。 取一个随机字符串,与要兑换的信息进行组合,组合的方式随意,只要最后恢复时使用相同的方式即可。假设这里将随机字符串的前3位放在兑换码的开始,然后跟上兑换类型,后三位放在最后。这里使用上面第一个随机字符串为例子。经过这一步组合,得到的字符串如为 DLDS08M4WVEQ。 然后计算上面得到的字符串的校验和,为 AD,将 AD 放在最后,这里随意,可以按自己想放的位置去放,自己知道就好了。现在得到的字符串为 DLDS08M4WVEQAD。 最后需要做的就是将上面得到的字符串进行打乱,按什么样的方式打乱呢,这里需要事先生成几套排列方案,例如 [8, 1, 5, 9, 2, 4, 0, 12, 7, 10, 13, 11, 3, 6],也就是字符中第一个字符放到索引 8 的位置,第二字符放到索引 1 的位置,第三个字符放到索引 5 的位置,以此类推。我们可以生成多套这样的排列方案,然后使用字符串中的其中一位,来表示,例如我们使用第2位的L来表示使用哪一套方案,将 L 转换为 int 数值,然后对排列套数进行 % 操作,得到使用哪一套排列方案,进行排列。这里要注意,第2位不能变,也就是不受随机排列影响,忽略掉,否则服务器没法恢复。...

March 1, 2022 · 1 min · 猫猫

我的独立游戏下载量和广告收入情况

经过了几个月的开发,我的游戏终于上线了。这篇博客来聊一下目前这个游戏的下载量和广告收入情况。 《游戏码农:那些打工的日子》是一个轻松的模拟经营文字游戏,游戏的主角是一个普普通通的小码农,刚刚来到一线城市,开始自己的职业打工生涯。游戏拥有丰富的玩法,轻松的升级体验,多种不同的赚钱方式,实现财富自由,指日可待。 目前已经上线 AppStore,TapTap,好游快爆等平台。 AppStore: https://apps.apple.com/cn/app/id1607035933 TapTap: https://www.taptap.com/app/230651 好游快爆:https://www.3839.com/a/141332.htm 下图是 Android 平台的广告收入情况 下图是 iOS 平台的广告收入情况 通过上面的广告收数据可以知道,从 2022.01.27 到 2022.02.05 这几天,Android 平台一共收入了 111 块钱,而 iOS 共收入了 70 块。 下面是各个渠道的下载量统计 从上线以来,目前总玩家数有2982,期中日活玩家平均不到200。在渠道统计中有一个为 Development 的渠道,占了总玩家数的大部分,但是,这个渠道的包不是我发的,而是被破解了广告的一个包,所以其实真正导致收入的玩家数,是很少的。 综上,这个游戏从玩法上来说,玩家粘性一般。从收入上来说,也是几乎可以忽略了。假设包没有被破解,可能收入会翻倍,不过那也没多少,和之前打工时的工资,根本无法比。 猫语互动 欢迎关注微信公众号 猫语互动,博客文章同步推送

February 6, 2022 · 1 min · 猫猫

游戏码农:那些打工的日子

经过了几个月的开发,我的游戏终于上线了。 《游戏码农:那些打工的日子》是一个轻松的模拟经营文字游戏,游戏的主角是一个普普通通的小码农,刚刚来到一线城市,开始自己的职业打工生涯。游戏拥有丰富的玩法,轻松的升级体验,多种不同的赚钱方式,实现财富自由,指日可待。 目前已经上线 AppStore,TapTap,好游快爆等平台。 AppStore: https://apps.apple.com/cn/app/id1607035933 TapTap: https://www.taptap.com/app/230651 好游快爆:https://www.3839.com/a/141332.htm 找工作 游戏开始需要完善简历信息,然后选择中意的公司进行投递和面试,拿到 Offer 后,不同的公司,给出的薪资略有差距,需要仔细考虑。 租房子 压一付一的租房模式,大大缓解了刚开始打工的年轻人,到底是住的远一点,舒服一点,便宜一点。还是住的近一点,老破小,还贵。 点外卖还是自己做饭 自己做饭,需要先购买食材,然后根据菜谱来做,挑战很大,但是成本低。点外卖,省力,就是花钱有点多。 学习 想要提高自己的专业经验,光打工是不够的,还得多多学习。 休息 在家里的时候,可以打打游戏,看看小说,睡睡觉,打工也是一个长期的活,同时也要照顾好自己噢。 通勤 打车很舒服,消耗体力也小,坐地铁便宜,但是人挤人,应该怎么选择呢?似乎还得看看自己的存款 上班 认认真真完成工作,也别忘记偶尔摸个鱼,或者钱很多可以把自己的工作任务偷偷外包给同事。 投资 光靠打工是很难实现财富自由的,还是投资吧,股票、基金、贵金属等等,多种投资模式自己选择,真实的市场波动。 资产 有些东西可能平时用不着,但是很贵。 赚钱小游戏 偶尔休闲一下,打两把小游戏,顺便赚点钱,当然,也可能输。 猫语互动 欢迎关注微信公众号 猫语互动,博客文章同步推送

February 4, 2022 · 1 min · 猫猫

Gameplay 02 游戏中的跳跃

游戏中的跳跃,就是以某一个速度起跳,克服重力。而以不同的速度,起跳的最高点是不一样的,很难去量化,所以我们可以定义每次起跳的最大高度,然后求出起跳速度,即可做到一切可控。 自由落体公式 $h = \frac{1}{2}gt^2$。速度 $v = gt$,这个是瞬时速度,但是自由落体的速度是均匀变化的,所以平均速度就是下落高度中间时刻的速度,所以才得出 $h = \frac{1}{2}gt^2$。 我们的目标是求出跳跃的速度。 首先,假设我们以一个初始速度 $j$ 来跳跃,这个是一个向上的速度,但是因为重力的存在,所以我们的跳跃速度会因为重力的向下抵消,而逐渐趋向于 0。当 $j$ 慢慢被抵消到 0 时,我们也就达到了以 $j$ 这个速度来跳跃所能到达的最大高度。 对于任意时刻 $t$,速度 $v = j - gt$,当 $j - gt = 0$ 时,也就是我们所能到达的最大高度。所以,到达最大高度的时间为 $t = \frac{j}{g}$。 根据上面的公式,我们可以知道,在以 $j$ 来跳跃的整个过程中,任意时刻的高度为 $h = jt - \frac{gt^2}{2}$。 由于我们上面已经知道了,在 $t = \frac{j}{g}$ 时,我们将达到最大跳跃高度。将 $\frac{j}{g}$ 带入到任意时刻的高度公式中 $h = jt - \frac{gt^2}{2}$。我们可以得到 $h = j(\frac{j}{g}) - \frac{g(\frac{j}{g})^2}{2}$。 化简上面的公式将得到 $h = \frac{j^2}{g} - \frac{\frac{j^2}{g}}{2} = \frac{j^2}{g} - \frac{j^2}{2g} = \frac{j^2}{2g}$。...

January 22, 2022 · 1 min · 猫猫

Gameplay 01 游戏开发中的平滑移动

这篇博客,聊一聊在游戏开发中,控制角色或者其他物体的平滑移动。现实中,一个物体,从静止加速到匀速运动状态,或者从匀速运动状态变为静止状态,都会有一个过程。就像人走路,或者汽车开动。 一个物体在运动状态下,会有一个速度变量,也就是我们期望的速度。而从静止到运动状态的过程,会有一个加速度。 而游戏开发中,要做到一个物体平滑的运动,也就是模拟出这个从静止,通过加速度,达到期望速度的过程。 游戏是按帧运行的,在初始的时候,目标运动速度为0,随着每一帧的流逝,目标速度会不断累加一帧中的加速度,当累加到期望速度时,则会以期望速度来运动。 代码如下,这里是在 Unity 中实现的,但是原理对于所有游戏引擎通用 using System.Collections; using System.Collections.Generic; using UnityEngine; public class MovingSphere : MonoBehaviour { // 用户设定最大期望速度 [SerializeField, Range(0f, 100f)] private float maxSpeed = 10f; // 用户设定最大加速度 [SerializeField, Range(0f, 100f)] private float maxAcceleration = 10f; // 当前的运动速度 private Vector3 velocity; // Update is called once per frame void Update() { // 通过读取用户输入,来确定期望速度向量(向量包含了大小和方向) Vector2 playerInput; playerInput.x = Input.GetAxis("Horizontal"); playerInput.y = Input.GetAxis("Vertical"); Vector3 desiredVelocity = new Vector3(playerInput.x, playerInput.y, 0....

January 6, 2022 · 1 min · 猫猫

编译 Apple Silicon 版本 Aseprite

编译苹果 M1 芯片版本的 Aseprite,步骤如下 ...

December 1, 2021 · 1 min · 猫猫

《音乐与僵尸:Zombie Rhythm》开发日志

《音乐与僵尸:Zombie Rhythm》经过了一个多月的开发,终于上线了。这是一个融合了丧尸和音乐节奏的休闲游戏。这篇文章就聊一下这个游戏的整个开发过程。 ...

October 12, 2021 · 1 min · 猫猫

《我在美国学游戏设计》笔记

从情感体验出发,探索出最合适的机制来表达情感。 ...

September 27, 2021 · 1 min · 猫猫

如何开发一个问答类游戏

问答类游戏,在开发过程中还算是比较简单的一个分类,核心的内容就是问题与答案。抽象来讲,问题可能是文字,也可以是图片,也可以是声音等等,而对应玩家可以选择的答案,也可以不同的表现形式。例如看电影海报猜电影名字,听音乐片段猜歌曲等等 【诗仙与诗魔】,是一个诗词挑战类游戏,本质上也算是一个答类游戏,问题变成了某一首诗中的某一句,而答案就是从给定的类似诗句中选择正确的那一句。接下来我将从技术有角度来解析一下这个游戏的整个开发过程。 这个游戏现在可以直接从商店下载体验,在 AppStore 或 TapTap 搜索 诗仙与诗魔 即可找到。 这个游戏现在可以直接从商店下载体验,在 AppStore 或 TapTap 搜索 诗仙与诗魔 即可找到。 iOS 下载连接: https://apps.apple.com/app/id1583234447 Android 下载连接: https://www.taptap.com/app/222178 先解析一下这个游戏,诗仙与诗魔有三种玩法,独自练习,就是关卡模式。无尽冲榜,就是不断地累积得分,然后进行排行榜。匹配挑战,是可以与其他玩家进行联网匹配的玩法,这一个涉及到服务器部分的开发。 客户端的部分 客户端在启动后,会先去一个固定的域名,拉取一些必要的配置信息,例如服务器的状态,排行榜和匹配服务器的连接地址,服务器的状态等等。这个可以自己根据需求配置各种各样的信息,只有这些必要的信息拉到后,游戏才会继续下一步。 接下来会从本地尝试读取用户数据,如果本地没有,则会从服务器尝试请求,如果服务器也没有,则认为这是一个新玩家。弹出玩家昵称输入界面,玩家确定后,会将用户的ID和昵称等数据发到服务器,并且在本地存档,然后就会进入游戏。如果本地没有用户数据,但是服务器有,就会使用服务器保存的用户数据,进行数据恢复,然后在本地存档。 接下来就进入了主界面,可以选择三种不同的玩法。先说一下诗词数据。诗词数据是使用 flatbuffers 存储在游戏包里的。每一个记录,保存了一首诗的ID,名字,作者,内容等。游戏启动后,会读取所有的诗词数据,进行结构化存储。每一首诗,会创建一个 Poem 对象,里面保存了这首诗的内容,以及额外的数据,例如这首诗有几句,每一句的字数,这些数据会用于随机生成问题,以及根据字数,从其他诗词中选择类似的诗句,用作答案。 关卡模式,就是罗列出诗词配置表中的每一首诗,作为一个关卡,当玩家作答完毕后,会记录所用时间。在关卡界面,所以看到每一首作答过的诗词所用的时间。 无尽冲榜,首先进入时会消耗体力,对于每一个新玩家,会给予默认300体力,还有2个复活道具,5个刷新道具。在冲榜模式中,每一首诗会有10秒的倒计时,在过程中,玩家可以选择使用一个刷新道具,换一首诗作答,以此不终断冲榜过程。冲榜结束后,会给出得分,客户端会得得分提交到服务器。对于头衔,是由得分计算出来的,这个直接在客户端计算。游戏没有作作弊方面的处理,对于这个游戏来说,没什么必要。如果失败,则必须消耗一个复活道具,才能继续从失败的地方继续冲榜。如果道具或体力不足,则可以通完看广告获得。 匹配挑战,匹配挑战同样会消耗体力,进入后,首先会向服务器发送匹配消息,服务器会在根据匹配的等待时间,根据玩家的 elo 分值,进行实力相当的匹配,如果最后没有真实玩家,则会匹配一个机器人,与玩家一起玩。每一局匹配挑战由10首诗构成,由哪10首诗,以及每一首诗的可选择答案,则由服务器生成,以此保证两个玩家使用的挑战数据是一致的,保证公平性。 匹配挑战的分得计算,每一首诗为1000分,如果答错,则0分。如果答对,先得500分,剩下的500分,根据作答速度,剩余时间的百分比,进行得分。得分由服务器计算,一定程度上受网络影响。 服务器的部分 服务器可以分为三部分,服务器及用户基础数据,排行榜,匹配,这三部分是使用不同的方式实现的。 服务器及用户基础数据 这一部分使用 aws 的 DynamoDB、Lambda、 API gateway 实现的。通过API gateway 调用 lambda 读写 DynamoDB的数据,可以根据网上一些视频教程来操作来下。逻辑很简单,主要是配置各种权限的时候稍微麻烦一点,也还好。 排行榜 排行榜放在了 aws 的免费 ec2上,因为游戏的量不大,所以免费的也够用,数据直接放在了 Redis 中,API 逻辑是使用 Rust 来写的。 匹配 匹配部分也是放在 aws 的免费 ec2 上。也是使用 Rust 写的。连接模块使用了 message-io 的 websocket。客户端和服务器使用了简单的 json 交互,因为数据比较简单,就没有使用更复杂的协议。期中,匹配开了两个线程,一个用于监听客户端的连接,收到连接后,会将连接数据发往另一个线程,数据的交互是使用了 rust 的 channel。游戏管理器收到新的连接,就会加入到客户端的列表。收到客户端发来的消息后,会进行解析,然后进行逻辑处理。...

August 29, 2021 · 1 min · 猫猫