欢迎光临散文网 会员登陆 & 注册

随笔|用Unity帮助理解并解决瓜游立绘的拼图游戏

2020-09-29 15:20 作者:Deficuet  | 我要投稿

前排提示:打开Unity一步步捏几个2D对象对理解该文帮助巨大。记得使用Inspector的Debug模式而不是Normal

因为太复杂了怕我自己忘了所以写的比较详细

拿谢菲的皮肤作为栗子吧

人琴分离十米自动爆炸(

手头有两张立绘 至于怎么来的,我只能说懂的都懂不懂也没必要懂

想把他们拼在一起,咋整

用Photoshop吧,得一点一点扣细节,而且无法直接拼,这两张图片的尺寸差别太大

(使用了Python的PIL库)拼,就硬拼

所以肯定要调整尺寸。这就更要命了,其一用PS慢慢调不方便而且要花很多时间,毕竟光看图的话精确的原本的尺寸不得而知;其二黄鸡还准备了很多拼图给你玩(

这对我这个追求完美同时又是条懒狗的人来说是不能接受的(

那咋整啊

游戏咋整的我就咋整

首先在painting文件夹里找到个叫xiefeierde_4的无后缀无扩展名文件,用点什么手段打开它,然后找到这么个东西

打开它,一路点开直到找到RectTransform Base,这是我们要的,同时我们也知道了其上的GameObject类对象名字是xiefeierde_4_front(略显废话

把它的大部分子项展开

戳开它的m_Father项,可以看到另一个RectTransform Base

故技重施,把这个RectTransform Base的子项都展开。这次瞅瞅它的第一项GameObject类的m_GameObject。将其一直展开至此

易得该GameObject类对象叫layers。

这个RectTransform对象也有个m_Father,故技重施。

这个GameObject类对象的名字是xiefeierde_4。再康康它的RectTransform的m_Father

已经再没有对象了,说明该RectTransform是最顶层的

由此我们得到了 xiefeierde_4 -> layers -> xiefeierde_4_front 的父对象和子对象的套娃关系。

接下来收集我们需要的数据

为了方便,以下将直接把GameObject对象的名字用作指代称呼其对应的RectTransform对象

先来看xiefeierde_4的RectTransform Base,它是所有人的父对象。

第一次看这一堆我也头大

对我们的目的来说其实只有SizeDelta有用。

这里讲一下根据SizeDelta求得RectTransform对象的Size

看它的AnchorMin,这是矩形左下角的点。它的AnchorMax,这是矩形右上角的点

在这里AnchorMin和AnchorMax都是(0.5, 0.5),易得该矩形的左下角和右上角两点重合在一起

所以位于矩形四个角的四个锚点围成的矩形的尺寸为(0, 0)

而SizeDelta是由RectTransform对象的尺寸(长与宽) 减去 其定义的锚点所围成的矩形的尺寸

由此可得xiefeierde_4的原始尺寸为(3813, 2456)

也就是说只有琴的部分的立绘原始尺寸为3813x2456

其实到这一步就可以把图丢进PS了,不过已经到这步了为了方便写程序我选择贯彻到底(

之后看看xiefeierde_4的子对象layers

这里我们需要的有layers的AnchorMin, AnchorMax, AnchoredPosition和Pivot。这几个值描述了layers的Pivot对于其父对象即xiefeierde_4的相对位置。

那么来算吧,layers的Pivot位于xiefeierde_4的坐标

首先明确当AnchoredPosition为(0, 0)时它在哪

先看决定四个锚点位置的两个值,AnchorMin和AnchorMax,分别为(0, 0)和(1, 1)

讲一下RectTransform锚点,锚点是戳在该RectTransform的父对象上的,取值范围为[0, 1],实际转化成坐标时要将数对中的两个值分别 乘 父对象的长和宽。当父对象的长和宽均>=0时,锚点的(0, 0)点总是在父对象的左下角而(1, 1)点总是在父对象的右上角。若父对象的长宽存在负数,举个栗子,当父对象的长和宽均小于0时,锚点的(0, 0)将位于父对象的右上角而(1, 1)将位于父对象的左下角。

搞懂了锚点的机制之后你放屁再来看看layers的锚点,分别为(0, 0)和(1, 1),也就是框住了整个父对象,四个锚点围成的矩形尺寸也与父对象的尺寸相等,即(3813, 2456)

然后来整Pivot的位置。Pivot直译为“枢纽”,当RectTransform对象旋转时将绕该点旋转。其既确定了当AnchoredPosition为(0, 0)时“原点”的位置,也确定了自身在定义它的RectTransform对象内的位置。与锚点一样Pivot的取值范围为[0, 1]。确定“原点”坐标时,Pivot的两个值要分别 乘 其从属的RectTransform定义的锚点所围成的矩形的长和宽。前面提到layers的锚点矩形尺寸为(3813, 2456),Pivot的值为(0.5, 0.5),所以layers的AnchoredPosition的“原点”横坐标为3813 * 0.5 = 1906.5,纵坐标为2456 * 0.5 = 1228,即“原点”位于父对象的坐标为(1906.5, 1228)。同时也说明了layers的Pivot位于layers的正中心。

之后看AnchoredPosition的实际值,为(-36.568848, 439.746582)。这就是layers的Pivot相对于“原点”的偏移量。

讲一下RectTransform的坐标系。当一个点的横坐标增加时会往右走当其纵坐标增加时会向上走。

现在可以算layers的Pivot在xiefeierde_4上的坐标了。从“原点”出发,横坐标减少36.568848,纵坐标增加439.746582,向左再向上,可得坐标为(1869.931152, 1657.746582)。到此layers已经利用完了。

在这想提一嘴layers的尺寸,虽然用不到的。layers的SizeDelta是(-3822, -2480)。前面提到了:

“SizeDelta是由RectTransform对象的尺寸(长与宽) 减去 其定义的锚点所围成的矩形的尺寸”

而layers的锚点围成的矩形尺寸为(3813, 2456)

所以layers的长 - 3813 = -3822,其宽 - 2456 = -2480

也就是说layers的尺寸为(-9, -24)


最后把目光放到只有人没有琴的立绘,即xiefeierde_4_front。

要用到的是AnchorMin, AnchorMax, AnchoredPosition, SizeDelta和Pivot。首先观察AnchorMin和AnchorMax,都是(0.5, 0.5),所以四个锚点堆在一起,即锚点围成的矩形尺寸为(0, 0),可得xiefeierde_4_front的实际尺寸等于SizeDelta,即(1374, 2048)。根据上面提到的锚点的机制,可得xiefeierde_4_front的四个锚点都堆在layers的正中心,与layers的Pivot重合。而又因为xiefeierde_4_front的四个锚点堆在一起,所以可直接将xiefeierde_4_front的“原点”,即假设AnchoredPosition为(0, 0)时,直接视为锚点堆在一起的坐标,所以xiefeierde_4_front的“原点”的相对于xiefeierde_4的坐标等于layers的Pivot的坐标,即(1869.931152, 1657.746582)。之后便可求得xiefeierde_4_front的Pivot相对于xiefeierde_4的坐标。由(1869.931152, 1657.746582) 加上 AnchoredPosition的 (1240.699951, -280.399994);从“原点”出发,向右再向下。最后求得Pivot位于 (3110.631103, 1377.346588)。

还是不得不拿张图来说明(

*左侧是堆在一起的四个锚点,白框是xiefeierde_4_front的区域,蓝色实心点是矩形区域的四个顶点,蓝色空心圈是该RectTransform的Pivot*

为了方便使用Python的PIL库,现在要求矩形区域左上角的点。现在已经求得Pivot在xiefeierde_4上的坐标为 (3110.631103, 1377.346588)。Pivot的值为(0.490676, 0.666504),可求得Pivot在xiefeierde_4_front的矩形区域内坐标为(1374 * 0.490676, 2048 * 0.666504),即(674.188824, 1365.000192)。所以左侧框线距离Pivot 674.188824个单位,下方框线距离Pivot 1365.000192个单位;易得上方框线距离Pivot有 2048 - 1365.000192 = 682.999808 个单位。目标点位于Pivot的左上方,所以从Pivot出发,向左再向上,用Pivot相对于xiefeierde_4的坐标,横坐标 减去 674.188824,纵坐标 加上 682.999808个单位,得到目标点在xiefeierde_4上的坐标为 (2436.442279, 2060.346396)。因为PIL库使用的坐标系与RectTransform的不同,其y轴正方向与RectTransform的相反,向下的。所以求目标点的坐标还要用xiefeierde_4的宽 2456 - 2060.346396 = 395.653604。所以最后的精确结果为(2436.442279, 395.653604)。由于PIL的相关方法(method)的参数只接受整数,所以需要四舍五入,即结果为(2436, 396)。同时再加上坐标修正,(x+1, y-1),得 (2437, 395),这才是最终的结果。至于为什么会有个坐标修正,我是不清楚,也许是中途换坐标系所导致的误差或者Unity自己的锅。

然后来最后验证吧

一转VS Code

导入PIL包中的Image类

open打开琴的立绘,即最高级的父对象xiefeierde_4,赋给变量p_main

open打开人的立绘,即xiefeierde_4_front,赋给变量p_front

至于layers,工具人罢了

resize p_main,扩大到其原本的大小3813 x 2456,质量选最高质量Image.ANTIALIAS

将p_front粘贴到p_main上,位置为(2437, 395)

.show()方法 用图片查看器浏览图片

代码产生的临时预览,格式为bmp所以没有透明通道

完美~

至于两张图片的清晰度不同的问题,我是懒得解决的毕竟相关方法算法上限就摆在那opencv好麻烦而且我也不知道有没有效

*该思路同样适用于给无头立绘接头以及需要将更多立绘贴在一起的场合(比如能代的新皮肤)(懂的都懂)

随笔|用Unity帮助理解并解决瓜游立绘的拼图游戏的评论 (共 条)

分享到微博请遵守国家法律