|
好久不见。
这是第38篇与游戏开发有关的文章。
书接上文:
上一篇讲的是,在RPG maker MV中,人物生成器的基本工作原理,以及相关资源的分类和使用规则。
本篇,将从实践出发,用流水账的方式,记录在Unity中实现人物生成器的一些关键步骤。
<hr/>| 分析资源
要说一上来就能对整个系统了如指掌,确实是有点吹牛了。
想要在Unity中复刻人物生成器,除了在RMMV中操作几次、找点规律外;还需要分析它用到的资源。
尽管上篇已经对资源名称的含义进行了说明;但是为了凑字数,还是记录一下这个结论是如何得到的。
我使用的方法是:用Excel来分析这些纹理的名称。
首先,将纹理名称保存到一个csv文件中。
将纹理名称导出到csv中
很明显,资源名称有强烈的规则感,似乎是被某种神秘力量、用下划线拼接而成的,所以我们对它进行分列处理。
对分列后形成的表格进行透视,就能得到更多的信息。
通过与RMMV进行比对,可以轻松的发现:纹理名称中AccA、AccB指的是的形象片段的类型;如AccA表示配件1、AccB表示配件2等。
而P_ _则表示此种形象片段的“变化”或“风格”,因为数量上可以和RMMV相对应。
再试着用纹理拼一下图就会发现:c_指的是层级,值越小,层级越高(c1在最上层)。
一些与类型名称相连的数字,比如RearHair1、RearHair2后面的数字1和2,是用来区分形象片段之间的层级。比如RearHair2是要放在Face下的,而RearHair1是放在Face之上的(数字越小,层级越高)。
可以用更复杂的例子,来验证上述规则。比如下面这件衣服就是由上下两部分组成(Clothing2在脸的下方,Clothing1在脸的上方),而每一部分又是由多张图片组成。
最后,名字中的m_ _ _ 指的是颜色,或者说一类颜色的值。比如m001被认为是皮肤颜色,这点可以从RMMV中的得到验证,当为某一个皮肤类型(比如头像)选定了颜色后,其余与皮肤有关的类型(耳朵等)也会被设置成相同的颜色。
当然,如果仔细看这个透视表,可能会产生这样的疑问:为什么RearHair既有m003也有m004呢?
如果把颜色是m004的RearHair对应的纹理打开就会发现,这里指的其实是头发上的一些装饰,所以它们单独使用了一个颜色分类,而没有使用头发的颜色。
角色动画使用的动作图分为颜色图和遮罩图两部分,它的命名规则与头像图基本一致,只是遮罩图会带有_c后缀。
RMMV的遮罩图使用的是特定的颜色,比如衣服会使用下面四种颜色来区分可以换色的区域。
通过以上各种乱猜,我们基本上弄清了RMMV中资源的命名规则。
RMMV形象片段文件的命名规则
其实,能弄清楚规则是因为后来不经意间在Google上搜到了疑似官方文档,里面有对纹理使用的详细介绍...
所以,这个事儿告诉我们:碰到问题还是得先Google,别自己瞎搞,免得浪费时间。
接下来就可以在Unity中构建人物生成器了。
<hr/>| 人物生成器的配置
我用以下四组配置来构建随机生成人物所需要的数据:
头像片段配置
动作图配置
形象片段随机生成配置
颜色配置
配置以Json格式导出,在启动时被加载到内存中,这是游戏框架中很基础的功能,不是本文的重点,所以在这就不赘述了。
<hr/>| 所需的数据
要生成一个人物形象,只需要两组数据。
首先,是形象片段ID;用人话讲就是:脸是几号、鼻子是几号、衣服是几号等;可以通过 形象片段随机生成配置 结合 头像片段配置 及 动作图配置 获取到。
当然,有些形象片段是有几率被随机到的(程序员生成头发的几率就会略低一些);有一些是必须存在的(五官);还有一些是从性别上区分的(胡子就是女性人物随机不到的)。当然,上述都可以通过配置来控制。
另一组需要的数据就是颜色ID,用人话讲就是:皮肤的颜色(会影响皮肤、耳朵、鼻子等)、毛发的颜色(影响头发、眉毛等)、衣服的颜色等分别是什么;可以通过 颜色配置 获取。
当然,如果想设计的更细致些,可以对颜色ID再进行一次分类,区分出哪些是“先天”颜色(皮肤、毛发、瞳孔),哪些是“后天”颜色(服装、配饰等);前者一旦创建无法改变,后者可以动态修改(更换装备)。
<hr/>| 头像和动画
上面两组数据准备好后,就可以在游戏运行时,“填充”成 人物头像 或 人物移动动画 了,逻辑很简单:根据形象片段的ID,把和它有关的所有片段纹理取出,找到对应的颜色,然后按照层级顺序,依次渲染即可。
需要指出的是;对于人物头像,我在Unity中使用了UGUI的Image组件来表现;因为它们多出现在UI系统中:例如对话、人物属性面板等。
而人物移动的动画,我使用了MeshFilter + MeshRenderer来表现,因为它们更多出现在地图中,特别是经常与TileMap一起使用。
稍有不同的是,我自己组织了用于渲染的网格数据,而不是用多个Image或多个MeshFilter + MeshRenderer的组合来表现人物形象。
下面分别就实现 头像 和 移动动画 的关键内容进行介绍。
● 头像
渲染一个由多个形象片段组成的头像,仅需要一个继承自Image的类即可。
在Unity中,一个Image的子类,可以通过重写OnPopulateMesh函数,在渲染前修改顶点数据,以实现某些特殊的表现需求;而渲染角色头像恰恰可以利用这点来完成。
重写OnPopulateMesh函数
重新填充顶点数据
填充顶点数组的逻辑很简单,唯一需要注意的是:在填充顶点属性时,可以将颜色信息放到Texcoord0.zw中进行传递;之后在片段着色器中,就可以利用这两个值进行颜色替换了。
在片段着色器中处理颜色替换
● 人物移动动画
人物移动动画也只由一个MeshFilter + MeshRenderer的组合来实现;我们要做的是动态维护一个网格;在动画切换时,通过修改这个网格的数据来实现行动方向的切换 以及 颜色的替换。
这里计算、填充顶点位置及UV的方法基本与上面Image一样,都是通过获取图集中Sprite信息计算得到的;相对麻烦一些的是颜色替换。
● 动画的颜色替换
首先,回到RMMV中,可以发现一个形象片段最多可以替换四个部分的颜色,例如:一件设计复杂的衣服,就有四个部分可以被替换颜色;而其他类型的片段,也都有若干个部分(不超过4个)支持替换颜色。
部分支持换色的形象片段
替换颜色的基本实现思路是:想要计算某个点的颜色,先去遮罩图中采样;然后与某一个指定的遮罩颜色进行比较,如果发现“是”这个颜色,那就表示这个点在遮罩范围内,它的颜色需要被替换,然后使用这个点颜色的灰度值,结合要被替换颜色的索引值,去渐变图中采样新颜色并使用;否则就使用原颜色。
当然,一个形象片段支持几种颜色的替换,上述逻辑就要执行几次。
在运行时如何将指定的遮罩颜色传递给着色器,以及如何传递要替换的颜色索引值呢?
我使用的方法是:根据形象片段的不同,将其对应的若干个(不超过四种)遮罩颜色以及要替换的颜色索引,通过网格中的顶点属性进行传递。
为了更好的利用顶点属性,我将遮罩颜色的RGB值以及颜色索引压缩保存到一个float中。
一个Vector4包含4个float,刚好可以保存下所有的遮罩颜色以及替换颜色的索引值。
准备将四个遮罩颜色及替换颜色索引保存到顶点属性中
需要注意的是,在向网格中的顶点属性写入压缩后的颜色信息时,应该保证相关的四个顶点(组成一个完整的形象片段)必须一致。
片段着色器中的逻辑就简单多了,只需要对保存上述压缩信息的顶点属性进行解压缩,然后分别进行颜色比较以及颜色差值计算就可以了。
<hr/>| 其他
除了上述内容外,还有一些零碎的细节,不知道归在哪里,就在这罗列下吧。
● 切图
RMMV的形象片段纹理很多,手动将纹理切分成Sprite-Sheet的话,工作量有点大;可以写一个脚本来处理它们,关键的步骤是通过TextureImporter来设置Sprite-Sheet。
这里需要注意的是,行动颜色图中,有些是包含了大量透明区域的,这部分需要调整脚本,在切Sprite-Sheet时跳过这些透明区域(否则合图的尺寸会被撑大)。
● 行动遮罩图
行动遮罩图是白底的,所以切成Sprite-Sheet后打图集时,Unity无法对其进行紧密排布,这会导致合图尺寸过大(甚至超过2048)。
可以先通过脚本将遮罩图的白色背景替换为透明(1,1,1,0),然后再重复上述切图的步骤,这样会减小合图尺寸。
● 关于Excel的数据透视表
因为之前工作的关系,我略微了解些使用Excel的方法。现在当程序员了,仍然会借助Excel的能力帮我解决一些问题。
我个人的经验是:数据透视表,是Excel学习性价比最高的功能。
这个功能简单、易用,只需稍微花一点点时间就能上手;配合公式一起使用的话,可以在很多工作情境下提升效率。
<hr/>| 写在最后
以上就是在Unity中复刻RMMV人物生成器的关键步骤了,您看懂了么?
我自己看了几遍,反正是没懂。
不过就先这样吧。
前两天骑共享单车时悟到了一个人生道理,分享给您:
话,要一句一句说,
饭,要一口一口吃,
日子,要一天一天过,
人生目标,要一个一个忘。 所以别着急,慢慢来吧。
与君共勉。
感谢您能读到这里。
下回见。
我的公众号 偶尔学学Unity 会特别不定期更新与游戏开发可能有关的文章,要是您特别闲的话可以关注,谢谢。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|