隨筆|用Unity幫助理解并解決瓜游立繪的拼圖游戲

前排提示:打開Unity一步步捏幾個(gè)2D對(duì)象對(duì)理解該文幫助巨大。記得使用Inspector的Debug模式而不是Normal
因?yàn)樘珡?fù)雜了怕我自己忘了所以寫的比較詳細(xì)
拿謝菲的皮膚作為栗子吧

手頭有兩張立繪 至于怎么來(lái)的,我只能說(shuō)懂的都懂不懂也沒(méi)必要懂
想把他們拼在一起,咋整
用Photoshop吧,得一點(diǎn)一點(diǎn)扣細(xì)節(jié),而且無(wú)法直接拼,這兩張圖片的尺寸差別太大


所以肯定要調(diào)整尺寸。這就更要命了,其一用PS慢慢調(diào)不方便而且要花很多時(shí)間,畢竟光看圖的話精確的原本的尺寸不得而知;其二黃雞還準(zhǔn)備了很多拼圖給你玩(
這對(duì)我這個(gè)追求完美同時(shí)又是條懶狗的人來(lái)說(shuō)是不能接受的(
那咋整啊
游戲咋整的我就咋整
首先在painting文件夾里找到個(gè)叫xiefeierde_4的無(wú)后綴無(wú)擴(kuò)展名文件,用點(diǎn)什么手段打開它,然后找到這么個(gè)東西

打開它,一路點(diǎn)開直到找到RectTransform Base,這是我們要的,同時(shí)我們也知道了其上的GameObject類對(duì)象名字是xiefeierde_4_front(略顯廢話

把它的大部分子項(xiàng)展開

戳開它的m_Father項(xiàng),可以看到另一個(gè)RectTransform Base

故技重施,把這個(gè)RectTransform Base的子項(xiàng)都展開。這次瞅瞅它的第一項(xiàng)GameObject類的m_GameObject。將其一直展開至此

易得該GameObject類對(duì)象叫l(wèi)ayers。
這個(gè)RectTransform對(duì)象也有個(gè)m_Father,故技重施。

這個(gè)GameObject類對(duì)象的名字是xiefeierde_4。再康康它的RectTransform的m_Father

已經(jīng)再?zèng)]有對(duì)象了,說(shuō)明該RectTransform是最頂層的
由此我們得到了 xiefeierde_4 -> layers -> xiefeierde_4_front 的父對(duì)象和子對(duì)象的套娃關(guān)系。
接下來(lái)收集我們需要的數(shù)據(jù)
為了方便,以下將直接把GameObject對(duì)象的名字用作指代稱呼其對(duì)應(yīng)的RectTransform對(duì)象
先來(lái)看xiefeierde_4的RectTransform Base,它是所有人的父對(duì)象。

對(duì)我們的目的來(lái)說(shuō)其實(shí)只有SizeDelta有用。
這里講一下根據(jù)SizeDelta求得RectTransform對(duì)象的Size
看它的AnchorMin,這是矩形左下角的點(diǎn)。它的AnchorMax,這是矩形右上角的點(diǎn)
在這里AnchorMin和AnchorMax都是(0.5, 0.5),易得該矩形的左下角和右上角兩點(diǎn)重合在一起
所以位于矩形四個(gè)角的四個(gè)錨點(diǎn)圍成的矩形的尺寸為(0, 0)
而SizeDelta是由RectTransform對(duì)象的尺寸(長(zhǎng)與寬) 減去 其定義的錨點(diǎn)所圍成的矩形的尺寸
由此可得xiefeierde_4的原始尺寸為(3813, 2456)
也就是說(shuō)只有琴的部分的立繪原始尺寸為3813x2456
其實(shí)到這一步就可以把圖丟進(jìn)PS了,不過(guò)已經(jīng)到這步了為了方便寫程序我選擇貫徹到底(
之后看看xiefeierde_4的子對(duì)象layers

這里我們需要的有l(wèi)ayers的AnchorMin, AnchorMax, AnchoredPosition和Pivot。這幾個(gè)值描述了layers的Pivot對(duì)于其父對(duì)象即xiefeierde_4的相對(duì)位置。
那么來(lái)算吧,layers的Pivot位于xiefeierde_4的坐標(biāo)
首先明確當(dāng)AnchoredPosition為(0, 0)時(shí)它在哪
先看決定四個(gè)錨點(diǎn)位置的兩個(gè)值,AnchorMin和AnchorMax,分別為(0, 0)和(1, 1)
講一下RectTransform錨點(diǎn),錨點(diǎn)是戳在該RectTransform的父對(duì)象上的,取值范圍為[0, 1],實(shí)際轉(zhuǎn)化成坐標(biāo)時(shí)要將數(shù)對(duì)中的兩個(gè)值分別 乘 父對(duì)象的長(zhǎng)和寬。當(dāng)父對(duì)象的長(zhǎng)和寬均>=0時(shí),錨點(diǎn)的(0, 0)點(diǎn)總是在父對(duì)象的左下角而(1, 1)點(diǎn)總是在父對(duì)象的右上角。若父對(duì)象的長(zhǎng)寬存在負(fù)數(shù),舉個(gè)栗子,當(dāng)父對(duì)象的長(zhǎng)和寬均小于0時(shí),錨點(diǎn)的(0, 0)將位于父對(duì)象的右上角而(1, 1)將位于父對(duì)象的左下角。
搞懂了錨點(diǎn)的機(jī)制之后你放屁再來(lái)看看layers的錨點(diǎn),分別為(0, 0)和(1,?1),也就是框住了整個(gè)父對(duì)象,四個(gè)錨點(diǎn)圍成的矩形尺寸也與父對(duì)象的尺寸相等,即(3813, 2456)
然后來(lái)整Pivot的位置。Pivot直譯為“樞紐”,當(dāng)RectTransform對(duì)象旋轉(zhuǎn)時(shí)將繞該點(diǎn)旋轉(zhuǎn)。其既確定了當(dāng)AnchoredPosition為(0, 0)時(shí)“原點(diǎn)”的位置,也確定了自身在定義它的RectTransform對(duì)象內(nèi)的位置。與錨點(diǎn)一樣Pivot的取值范圍為[0, 1]。確定“原點(diǎn)”坐標(biāo)時(shí),Pivot的兩個(gè)值要分別 乘 其從屬的RectTransform定義的錨點(diǎn)所圍成的矩形的長(zhǎng)和寬。前面提到layers的錨點(diǎn)矩形尺寸為(3813, 2456),Pivot的值為(0.5, 0.5),所以layers的AnchoredPosition的“原點(diǎn)”橫坐標(biāo)為3813 * 0.5 = 1906.5,縱坐標(biāo)為2456 * 0.5 = 1228,即“原點(diǎn)”位于父對(duì)象的坐標(biāo)為(1906.5, 1228)。同時(shí)也說(shuō)明了layers的Pivot位于layers的正中心。
之后看AnchoredPosition的實(shí)際值,為(-36.568848, 439.746582)。這就是layers的Pivot相對(duì)于“原點(diǎn)”的偏移量。
講一下RectTransform的坐標(biāo)系。當(dāng)一個(gè)點(diǎn)的橫坐標(biāo)增加時(shí)會(huì)往右走當(dāng)其縱坐標(biāo)增加時(shí)會(huì)向上走。
現(xiàn)在可以算layers的Pivot在xiefeierde_4上的坐標(biāo)了。從“原點(diǎn)”出發(fā),橫坐標(biāo)減少36.568848,縱坐標(biāo)增加439.746582,向左再向上,可得坐標(biāo)為(1869.931152, 1657.746582)。到此layers已經(jīng)利用完了。
在這想提一嘴layers的尺寸,雖然用不到的。layers的SizeDelta是(-3822, -2480)。前面提到了:
“SizeDelta是由RectTransform對(duì)象的尺寸(長(zhǎng)與寬) 減去 其定義的錨點(diǎn)所圍成的矩形的尺寸”
而layers的錨點(diǎn)圍成的矩形尺寸為(3813, 2456)
所以layers的長(zhǎng) - 3813 = -3822,其寬 - 2456 = -2480
也就是說(shuō)layers的尺寸為(-9, -24)
最后把目光放到只有人沒(méi)有琴的立繪,即xiefeierde_4_front。

要用到的是AnchorMin, AnchorMax, AnchoredPosition, SizeDelta和Pivot。首先觀察AnchorMin和AnchorMax,都是(0.5, 0.5),所以四個(gè)錨點(diǎn)堆在一起,即錨點(diǎn)圍成的矩形尺寸為(0, 0),可得xiefeierde_4_front的實(shí)際尺寸等于SizeDelta,即(1374, 2048)。根據(jù)上面提到的錨點(diǎn)的機(jī)制,可得xiefeierde_4_front的四個(gè)錨點(diǎn)都堆在layers的正中心,與layers的Pivot重合。而又因?yàn)閤iefeierde_4_front的四個(gè)錨點(diǎn)堆在一起,所以可直接將xiefeierde_4_front的“原點(diǎn)”,即假設(shè)AnchoredPosition為(0, 0)時(shí),直接視為錨點(diǎn)堆在一起的坐標(biāo),所以xiefeierde_4_front的“原點(diǎn)”的相對(duì)于xiefeierde_4的坐標(biāo)等于layers的Pivot的坐標(biāo),即(1869.931152, 1657.746582)。之后便可求得xiefeierde_4_front的Pivot相對(duì)于xiefeierde_4的坐標(biāo)。由(1869.931152, 1657.746582) 加上 AnchoredPosition的 (1240.699951, -280.399994);從“原點(diǎn)”出發(fā),向右再向下。最后求得Pivot位于 (3110.631103, 1377.346588)。

*左側(cè)是堆在一起的四個(gè)錨點(diǎn),白框是xiefeierde_4_front的區(qū)域,藍(lán)色實(shí)心點(diǎn)是矩形區(qū)域的四個(gè)頂點(diǎn),藍(lán)色空心圈是該RectTransform的Pivot*
為了方便使用Python的PIL庫(kù),現(xiàn)在要求矩形區(qū)域左上角的點(diǎn)?,F(xiàn)在已經(jīng)求得Pivot在xiefeierde_4上的坐標(biāo)為?(3110.631103, 1377.346588)。Pivot的值為(0.490676, 0.666504),可求得Pivot在xiefeierde_4_front的矩形區(qū)域內(nèi)坐標(biāo)為(1374 * 0.490676, 2048 * 0.666504),即(674.188824, 1365.000192)。所以左側(cè)框線距離Pivot 674.188824個(gè)單位,下方框線距離Pivot 1365.000192個(gè)單位;易得上方框線距離Pivot有 2048 - 1365.000192 = 682.999808 個(gè)單位。目標(biāo)點(diǎn)位于Pivot的左上方,所以從Pivot出發(fā),向左再向上,用Pivot相對(duì)于xiefeierde_4的坐標(biāo),橫坐標(biāo) 減去 674.188824,縱坐標(biāo) 加上 682.999808個(gè)單位,得到目標(biāo)點(diǎn)在xiefeierde_4上的坐標(biāo)為 (2436.442279, 2060.346396)。因?yàn)镻IL庫(kù)使用的坐標(biāo)系與RectTransform的不同,其y軸正方向與RectTransform的相反,向下的。所以求目標(biāo)點(diǎn)的坐標(biāo)還要用xiefeierde_4的寬 2456 - 2060.346396 = 395.653604。所以最后的精確結(jié)果為(2436.442279, 395.653604)。由于PIL的相關(guān)方法(method)的參數(shù)只接受整數(shù),所以需要四舍五入,即結(jié)果為(2436, 396)。同時(shí)再加上坐標(biāo)修正,(x+1, y-1),得 (2437, 395),這才是最終的結(jié)果。至于為什么會(huì)有個(gè)坐標(biāo)修正,我是不清楚,也許是中途換坐標(biāo)系所導(dǎo)致的誤差或者Unity自己的鍋。
然后來(lái)最后驗(yàn)證吧

導(dǎo)入PIL包中的Image類
open打開琴的立繪,即最高級(jí)的父對(duì)象xiefeierde_4,賦給變量p_main
open打開人的立繪,即xiefeierde_4_front,賦給變量p_front
至于layers,工具人罷了
resize p_main,擴(kuò)大到其原本的大小3813 x 2456,質(zhì)量選最高質(zhì)量Image.ANTIALIAS
將p_front粘貼到p_main上,位置為(2437, 395)
.show()方法 用圖片查看器瀏覽圖片

完美~
至于兩張圖片的清晰度不同的問(wèn)題,我是懶得解決的畢竟相關(guān)方法算法上限就擺在那opencv好麻煩而且我也不知道有沒(méi)有效
*該思路同樣適用于給無(wú)頭立繪接頭以及需要將更多立繪貼在一起的場(chǎng)合(比如能代的新皮膚)(懂的都懂)