Unity最近宣布推出額外的2D遊戲支持,添加了Box 2D物理和一個精靈管理器。
但這裏還是有些技巧需要牢記在心。逐幀更改圖像隻是動畫製作的冰山一角,若要讓你的遊戲出色運行,你還得使用轉換和旋轉等功能。
現在讓我們先從基本技巧開始。
更改幀 如果你已經準備好了製作動畫的紋理,你可能會使用SpriteManager腳本的付費版本,或者Unity的新版本。假設你使用的是2D位麵和紋理。這就是一個低效率的方法,但如果你是在製作一個game jam的項目,你可能會想塞入一些可行而好看,但卻不一定有效的元素。這也是一種覆蓋了所有步驟的全麵方法,如果是在精靈管理器中則可能被刪除某些步驟。
首先,你將需要一個公開的Texture[] 陣列,所以你可以將紋理拖入到Unity編輯器中的對象,以及一個在Start()中初始化到0的整數currentTexturep。下一步你需要一個像這樣運行的NextTexture() 函數:
NextTexture(){
currentTexture++;
if(currentTexture>=textureArray.Length) currentTexture=0;
AnimatedPlane.renderer.material.mainTexture = textureArray[currentTexture];}
有兩種簡便的方法可以調用這種函數:協同程序遞歸和固定間隔。
使用固定間隔是最快的方法(但較不精確)。你需要一個整數計數器,在你的Start()函數中初始化到0,以及一個FixedUpdate() 函數(注:每次都會更新,你可以在Unity時間管理器中自己調整)。
在FixedUpdate()中放置你的條件句(例如if(walking)),並在其中用conter++增加你的計時器,之後設置如下聲明:
if(counter>=animationDelay){
counter=0;
extTexture();
}
這裏的animationDelay可以是你自己選擇的任意值。這將以持續速度(取決於你在Unity時間管理器中設置的速度)推進幀。
第二個方法是使用遞歸。但這一方法的劣勢在於不易處理條件句,但你還是能夠獲得所需要的準確延時。如果你想讓特定幀延長或縮短,這一方法就尤其管用。你需要一個IEnumerator TextureChanger() 以及to StartCoroutine(TextureChanger()) in Start().
IEnumerator TextureChanger(){
yield return new WaitForSeconds(timeInterval);
if([conditions]) NextTexture();
}
這裏timeInterval也是你自己選擇的任意值。有了這些函數,你就可以將任意數量的紋理拖到GameObject,這樣隻要你提供正確的條件,它就會正確運行動畫。
現在讓我們做一些更有趣的操作。
平滑移動到一個點 以下公式是製作Unity 2D動畫的一個訣竅:
where 0 < slidespeed < 1. I recommend 0.1f as a good slidespeed value.
這個公式允許你把對象完美移動到一個點。在滑動GUI、角色控製、關卡生成、攝像跟隨、褪色/移位等操作中尤其管用。
descension
這是我即將發布的新遊戲《Rotation Station》中的一個高級版本,是從一個較低點移到一個較高點,最後變成一個小泡。每個貼圖都會根據該公司向下移動,但每個貼圖都有隨機的延時,隨機的初始化旋轉(也使用這一公式旋轉至它所期望的方向)。
關於角色控製的例子可以參考我最近推出的《Rude Bear Radio》,在這個項目中,該公式運用於製作流暢的鼠標控製方法。
Bearo-Wing
那麼,讓我們看看如何將其運用於上述例子。
首先,我們需要知道鼠標位於2D區域。為了找到它,我們要先將這個代碼放置於滑動GameObject的FixedUpdate()函數中:
Vector3 MousePosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
Input.mousePosition.y, transform.position.z-Camera.main.transform.position.z));
這裏使用了鼠標的X和Y軸位置,以及從攝像機到滑動GameObject的距離來確定鼠標的2D位置和3D坐標。現在我們要從這個環節的開端來調整該公式。所以,要記住Unity中的2D步驟。
transform.position += new Vector3((MousePosition.x-transform.position.x),
(MousePosition.y-transform.position.y),0)*slidespeed;
你就隻要這兩行代碼就搞定了!至於GUI這類東西,你可以在之後編寫一個聲明:
if(Mathf.Abs(finalvalue-currentvalue)
讓我們再看另一個例子,《Rude Bear Radio》中的困難模式Mario台階。
Super-Bario-Bros
其中的背景使用以下公式由黑變白:
background.renderer.material.color =
(1-factor)*background.renderer.material.color+factor*desiredcolor;
你從中可以看到它遵從的基本形式,簡寫就是Next = current+(final-current)*factor。代碼會檢查R值是否處於一定的色彩範圍,如果是,它就會更改factor,令其更為迅速地褪色。如果R值非常接近於1,它就會將其所需顏色設置為黑。你還可以檢查下R、G和B,並以一個陣列推進顏色。你可以在我的第二個案例項目《Rude Bear Rising》的背景中看到這種例子。
目前來看,這些都很簡單,你可以照搬公式做。而下一步操作則需要考慮更多因素。
三角法和數學的重要性 三角法對動畫製作來說非常重要。就算有了優秀的幀,也不一定能夠令它們看起來生動美麗,有時候你根本不需要幀就能做事。
例如,我首次進入Ludum Dare工作室時,我的室友就給我畫了幾張圖。我至今仍然記得其中的每個角色,用什麼方法呢?像木偶一樣將角色綁在棍子上操作。
RudeBear
這種移動方式非常簡單,轉換時用正弦(sin),旋轉時用餘弦(cos)。
為了創造這種動畫,你要讓波紋停止並在你鬆手和輸入時繼續,否則這種動作就會極端分散。
所以你需要一個首要變量(即我所謂的walkbob),隻要對象還在移動,它就會在FixedUpdate中增加Time.deltaTime。之後就製作你的函數:
translation = maxHeight*Mathf.Sin(speed*walkbob);
rotation = maxRoll*Mathf.Cos(speed*walkbob/2);
然後將位置和旋轉設為這些值(例如transform.position = new Vector3(transform.position.x,translation,transform.position.y))。
這可以處理類似那種動作,但是還有一種動畫需要考慮更多因素,這就是我所謂的三角舞,它用於製作可愛角色隨著音樂搖擺起舞,例如下圖:
Rude-Bear-Radio
首先,你在打算移動遊戲對象時,就要選取一個浮動的initialtime = Time.time,這樣你的對象才能以正確的位置和方向開始,並且不會突然跳入動作。
下一步,我們就要想想三角函數的概念。
我們使用簡諧運動,其形式如下:
Y是指當前值,A是振幅,f是頻率,t是運行時間,phi是指階段。首先,我們很容易確定振幅。它是我們希望對象所具有的最大化高度或旋轉。
下一個就是運行時間和階段。我們將用(Time.time-initialtime)輕鬆取代t而一次性處搞定這兩者。這會將φ降為0,所以最後我們隻需要得到頻率。我強烈推薦令此頻率與你的音樂頻率吻合(如果你是自己作曲,這一點很容易辦到)。
如果你還不知道自己音樂的BPM,那就去摸索每個節拍,直到弄懂為止。如果你已經有節奏感,這就很好辦了。如果你沒有,那也不用擔心,我們會利用中心極限定理。持續點觸你的整首歌,每欠點觸都會減少平均值中的錯誤。
現在你就知道它每分鍾如何打節拍了。你將以60來劃分這個值,找到每秒多少拍。如果你隻想在半小節或一個完整的小節中使用一次動作,那就可以按2或4數值來劃分。這個數值就是頻率,你可以從 Mathf.PI獲得pi。所以現在你要將對象的位置設為該數值。此時你隻是在調整高度:
transform.position = new Vector3(transform.position.x,maxheight*
Mathf.Sin(2*Mathf.PI*frequency*(Time.time-initialtime)),transform.position.z);
但這還不夠好。首先,我們要讓對象合拍,這樣它就得從其最大振幅開始。我們此時要使用餘弦。但更重要的是,要讓它從一端跳躍到另一端,這樣它就不會像波紋一樣滑上滑下。這時要用cos^2,這樣它才會突然停在0標記,並再次走向正數。因此:
transform.position = new Vector3(transform.position.x,maxheight*Mathf.Pow(Mathf.Cos(
2*Mathf.PI*frequency*(Time.time-initialtime)),2),transform.position.z)
這裏要注意舞動的高度。最終旋轉要使用正弦,這樣其旋轉和轉化就是異相的。因此:
transform.rotation = Quaternion.EulerAngles(0, maxRotation*
Mathf.Cos(2*Mathf.PI*frequency*Mathf.Sin(Time.time-initialtime)), 0);
這裏要記住兩件事:如果你使用一個位麵,並希望它麵對攝像機,這些值就不能是0和0,而必須是pi/2和–pi/2。這裏我使用的是EulerAngles而不是Euler,因為Euler使用的是度數,而EulerAngles使用的是弧度。我們要做一些數學運算,我們現在要運用弧度,所以得使用EulerAngles!否則你之扣就得輸入一個換算因數。
在此你可以看到我新遊戲的一種類似動畫,你可以用同種方法更改比例而不是位置。
RoStlogo
現在我們要討論最後一種動畫類型:
紋理補償
你可以用自己所學到的一切來操作2D紋理補償,以製作美妙的動畫背景。你可以在《Rude Bear Radio》及其主界麵中看到我對《VVVVVV》的拙劣模仿。抓取一個位麵,在其上粘附一個重複紋理,編寫一個FixedUpdate() 函數,並根據下屬性進行調整:
renderer.material.mainTextureOffset
renderer.material.color
這將導致牆體四處滑動並改變顏色。最後,如果你想讓它們看起來更有趣,還可以運用renderer.material.mainTextureScale。這可以製作一個真正有趣的視覺效果,但它很有幹擾性,不要讓它影響你的主要遊戲玩法。