天天看點

《iOS和tvOS 2D遊戲開發教程》——第2章,第2.4節挑戰

本節書摘來自異步社群《ios和tvos 2d遊戲開發教程》一書中的第2章,第2.4節挑戰,作者 【美】raywenderlich.com教程開發組,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

2.4 挑戰

本章有3個挑戰,它們都很重要。完成這些挑戰,能夠讓你練習使用向量,并且會引入新的數學工具,而在本書的剩下内容中,你将會用到這些工具。

同樣,如果遇到困難,可以從本章的資源檔案中找到解決方案,但是你最好是自己能夠解決它。

挑戰1:數學工具

你肯定已經注意到了,在開發這款遊戲的時候,經常要進行點和向量的計算,例如,把點相加和相減,求取長度值等等。我們還需要在cgfloat和double之間做很多強制轉型。

在本章中,到目前為止,我們都是以内嵌的方式自行完成這些計算的。這是做事情的一種很好的方式,但是,在實際工作中,這可能變得很繁瑣而且具有重複性;還容易出錯。

使用iossourceswift file模闆建立一個新的檔案,将其命名為myutils。然後,使用如下的代碼替換myutils的内容:

在swift中,可以讓+、-、*和/這樣的運算符作用于任何想要的類型之上。這裡,我們讓它們作用于cgpoint之上。

現在,可以像下面這樣來把點相加了,但是,不要在任何地方添加這些代碼;這裡隻是給出一個示例:

讓我們也覆寫cgpoints上的減法、乘法和除法運算符。在myutils.swift的末尾,添加如下的代碼:

現在,可以把一個cgpoint和另一個cgpoint相減、相乘和相除了。還可以将點和标量的cgfloat值相乘和相除,如下所示。同樣的,不要在任何地方添加這些代碼,這裡隻是給出一個示例。

最後,添加擴充了cgpoint的類,它帶有一些輔助方法:

當這個app在32位架構的機器上運作的時候,#if/#endif語句塊為true。在這種情況下,cgfloat和float具有相同的大小,是以,這段代碼編寫了接受cgfloat/float值(而不是預設的double)的atan2和sqrt版本;這就允許你對cgfloat/float使用atan2和sqrt,而不會受到裝置架構的限制。

接下來,這個類擴充添加了一些友善的方法來擷取點的長度,傳回該點的一個正規化的版本(即長度為1),并且得到該點的一個角度。

使用這些輔助函數,将會使得代碼更加簡潔和清晰。例如,來看看movesprite(velocity:)方法:

使用*将velocity和dt相乘,避免了強制轉型,簡化了第1行代碼。此外,使用+=運算符将精靈的位置和移動的量相加,簡化了最後一行代碼。

最終的結果應該如下所示:

你的挑戰是,修改剩下的zombie conga以使用新的輔助代碼,并且驗證遊戲仍然能夠像預期的那樣工作。當你完成之後,應該進行如下的調用,這包括對前面已經提及的兩個操作符的調用:

+=運算符:1次調用;

-運算符:1次調用;

*運算符:2次調用;

normalized:1次調用;

angle:1次調用。

你将會注意到,當完成了這些工作的時候,代碼變得整潔了很多,而且更加易于了解了。在後續的幾章中,你将要使用我們所編寫的一個數學庫,它和這裡所建立的數學庫非常相似。

挑戰2:讓僵屍停下來

在zombie conga,當你點選螢幕的時候,僵屍會朝着點選的位置移動,但是随後,它會繼續移動以超過該位置。

這是我們想要在zombie conga中得到的效果,但是,在其他的遊戲中,你可能想要讓僵屍在點選的位置停下來。你的挑戰是修改遊戲以做到這一點。

如下是針對一種可能的實作的一些提示:

建立一個名為lasttouchlocation的可選的屬性,并且當玩家觸摸場景的時候,更新這個屬性。

在update()中,檢查最近一次觸摸的位置和僵屍的位置之間的距離。如果這個距離小于或等于僵屍将要在目前幀中移動的距離(zombiemovepointspersec * dt),那麼就把僵屍的位置設定為最近一次觸摸的位置,并且将其速度設定為0。否則,正常地調用movesprite(velocity:)和rotatesprite(direction:)。應該還要調用boundscheckzombie()。

為了實作這些,要用到挑戰1中的輔助代碼,使用一次-運算符并且調用一次length()。

挑戰3:平滑移動

目前,僵屍會立即旋轉以面朝點選的位置。這可能有點突兀,如果僵屍随着時間的流逝逐漸平滑地旋轉以面朝新的方向的話,看上去會好很多。

為了做到這一點,需要一個新的輔助程式。将如下代碼添加到myutils.swift(to typeπ, use option-p)的末尾。

如果cgfloat大于或等于0,sign()傳回1,否則的話,它傳回-1。

shortestanglebetween()傳回兩個角之間的最短的角度。這并不是将兩個角相減那麼簡單,理由有兩個:

1.角度在超過360度(2 * m_pi)之後會“舍入”。換句話說,30度和390度表示相同的角度,如圖2-24所示。

2.有時候,兩個角之間旋轉最短的方式是向左,而有時候又是向右。例如,如果從0度開始,想要轉到270度,最短的方式是轉-90度,而不是轉270度,如圖2-25所示。我們不想讓僵屍轉一大圈,雖然它是僵屍,但是它并不蠢笨。

《iOS和tvOS 2D遊戲開發教程》——第2章,第2.4節挑戰

圖2-25 

是以,這個程式求得兩個角度之間的差,去掉任何比360度大的部分,然後确定是向右旋轉還是向左旋轉更快。

你的挑戰是修改rotatesprite(direction:),以接受并使用一個新的參數,即僵屍每秒應該旋轉的弧度數。

定義如下的常量:

let zombierotateradianspersec:cgfloat = 4.0 * π

并且将該方法的簽名修改為如下所示:

這裡針對這個方法的實作給出一些提示:

使用shortestanglebetween()找出目前角和目标角之間的距離,稱之為shortest。

根據rotateradianspersec和dt計算出在這一幀中要旋轉的量,稱之為amttorotate。

如果shortest的絕對值小于amttorotate,使用shortest來替代它。

将amttorotate加到精靈的zrotation中,但是先将其與sign()相乘,以便可以朝着正确的方向旋轉。

不要忘了在update()中更新對旋轉精靈的調用,以便它可以使用新參數。

如果你完成了所有這3個挑戰,做的真是不錯!你真的已經了解了如何使用“經典的”方法随着時間來更新值,進而移動和旋轉精靈。

然而,經典的方法隻是為了便于了解,它總是會讓步于現代的方法的。

在第3章中,我們将學習sprite kit如何通過神奇的動作,讓一些常見的任務變得非常容易。