Hi there 👋

  • 欢迎来到我的Blog,我是 Fred
  • 目前是一个独立开发者
  • Let’s make something fun.

让 Unity Shader 不受 Time.timeScale 的影响

Time.timeScale 是 Unity 的时间缩放变量。如果将此设置为0,那么 Time.time 将停止,并且 Physics 和 Animator 在默认情况下也将停止。所以,将 Time.timeScale 设置为0,通常为了做暂停相关的东西。 但是,有时候希望即使将 TimeScale 设置为 0,有些东西也能继续运行,比如在写 Shader 时,经常会用到 _Time 属性,但是它会受到 Time.timeScale 的影响。不过有以下几种方式可以做到不受影响。 方法一 private void Update() { material.SetFloat("_UnscaledTime", Time.unscaledTime); } 这种方式比较直接,但是也有弊端,如果要设置的 Shader 很多,会增加很多 MonoBehaviour。 方法二 Unity 可以设置 Shader 全局变量,即材质之间共享属性。 private void Update() { Shader.SetGlobalFloat("_UnscaledTime", Time.unscaledTime); } 这样场景中只需要一个做这件事情的 MonoBehaviour 的脚本即可。这个方法可以覆盖大多数情况。 方法三 如果场景中不想放任何脚本,还有一个更强大的方法,那就是使用 PlayerLoop 来独立于 MonoBehaviour 更新全局属性。 首先引入一个工具类 PlayerLoopModifier.cs,代码如下 using System; using System.Collections.Generic; using System.Linq; using UnityEngine.LowLevel; public class PlayerLoopModifier : IDisposable { private PlayerLoopSystem root; public PlayerLoopModifier() { root = PlayerLoop....

June 25, 2022 · 3 min · fred

Lua 带权重随机

t 是数据数组,weights 是权重数组,两个数组长度是一致的。 function RandomWithWeight(t, weights) local sum = 0 for i = 1, #weights do sum = sum + weights[i] end local compareWeight = math.random(1, sum) local weightIndex = 1 while sum > 0 do sum = sum - weights[weightIndex] if sum < compareWeight then return t[weightIndex], weightIndex end weightIndex = weightIndex + 1 end return nil, nil end

June 3, 2022 · 1 min · fred

理解 Entity Component System

Entity-Component-System (ECS) 是一种架构模式。这种模式广泛地应用在游戏开发中。ECS 使用组合原则,因此这种模式使程序具有更好的灵活性和扩展性。游戏场景中的所有对象都被视为一个实体 (Entity)。这种模式在默认情况下也具有更高的性能。 Entity-Component-System 有三个部分组成 Entity (实体) Component (组件) System (系统) 什么是 Entity Entity 可以理解为一个对象的标识,它没有任何具体的数据和行为,只是标识一个东西。在实现上,通常可以用一个 Struct 来实现。而组件,为其提供数据。 例如,我们要实现一个太空版本 Minecraft,所有游戏中能看到的,有形的东西,都算作一个实体。一搜飞船,一个角色等等。 什么是 Component 组件是附加到实体的可重用模块,它是实体的单一行为描述。组件提供了实体的表现,行为,和功能。不同组件的组合,可以创造出不同类型的逻辑实体。 什么是 System 一个 System 在运行时会遍历很多组件,以此实现高效的性能。例如渲染,物理,寻路。系统为组件提代了全局的管理和服务。 我们可以使用系统来分离逻辑和数据,系统可以用来处理逻辑组件,充当数据容器。 关于系统的例子 处理重力加速度 将速度应用到一个向量上 根据 AI 的设计,来控制机器人的输入 渲染 (位置,Sprite) 处理玩家输入 组合 我们可以组合不同的 Component,以及设置 Component 不同的数据值,来配置具体的实体。 ECS 的优势 降低代码量以及复杂度 对于逻辑扩展拥有很高的灵活性 对于 3D 和 VR 需要大量渲染逻辑的项目有性能优势 让非技术人员更方便地编写脚本 可以分离庞大复杂的类结构 代码可重用和可组合性很强 更加方便的单元测试 可以支撑复杂的 VR 程序 运行时组件的替换 多进程和多线程友好 分离数据和功能 更加灵活地定义游戏对象 提供了解耦,封装,模块化,可重用性方法,以此构成一个干净的设计。 ECS 的劣势 不能像 MVC 那样直观定义逻辑 要用好 ECS,需要更多的思考组件的设计 ECS 需要写大量的小型代码,增加了出错的风险 目前的应用没有面向对象广泛 ECS 示例 看下面的图,这是一个兔子的实体,其中有很多组件被附加到了实体上,Placeable、Huggable、Consumable、Hopping 等 …...

April 3, 2022 · 1 min · fred

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 · fred

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

在开发独立游戏《小镇危机:来自丧尸的问候》时,需要设计一个兑换码的功能,但是在网络上也没有找到合适的方案,所以这里就自己考虑了一种。这里会说明思路,具体的实现,可以按照自己的方式去定制。 我们的游戏中有两种资源可以兑换,一种是星星,一种是钻石。所以就需要在兑换码中通过某种方式表示出来。本质上就是将自己想兑换的数据,通过某种方式的变换,隐藏在兑换码中,然后服务器是知道解码方式的,通过解码,即可还原出玩家兑换的是什么,然后将兑换物品回给玩家。 我们的游戏兑换码为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 · fred

在过去的一个月里

已经一个多月没有写 This Week In Moeif 的周记了,在过去的一个月里,发生了很多事情。年前我们早早的回家了,不过游戏开发的工作依然在不断进行着。年后也过了正月十五才回的上海。 从做独立开发者开始,生活就没有了假期与工作日的明显界限,因为时间都是自己的,做的事情也是自己想做的,并且所做的一切,也都是自己的积累。有时候也会忙到很晚,但是明显没有打工时的那种身心疲惫。 1. 游戏码农:那些打工的日子 在过去的一个月里,首先我们上线了《游戏码农:那些打工的日子》这个游戏。并且这个游戏已经有了广告收入,虽然不多,但是已经开始有了。2月份的收入如下图 这个游戏可以目前安卓和iOS版本都已上线,可以直接在Taptap,好游快爆,AppStore等搜索 游戏码农 即可找到,也可以直接从下面连接进入应用平台。 Appstore: https://apps.apple.com/cn/app/id1607035933 TapTap: https://www.taptap.com/app/230651 好游快爆:https://www.3839.com/a/141332.htm 2. 小镇危机:来自丧尸的问候 昨天,我们又上线了另一个游戏《小镇危机:来自丧尸的问候》。这个游戏的资源包是买的,但原版是英文版,我们自己改成了中文版,然后加入了排行榜系统,兑换码系统。目前游戏也已在安卓和iOS平台上线。 AppStore: https://apps.apple.com/cn/app/id1611293156 TapTap: https://www.taptap.com/app/231533 好游快爆:https://www.3839.com/a/141899.htm 3. 接下来的规划 就在今天,我们确定了接下来要开发的一个项目,我们乐观的预计,会比前两个游戏拥有更多的用户量,以及更多的收入。敬请期待。 4. 另外欢迎加入我们的 Moeif Games 玩家交流群:163359029 萌一小栈 欢迎关注微信公众号 萌一小栈,博客文章同步推送

February 28, 2022 · 1 min · fred

Roguelike In Rust 05: 生成地牢

这一节我们将会创建一个地牢,地牢由不同的房间组成,房间与房间之间是联通的,玩家可以行走。下面是最终运行效果图。 ...

February 22, 2022 · 4 min · fred

Roguelike In Rust 04: 地图与行走

接着上一节的内容,这一节将创建地图,然后玩家可以在地图中行走。地图分为可行走区域和不可行走区域。我们可以认为地图是由一个一个的格子组成。 先看一下最终的效果 ...

February 8, 2022 · 4 min · fred

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

经过了几个月的开发,我的游戏终于上线了。这篇博客来聊一下目前这个游戏的下载量和广告收入情况。 《游戏码农:那些打工的日子》是一个轻松的模拟经营文字游戏,游戏的主角是一个普普通通的小码农,刚刚来到一线城市,开始自己的职业打工生涯。游戏拥有丰富的玩法,轻松的升级体验,多种不同的赚钱方式,实现财富自由,指日可待。 目前已经上线 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 · fred

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

经过了几个月的开发,我的游戏终于上线了。 《游戏码农:那些打工的日子》是一个轻松的模拟经营文字游戏,游戏的主角是一个普普通通的小码农,刚刚来到一线城市,开始自己的职业打工生涯。游戏拥有丰富的玩法,轻松的升级体验,多种不同的赚钱方式,实现财富自由,指日可待。 目前已经上线 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 · fred