阅读视图

发现新文章,点击刷新页面。
🔲 ☆

使用 OpenAI 的最佳实践

如何向GPT-3和Codex提供清晰有效的指令。 Prompt 是怎样工作的 由于指令跟随模型的训练方式或它们所接受的数据,有特定的提示格式可以很好地配合当前任务并可靠地发挥作用。以下是我们发现可靠有效的一些提示格式,但请随意尝试不同格式,以找到最适合您任务的格式。 经验法则和示例 注意:"{text input here}“是实际文本/上下文的占位符 1. 使用最新模型 为了获得最佳结果,我们通常建议使用最新、功能最强大的模型。截至2022年11月,生成文本的最佳选项是“text-davinci-003”模型,生成代码的最佳选项是“code-davinci-002”模型。 2. 在提示的开头放置说明,并使用###或”““分隔指令和上下文 低效方式 Summarize the text below as a bullet point list of the most important points. {text input here} 高效方式 Summarize the text below as a bullet point list of the most important points. Text: """ {text input here} """ 3. 请尽可能具体、描述性和详细地说明所需的上下文、结果、长度、格式、风格等。 请具体说明上下文、结果、长度、格式和风格等。 低效方式 Write a poem about OpenAI. 高效方式 Write a short inspiring poem about OpenAI, focusing on the recent DALL-E product launch (DALL-E is a text to image ML model) in the style of a {famous poet} 4.
🔲 ☆

Unity 内存管理的专业提示

优化是游戏开发中很重要的一部分,涉及的方面主要有 CPU,GPU,内存,网络等。 在这篇博客中,主要会写关于内存相关的优化,Unity 是如何管理内存的,以及怎样才能使游戏更高效地运行。 在深入到 Unity 之前,我们先来看一下内存是如何工作的。 操作系统会在物理内存的基础上,创建一个虚拟内存,用于程序运行。在这个抽象中,会有一些虚拟地址空间(VAS) 在内存优化上,主要考虑两部分,也就是栈(Stack)和堆(Heap)。在理解栈和堆之前,首先要理解在 Unity 中,数据的类型,可分为值类型,和引用类型。对于值类型的数值,会直接存储在栈上,并且是可以直接复制的。例如,int, float, bool, struct, Color Vector3 等。 而引用类型的数据,则是存储在堆上,但是,指向这个数据的指针,是存储在栈上的。 栈(Stack) 存储值类型 存储引用类型的指针 由 CPU 自动管理,无须程序员关心。在函数调用时,参数将自动申请内存放入栈中,当函数结束时,这些参数又会从栈取出,释放内存,这一切操作都是自动的。 栈比堆的速度快 栈的容量有限,如果超过上限,则会出现栈溢出。 栈的运行方式是 Last in first out。也就是后进先出,或者说先进后出。 堆(Heap) 可以存储引用类型和值类型的数据 由程序员手动管理 内存空间不一定是连续的 比栈速度慢 可以扩展空间大小 接下来,我们来理解什么是 “垃圾”,以及什么是 “垃圾回收”。 垃圾 存储在栈上的一个指向堆数据的指针结束时(释放时),堆上的数据没有用了,对于这样的对象,可以理解为 “垃圾”。 垃圾回收 为了解决垃圾内存的问题,.Net 有对应的垃圾回收系统。 在初始化一个新的进程时,语言运行时会为该进程保留一个连续的地址空间区域。这个保留的地址空间称为托管堆。托管堆维持指向堆中下一个对象的地址指针。 从托管堆中分配内存,比非托管堆中分配内存要快。 垃圾回收系统会创建一个包含从根可访问的所有对相的图。当一个对象不在这个图中,也就是无法从根节点访问时,垃圾回收系统会将这部分内存视为垃圾,并在合适的时机释放为其分配的内存。 Unity 的内存管理系统 Unity 的内存管理分为三部分。 托管内存 托管内存使用托管堆以及垃圾回收系统自动分配和释放内存,而提供这个功能的是 Mono 或 IL2CPP。在 Unity 中我们大部分时候使用的都是托管内存,所以 New 对象时,都不考虑释放,垃圾回收系统会帮我们处理掉。 C# 非托管内存 C#非托管内存层使你可以在编写C#代码的方便下访问本机内存层以微调存储器分配。 您可以在Unity Core API中使用Unity.CollectionsNamespace(包括NativeArray),以及Unity Collections软件包中的数据结构来访问C#非托管的内存。如果您使用Unity的 Job System 或 Brust,则必须使用C#非托管内存。
🔲 ☆

通过作用域最小化来避免屎一样的代码

面条式代码,是软件工程中反面模式的一种,也就是源代码的控制流程复杂,混乱难以理解,见到来说,就是屎一样的代码。 最小化变量的作用域,是避免产生面条式代码的一种有效方式。 作用域最小化是一种构建代码的方式,操作起来很容易 声明具有最小作用域的变量 用具有最小作用域的数据来分配变量 事实上,是代码的结构,定一了变量的可见性。 背景 一个程序是由一些单一或者组合的语句构成,例如赋值操作、条件判断、循环等。 通常来说,如果有两个代码块 A 和 B 如果 A 包含 B,那么 A 就是 B 的外部代码块 如果 B 被 A 所包含,那么 B 就是 A 的内部代码块 代码的缩进级别,是由嵌套级别数量决定的,直接的内部块会比其外部块多一个级别。 我们假设定义全局作用域,也就是没有外部块的代码,缩进级别为0,而全局变量,就是那些在全局范围内定义的变量。 变量可见规则 一个变量的可见性,由下面规则决定 从该变量的声明语句开始 结束于变量声明块的末尾 并且在开始与结束中间的嵌套块中也是可见的 反过来说,如果一个变量是不可见的,那么 在变量声明前 在变量声明块结束后 建议 R1. 尽量不要使用全局变量 R2. 声明单一用途的变量 R3. 在接近变量用途的地方声明变量 R4. 保持小的代码块 R5. 使用靠近其声明的变量 R6. 使用不超过2层的嵌套 R1. 尽量不要使用全局变量 全局变量会使代码变得难以阅读和理解,难以维护和测试。 全局变量的使用,增加了出现问题的概率,并且不容易被发现。 程序中可能错误地分配变量的语句越少越好。 总之,全局变量的使用往往代表着技术债务,必须尽快重构以避免后期的不可维护。 R2. 声明单一用途的变量 为单一的特定目的声明和使用变量,以便将其作用域限制作到最小。 一个变量的目的性越多,意味着可访问此变量的代码块越多。 而变量可见的语句数量越多,可能错误地赋值变量的语句就越多。 可能错误地赋值变量的语句越多,那么发现和修复潜在错误就越困难。 R3. 在接近变量用途的地方声明变量 尽可能地在靠近将使用这些变量的语句和代码块的地方声明变量。 与 R2 严格相关。
🔲 ☆

噪声函数与地图生成

在我学习声音信号处理的时候,我的大脑很自然地联想到了地图生成。这篇博客记录了关于信号处理的一些概念与地图生成相关的东西。这些知识点不是一些新的东西,但对我来说,是以前从未接触过的,所以我想记录一下,并且分享给大家。这篇博客会覆盖一些简单的主题,频率、振幅、噪声的种类、噪声的应用等。涉及到的数学部分,基本上只有正弦波形。 这里会从简单的概念开始,然后逐渐深入。 注意:下面涉及的代码,虽然是以 Python 来描述的(简单直观),但文章的目的是为了解释原理,使用任何语言都可以的。 1. 为什么随机性是有用的 我们在程序化的地图生成中要做的是生成一组输出,其中有一些东西是相同的,而有一些东西是不同的。例如,在我的世界这个游戏中,所有的地图都有很多相似性。生物群落,方块大小,生物群落的平均大小,洞穴的平均高度,不同石头所占的比例等等。但是,也有一些不同的地的:群落的位置,黄金的位置,洞穴的大小等等。作为游戏的设计者,需要决定哪些部分需要是相同的,哪些部分需要是不同的。 对于不同的部分,通常是使用随机数生成器。让我们来做一个极其简单的地图生成器:它将包含20个格子,其中某些格子将包含宝箱。结果如下 请注意这个地图有多少共同的地方:首先它都是由格子组成(每个点作为一个格子),每行有20个格子,然后有两种类型的块,一个是空白,一个是宝箱。 但有一点是不同的,哪一个格子是什么类型,也就是说宝箱可能出现在从0到19的任何一个格子。 我们可以使用随机数来选择将宝箱放在哪一个格子中。最简单的方式是选择从0到19的随机数。这意味着每一个格子都可能被选择。大部分的编程语言都包含随机数生成函数。在 Python 中,使用方式是 random.randint(0, 19)。完整代码如下 def gen() map = [0] * 20 pos = random.randint(0, 19) map[pos] = 1 return map for i in range(5): print_chart(i, gen()) 生成结果如下: 假设我们想让地图中的宝箱有更多的可能性出现在左边,这时就要使用非均匀随机数选择了。有很多方法可以完成这件事情,其中一种方式是首先选择一个随机数,然后将它向左移动,例如,使用函数 random(0,19)/2,下面是 Python 代码 def gen(): map = [0] * 20 pos = random.randint(0, 19) / 2 map[pos] = 1 return map for i in range(5): print_chart(i, gen()) 然后,如果我们想让宝箱更多地出现在左边,但是,右边也不能一个没有,应该怎么办呢?一个方式是使用平方数,也就是先选定一个随机数,然后计算它的平方,然后再用结果除以19(地图右边界索引),得到的结果向下取整。下面是代码和效果 def gen(): map = [0] * 20 pos = random.
🔲 ☆

Unity 游戏启动前显示隐私协议

使用 Unity 开发的游戏,在上架某些平台时,比如 TapTap,由于政策的原因,需要在收集用户信息,或使用某些权限时,先弹出隐私协议,用户同意之后,才能操作。但是如果直接在 Unity 里做这件事情,哪怕是用一个空场景来做,Unity 本身就会在隐私协议前收集一些信息,所以,我们需要使用原生代码,来操作这一块逻辑。这里只说 Android。 首先要做的就是在 Assets/Plugins/Android 新建一个 java 文件,用来作为启动 Activity,在这个 Activity 中,先展示隐私协议,当玩家点击同意后,再去调用 Unity 的 Activity。 package com.moeif.moeifgames; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import com.unity3d.player.UnityPlayerActivity; public class MoeNativeActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!isTaskRoot()) { Intent intent = getIntent(); String action = intent.getAction(); if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) { finish(); return; } } Boolean anInt = false; // 隐私协议相关 SharedPreferences base = getSharedPreferences("base",MODE_PRIVATE); anInt = base.
🔲 ☆

一个独立游戏的开发总结

从2021年4月开始,我作为一名独立开发者,开始了自己的瞎折腾之路。一年多没有做出什么赚钱的项目。不过现在,终于做出了一个对于我自己来说,算是成功的项目。 我现在上线的这款游戏是一个文字游戏,画风稀碎,也没有什么具体的游戏类型,一切都是野路子,只要觉某个玩法好玩,就会添加这个玩法。这个游戏就是《无量:钓海》,目前已经上线了 TapTap、好游快爆、AppStore、光环助手、4399 平台。在没有版号的情况下,国内也就这些平台可以上了。 《无量钓海》TapTap 链接: https://www.taptap.com/app/234065 游戏从构思,开发,到上线,经历了很多问题,也学到很多东西。这些经验,趟过的坑,开发上的积累,等等,都可以用于下一个项目。 这个项目参与的人可以说有三个。工程的开发,是我来做,游戏内容的构思,策划,是另一个小伙伴在做。第三个人,也是一个游戏玩法,帮我们做了一部分角色的图片。 这个游戏的起点,是在我一个游戏《游戏码农》的玩家群里,有一个玩家说他有一个很好的点子,建议我做一下。正好那个时候也在想新项目的方向,我考虑了一下,所性就问他是否愿意合作开发,然后游戏的广告收益进行分成。结果已经知道了,我们合作了。而这个玩家,是一个正在读高中的学生。在合作的过程中,一开始的沟通肯定不是那么顺畅的,因为对方也没做过游戏。但最终这个问题还是解决了,方法也很简单,就是把自己构思的东西,写明白,写详细,以文字的形式描述出来。至于工具,尝试了很多,最终他用起来最顺手的还是 WPS 云文档,那就这个了,毕竟工具而已,无所谓的。作为独立开发者,我觉得不要纠结于用什么工具,不要拿公司那套完善的流程来套用,可能并不合适。一定要记住目标,就是把游戏做出来,把构思内容传达明白,至于方式,在开始的阶段,根本不重要。当然,这只是从我个人的体验角度出发,如果意见不同,那就以你为准 游戏从构思,到上线,一共是两个半月的时间,前一个月,基本上没有工程开发相关的东西,也不是没有,只是没有游戏内容上的开发,那时我记得我好像在写热更新,广告调用,等等通用的东西。游戏一开始的构思方向,和现在上线的版本,差别还是挺大的,一开始构思的内容,除了核心的钓鱼这个点,其他的都推翻了。一开始挺慌的,不确定性太大了,策划心里可能也没谱,但还是这样做了,还好,这个方向也没啥大问题。 游戏在5.16号上线了 TapTap,好游快爆。建立了玩家 QQ 群,很快突破了2000人,TapTap 上的评分,也一路上涨,当然,这一切并不是因为游戏,而是我们在 QQ 群里说让大家评论,然后有兑换码奖励。这一点一定不要学,因为 TapTap 是不允许的。因为这个操作,游戏的评分从 4 分,2天内直接冲到了9分以上,并且进了热门榜前5。这也带来了大量的玩家加入QQ 群,为此我还给腾讯贡献了好几百块,用来充年度 VIP 会员,用来扩群。 不过给兑换码让玩家评论的方式,在 TapTap 这里是不允许的。后来,TapTap 就给我们发了警告,不过一开始我没有看到,所以导致了后面大量的评论被删,而且被删的都是一些好评,差评全都留下了,这直接导致了评分的腰斩,回到了6点几分。现在还好,慢慢的恢复正常了,稳定在 7 分左右。至此,游戏的前期平台流量,也基本上宣告结束了,每日下载量巅峰时刻是 1W 多,后来逐步下降,现在完全是自然量了,TapTap 平台每日新增玩家也就几十个,加上其他的平台,现在每日新增在 150 左右。目前累计玩家总量 4.9W 左右,我自己统计的,平台统计的可能会更多一点。每日活跃玩家总数大概是 1800 左右。 玩家 QQ 群人数多了,就会出现很多问题,很多人提各种建议,根本来不及做,只能先汇总下来,慢慢画饼。不过很多饼最终还是做出来了。另外,千万不要跟玩家硬杠,玩家觉得体验不好,自然有不好的道理,作为游戏开发者,要明白目标是什么,是赚钱(为爱开发,或者家里有矿的随便杠),一定要学会认怂。有一些玩家,玩的不爽了,没玩明白,反手就是 TapTap 上一个差评,而 TapTap 上的评评分,好敏感,可能几个差评就直接把分数拉下来了。所以,一定要学会认怂,和玩家硬杠,嘴上可能一时爽了,最终受损失的还是自己。另外,不要随便设置 QQ 管理员,设置了管理员,有一些管理员会觉得有权力了,但是有一些人不会真正站在游戏的角度考虑问题,会和玩家硬怼,因为管理员和游戏没有什么利益上的关系。玩家才不管这个人是不是游戏开发者,反手就是一个差评,受损失的还是游戏开发者。 为什么要以文字的形式来开发游戏呢?为什么不找人合作,将美术做的更好看一点呢?其实我也想啊,要是有一个亿,我也愿意组个团队去折腾,去尝试。可是现实是,对于独立开发者,最重要的还是要先活下去,有稳定的能够支撑基本生活的收入。文字游戏的开发周期,开发难度,是很小的,而文字的表现力,又是无限的。再就是找到合适的人,就很难,其次,风险很高,无法保证做出来一定有收入,还有分成问题,到底程序占多少,策划占多少,美术占多少,平均分配肯定是不合适的,还得根据不同的项目,工作量,来决定,前期分成如果没谈好,哪怕勉强做,可能后期效果,开发效率,也会有所影响。所以,并不是人越多,越好。 游戏从技术上采用了 xlua 热更新的方式开发的,所有的游戏逻辑都是用 lua 来写的,这带来了非常大的好处,我们可以快速的迭代版本,修改 Bug 等等。目前保持的节奏基本上是每天都会更新一点新内容。群里的玩家也养成了每天晚上8点等更新的习惯。如果技术上允许,建议大家使用这种方式,真的迭代很方便,资源上传 CDN 就可以。目前我用的 CDN 是 DogeCloud,新用户的话有免费的存储空间和流量,对于一个小项目来说,完全够用,目前我还没有把免费流量用完,连一半都没用上。 目前游戏的主要收益来自于两方面,一方面是广告,一方面是爱发电的赞助。至于赚了多少钱,从开发时间上来算,肯定没有之前打工时赚的多,不过还好有点收入。 游戏还在继续迭代,玩家的流量,也在缓慢减少,不过应该还能再持续一段时间。下一个项目,也在构思中了,敬请期待。 以上这些都是我从一个独立开发者的角度来谈的,无法和商业公司的开发模式去比较,仅仅是我所经历的一些东西。 技术交流,欢迎添加我的微信:ifloop
🔲 ☆

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
🔲 ☆

理解 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 等 …
🔲 ☆

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.
🔲 ☆

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

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

在过去的一个月里

已经一个多月没有写 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 猫语互动 欢迎关注微信公众号 猫语互动,博客文章同步推送
🔲 ☆

Roguelike In Rust 05: 生成地牢

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

🔲 ☆

Roguelike In Rust 04: 地图与行走

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

先看一下最终的效果

🔲 ⭐

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

经过了几个月的开发,我的游戏终于上线了。这篇博客来聊一下目前这个游戏的下载量和广告收入情况。 《游戏码农:那些打工的日子》是一个轻松的模拟经营文字游戏,游戏的主角是一个普普通通的小码农,刚刚来到一线城市,开始自己的职业打工生涯。游戏拥有丰富的玩法,轻松的升级体验,多种不同的赚钱方式,实现财富自由,指日可待。 目前已经上线 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 的渠道,占了总玩家数的大部分,但是,这个渠道的包不是我发的,而是被破解了广告的一个包,所以其实真正导致收入的玩家数,是很少的。 综上,这个游戏从玩法上来说,玩家粘性一般。从收入上来说,也是几乎可以忽略了。假设包没有被破解,可能收入会翻倍,不过那也没多少,和之前打工时的工资,根本无法比。 猫语互动 欢迎关注微信公众号 猫语互动,博客文章同步推送
🔲 ⭐

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

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

Roguelike In Rust 03: 实体和组件

对于游戏开发者,可能或多或少听说过或者使用过 ECS 的结构。现在大多数游戏使用的还是面向对象的模式,面向对象编程并没有什么问题,但是在游戏开发过程中,当游戏不断的超出原有的设计时,从整个工程的扩展来说,ECS 拥有更好的扩展性。 下面是一个面向对象的例子 BaseEntity Monster MeleeMob OrcWarrior ArcherMob OrcArcher BaseEntity 是一个基类,包含了基本的数据和代码,用于表示地图上的一个实体。Monster 是一个怪物,MeleeMob 是一个近战单位,它会发现近处的目标,然后干掉它。ArcherMob 是一个可以远程攻击的单位。完成这样一个实体逻辑,可能首先需要按照不同的单位,将逻辑分开,并且抽出共同的逻辑,放到基类中。如果这时增加了一个兽人的逻辑,它即可以近战,又可以远程,并且在完成某些任务时,会变得更友好,怎么办?那就改逻辑呗,继续抽象,分离和整理代码。有很多已经上线的游戏是这样做的。但是,如果使用 ECS,这样的扩展会变得更加容易。 Entity Component 的模式会消除面向对象模式中的层级结构,取而代之的是使用 Components 来描述一切东西,例如一个兽人,一只狼,一瓶药水等等。Component 只是数据,给一个实体,添加多个 Component。 例如,我们可以创建一个实体,然后赋予它一些 Components,Position,Renderable,MelleAI,RangedAI,Hostile,Friendly 等等。对于近战单位,可以给它 MelleAI,Renderable 等。对于远程单位,可以给它 RangedAI,Renderable。对于兽人,在完成任务前,它有 Hostile 组件,而完成任务后,会变得更加友好,那就移除 Hostile 然后添加 Friendly。可以按照游戏逻辑随意地去组合。 ECS 中的 “S” 叫做 System。System 会从 Components 中读取数据,然后执行自己的逻辑代码。例如在单位的显示逻辑中,用于显示的 System 会从单位的 Position 和 Renderable 组件中拿取数据,然后用于在地图上显示实体。 对于小型游戏来说,在使用 ECS 时可能会感觉比面向对象写了更多的代码,前期确实是这样,但是对于后期添加逻辑,ECS 就变得容易了很多。 使用 ECS 很重要的一点就是要知道 ECS 只是处理组合的一种方式,但并不是唯一的方式。对于实现功能来说,并没有什么唯一的方式,在了解了原理后,按照自己的习惯和喜好来就行。 接着上一节的 hellorust 工程,使用 Specs 库 cargo add specs cargo add specs-derive Cargo.toml
🔲 ☆

Roguelike In Rust 02: Hello Rust

Rust 算是一个新兴的语言,近两年非常火了,但是他首次出现是在 2010 年。Rust 有非常好用的工具 cargo 和 rustup。 如果要学习 Rust 这门编程语言,也有很多优秀的教程。 The Rust Programming Language Book Learn Rust by Example 24 Days of Rust Rust’s Ownership Model for Javascript Developers Rust 编辑器可以使用 VSCode 在终端中使用命令 cargo new hellorust 可以创建一个名为 hellorust 的工程。src/main.rs 是起始文件。Cargo.toml 是工程的配置文件,里面包含了一些其他库的引用信息。 此时 src/main.rs 的代码如下 fn main() { println!("Hello, world!"); } fn 是函数的关键字 main 是主函数名,也就是整个程序的起始函数。 println! 是一个打印宏 使用命令 cargo run 可以编译并运行工程。 一些有用的 cargo 命令 cargo init 初始化一个新的工程 cargo build 会下载所有的依赖库,并且编译整个项目 cargo update 会根据 Cargo.
🔲 ☆

This Week In Moeif 30

下个周计划去做个小手术,把额头上的小脂肪瘤干掉,应该可以直接在门诊做。上海的医保也可以直接用了。

从下一期开始,我要考虑一下改变一下周记的模板,看看如何改成内容叠加式,这样最后就知道这一年干了什么。

🔲 ⭐

This Week In Moeif 29

这周主要在加速开发码农游戏,其他的事情都暂缓了。 这周注册了一个新的域名,国内的,这样可以备案,可是域名拼错了…,不过也无所谓,反正不对外,只是在代码中使用。似乎找到了一个国内和国内访问腾讯云都很快的方法,就是国内直连,国外使用 Cloudflare 加速,等后面有了服务器的逻辑可以测一下。 考虑了一下下一个项目的事情,准备下一个项目海外版增加内购,国内还是暂时以广告为主,暂时这样计划着。 看了一下Godot,编辑器确实很快,但是从产品开发上,还是Unity更保险一些,一方面比较熟悉,一方面各种支持和资源很丰富。目前确实没有转引擎的必要。 项目进度 游戏码农:那些打工的日子 这周完成了资产模块的逻辑和UI,投资模块的逻辑和UI。投资模块的价格数据,使用了市场上真实的数据,目前只加了一个数据源,后面会再加几个,增加可靠性。另外,这个项目的软著终于有动静了,目前处于待发放的状态,也就是通过了,估计下周能邮出。 本周电影 这周忙到没时间看电影 本周书籍 《愿你迷路到我身旁》 《游戏设计艺术》(阅读中) 下周初步计划 继续逻辑编写
❌