1. 程式人生 > >Unity3D遊戲開發從零單排(四) - 制作一個iOS遊戲

Unity3D遊戲開發從零單排(四) - 制作一個iOS遊戲

tint shade 私有 在屏幕上 type return 移動 begin document

提要

? ? ? ?此篇是一個國外教程的翻譯。盡管有點老,可是適合新手入門。自己去寫代碼。debug,布置場景。能夠收獲到非常多。

遊戲邦上已經有前面兩部分的譯文。這裏翻譯的是遊戲的最後一個部分。


歡迎回來

在第一篇中,我們學會了怎麽在Unity中搭建遊戲的場景,而且設置模型的物理屬性。

在第二篇中,我們學會了怎麽在unity中使用腳本,而且創建了大部分的遊戲邏輯,包括投球和得分!

在這最後一節中。我們將會為用戶創建一個菜單系統,而且和GameController進行交互,我們開始吧。


在設備上測試

到眼下為止。我們僅僅在unity內建的模擬器中進行了測試。

如今你的項目能夠正常執行了,是時候讓他在真實的設備裏跑跑測試了。

點擊菜單條 File->Build Setting.你懊悔看到以下的對話框:

首先。確定你選擇對了平臺(iOS旁邊應該有一個unity的標誌,假設沒有,選擇iOS,然後點Switch Platform)

選擇Player Settings,在inspector面板中就能夠對遊戲進行編譯設置。

技術分享圖片


(譯註:Android平臺的執行能夠參考 - Unity3D遊戲開發從零單排(一) - 真機執行)


這裏有一大堆能夠設置的東西。可是如今你真正須要關心的是保證遊戲的屏幕方向是正確的。

在Resoluion and Presentation面板中的devices orientation的下拉選框中選擇Landscape-Left。其它保持默認。接下來是Other Settings。

技術分享圖片

在這個部分你須要輸入你的developer Bundle Identifier(和在XCode裏面一樣),余下的部分保持默認。


是時候動真格的了

當你設置好編譯的依稀選項之後,回到Build Setting對話框,點Build。

Unity將會彈出一個選擇項目位置的對話框。當你選擇好存儲位置後,Unity將會啟動XCode執行項目。而且準備好了編譯和執行項目了。

註意:不要僅僅在模擬器裏跑你的遊戲,由於Unity僅僅提供了iOS的設備。在你的移動設備上去跑遊戲。點這裏查看跟多相關的內容。

技術分享圖片

執行成功之後。接下來就是為你的遊戲制作一個簡單的菜單了。


保存分數

首先下載這個資源,裏面包括了一些工具類來處理數據的存儲和讀取。

解壓壓縮包,將裏面的.cs文件拖到項目的Scripts目錄中。

數據存儲的這些類的實現並不在教程範圍內,以下我們寫一個小的測試來學習怎樣使用它。


在場景中創建一個空的GameObject,將LeadeboardController腳本拖上去。

再在這個GameObject上加入一個腳本組件,命名為LeaderboardControllerTest,測試的內容是存儲一些分數,然後再取回來。


你須要在測試類中索引LeaderboardController。加入一個LeaderboarfController的公有數據成員,代碼例如以下:

using UnityEngine;
using System.Collections.Generic;
using System.Collections;
 
public class LeaderboardControllerTest : MonoBehaviour {
	public LeaderboardController leaderboard; 
 
	void Start () {	
	}
 
	void Update () {	
	}
}

註:註意 using System.Collections.Generic;放在類的最上面。這是引入相關的包,在以下的包中你就能夠使用Generric中的特有的collections了。關於Generic包的文檔能夠參見這裏。


使用LeaderboardController中的AddPlayerScore方法來測試:

	void Start () {
		leaderboard.AddPlayersScore( 100 ); 
		leaderboard.AddPlayersScore( 200 ); 				
	}
這樣就能夠將分數保存在閃存中。即使關掉應用。數據還是能夠取回來。為了取回數據,須要註冊LeaderboardControllers的OnScoresLoaded方法。同一時候還要實現相應的handler函數,代碼例如以下.

順便提一下 - 異步調用的方式能夠同意你去擴展LeaderboardController,假設你想的話,讓它能夠處理一個遠程的leaderboard。

	void Start () {
		leaderboard.OnScoresLoaded += Handle_OnScoresLoaded; 
 
		leaderboard.AddPlayersScore( 100 ); 
		leaderboard.AddPlayersScore( 200 );
 
		leaderboard.FetchScores();
	}
 
	public void Handle_OnScoresLoaded( List<ScoreData> scores ){		
		foreach( ScoreData score in scores ){
			Debug.Log ( score.points );
		}
	}

參數List傳回的是ScoreData對象的一個list。ScoreData是一個簡單數據對象,將分數進行了了一個簡單的封裝。

在Handle_OnScoresLoaded方法中將會遍歷每一個每一個分數對象,然後將分數打印輸出。這就是我們想要的。就是這樣。

接下來要執行看看了:

創建一個新的GameObject,命名為LeaderboardControllder,將LeaderboardController.cs加入上去。

選定LeaderboardContrillerTest對象,將LeaderboardControllder賦給腳本中相應的公有成員。

點執行,看分數是不是在終端現實了!


創建一個簡單的菜單

是時候做點讓人興奮的新東西了 —— 你將會學到怎樣創建一個遊戲菜單!

以下是我們將要做成的樣子:

在Unity3D中實現用戶界面有3種方式,每一種都各有優缺點,以下就細致討論一下。

1)GUI

Unity提供了一套自己定義的用戶界面,通過MonoBehaviour的回調函數OnGUI來處理事件,Unity支持用皮膚來改變這些界面的外觀。

對於那些不是非常在意性能的設備,這是一個非常理想的解決方式。它提供了非常豐富的預設控制。可是考慮到性能問題,自帶的GUI不應該在遊戲進行時出現。

2)GUITexture和GUIText

Unity提供了兩個組件,GUITexture和GUIText,這兩個組件能夠讓你能夠在屏幕上呈現2D的圖像和文字。

你能夠非常方便地通過擴展這兩個組件來創建自己的用戶界面,相比於GUI 組件,性能上優秀非常多。

3)3D Planes/Texture Altas

假設你要創建一個在遊戲頂層現實的菜單(比方HUD),那麽這個就是最好的選擇。即使這個最麻煩!:] 可是一旦你創建好了頂層顯示的相關類。你就非常easy將它們適用在其它的新的項目中。

3D planes即用一套3D 平面來實現HUD,這些3D平面關聯著同一個紋理集合,紋理集合就是將一些細小的紋理拼接在一起。組成一張大的紋理圖片(譯註:分辨率通常為2

的n次方,方面一次性載入到內存)。這個和Cocos2D中的sprite sheet的概念相似!:]

由於各個HUD共享的是同一個材質(指向同一個紋理),通常僅僅須要一個調用就能夠將HUD全部渲染出來。

在大部分情況下,你須要為HUD創建一個專用的攝像機。讓它們看起來是正交投影的,而不是透視投影的(指的是攝像機的種類)。

在這個遊戲中,我們的選擇是第一種。Unity自帶GUI。

除了上面我們提到的它的一些缺點,它最大的優點就是有預置的控制,能夠讓這篇教程更簡單一些。

以下我們首先為主菜單創建皮膚。然後你完畢渲染主菜單的代碼,最後將它鏈接到GameController上。

聽起來是不是非常棒。那即可動吧,少年!:]


皮膚

Unity提供了一種叫Skin的東西來裝飾GUI。這個東西能夠簡單的類比成Html的CSS。


我已經創建好了兩個Skin(在第一部分的教程中已經導入到工程裏面了),一個是480*320的分辨率,還有一個是960*640的用於是視網膜屏幕的。以下的圖片是480*320的Skin的屬性。

技術分享圖片


Skin的屬性文件有非常多的選項,讓你能夠為你的項目創建獨一無二的屬性。在這個項目中,你僅僅須要關心字體。

接下來打開GameMenuSmall,將scoreboard字體拖拽到Font屬性而且將字體設置到16. 打開GameMenuNormal,將scoreboard字體拖拽到Font屬性而且將字體設置到32.下一步就是制作真真的主菜單了!


主菜單


編譯執行

像之前做的一樣,File->Build Settings.點擊buildbutton。開始測試你的第一個遊戲吧!

技術分享圖片


編譯並執行XCode項目。你就能夠在你的設備上看到一個美麗的而且能夠work的菜單了。


主菜單

這個部分主要是GameMenuController的代碼,負責渲染主菜單而且處理用戶的輸入。以下是代碼中比較重要的片段,終於都會和遊戲連接起來。

創建一個名為GameMenuController的腳本,創建以下的一些變量。

using UnityEngine;
using System.Collections;
 
[RequireComponent (typeof (LeaderboardController))]
public class GameMenuController : MonoBehaviour {
 
	public Texture2D backgroundTex; 	
	public Texture2D playButtonTex; 	
	public Texture2D resumeButtonTex; 	
	public Texture2D restartButtonTex; 
	public Texture2D titleTex; 
	public Texture2D leaderboardBgTex; 
	public Texture2D loginCopyTex; 
	public Texture2D fbButtonTex; 
	public Texture2D instructionsTex; 
 
	public GUISkin gameMenuGUISkinForSmall; 
	public GUISkin gameMenuGUISkinForNormal; 
 
	public float fadeSpeed = 1.0f; 
	private float _globalTintAlpha = 0.0f; 		
 
	private GameController _gameController; 		
	private LeaderboardController _leaderboardController; 
	private List<ScoreData> _scores = null;
 
	public const float kDesignWidth = 960f; 
	public const float kDesignHeight = 640f; 
 
	private float _scale = 1.0f; 	
	private Vector2 _scaleOffset = Vector2.one; 
 
	private bool _showInstructions = false; 	
	private int _gamesPlayedThisSession = 0; 
}

首先。裏面有一系列的公有成員。能夠在unity中通過拖拽對象來設置。這些變量是渲染主菜單的各個元素。接下來的兩個變量變量來索引之前創建的那兩個Skin。

再以下的變量時用來淡入淡出主菜單。我們也須要用私有變量來索引GameController和LeaderboardController來獲得分數對象。

接下來是一系列用於處理屏幕分辨率的變量,比方iPhone 3GS(480*420)和iPhone4(960*360)。最後是用來管理GameMenuController的組件狀態的變量。

加入Awake()和Start()方法,例如以下:

        void Awake(){
		_gameController = GetComponent<GameController>(); 
		_leaderboardController = GetComponent<LeaderboardController>(); 
	}		
 
	void Start(){
		_scaleOffset.x = Screen.width / kDesignWidth;
		_scaleOffset.y = Screen.height / kDesignHeight;
		_scale = Mathf.Max( _scaleOffset.x, _scaleOffset.y ); 
 
		_leaderboardController.OnScoresLoaded += HandleLeaderboardControllerOnScoresLoaded;
 
		_leaderboardController.FetchScores(); 
	}

在Start方法中。從LeaderboardController中獲得score對象。同一時候,計算出和屏幕分辨率相關的一些比例,讓Gui能夠自適應,

代碼中scale offsets用來保證GUI元素能夠正常地縮放。比方。假設一個菜單是960*640的,當前設備的分辨率是480*320。然後你須要做的就是將菜單縮小50%,那麽scaleOffset就是0.5. 這麽做在簡單的多分辨率設備的適配中會非常不錯,你不須要反復創建資源。

一旦scores載入完畢,在本地存儲起來,將會用來渲染GUI.

	public void HandleLeaderboardControllerOnScoresLoaded( List<ScoreData> scores ){
		_scores = scores; 
	}

測試測試!

讓我們略微歇息一下,測試測試眼下為止我們所做的東西。

在GameMenuController中加入以下的code:

	void OnGUI () {
		GUI.DrawTexture( new Rect( 0, 0, Screen.width, Screen.height ), backgroundTex ); 
		if (GUI.Button( new Rect ( 77 * _scaleOffset.x, 345 * _scaleOffset.y, 130 * _scale, 130 * _scale ), resumeButtonTex, GUIStyle.none) ){
			Debug.Log( "Click" );  
		}
	}

上面的代碼片段主要是OnGUI函數的寫法,這個函數的行為相似於Update(),而且提供了對GUI Component的讀取,GUI Component提供了一系列的靜態方法來實現標準的用戶控制。點我去官方站點學習很多其它的OnGui和GUI類。

第一句話是用一張紋理繪制整個屏幕。

GUI.DrawTexture( new Rect( 0, 0, Screen.width, Screen.height ), backgroundTex );

接下來用的推斷語句中,GUI.Button方法在指定的一個地方渲染一個Button(用之前我們計算的縮放比例來定位)。這種方法的返回值和用戶是否點擊這個Button有關。點了就是true,沒點是false.

if (GUI.Button( new Rect ( 77 * _scaleOffset.x, 345 * _scaleOffset.y, 130 * _scale, 130 * _scale ), resumeButtonTex, GUIStyle.none) ){
			Debug.Log( "Click" );  
		}

上面的代碼中,假設用戶點擊了button,console中就會打印Click。

為了測試,將GameMenuController腳本附加到GameController上。將相應的公有變量拖拽上去。例如以下圖:

技術分享圖片

如今測試吧,點擊執行,你會開發出現了一個button。點擊它你就能夠在終端看到打印的信息。


技術分享圖片

還不賴吧?完畢菜單的第一步就搞定了!:]


使用skins

如今你確定了你的方向找對了。接下來依據屏幕的尺寸來設置skin。

用以下的代碼來替換OnGUI函數:

if( _scale < 1 ){
	GUI.skin = gameMenuGUISkinForSmall; 
} else{
	GUI.skin = gameMenuGUISkinForNormal;	
}

skins能夠確保你使用正確的字體大小(依據屏幕尺寸);使用哪一個skin是依據前面計算的_scale值。

假設_scale小於1.0就使用small skin,不是的話就是使用normal skin。


顯示和隱藏

相比於粗魯地彈出菜單,用淡入淡出來處理是更好的選擇。為了實現淡入淡出,我們須要處理GUI的static 變量 content Color (這回影響到GUI類裏繪制的全部內容)。

為了處理淡入。你應該慢慢地將_globalTintAlpha的值從0添加到1.然後將它賦給GUI.contenColor變量。將西面的代碼加入OnGUI函數:

_globalTintAlpha = Mathf.Min( 1.0f, Mathf.Lerp( _globalTintAlpha, 1.0f, Time.deltaTime * fadeSpeed ) ); 
 
Color c = GUI.contentColor;	
c.a = _globalTintAlpha; 
GUI.contentColor = c;

你須要一些方法來顯示和隱藏菜單,創建以下兩個方法,Show和Hide:

	public void Show(){
		// ignore if you are already enabled
		if( this.enabled ){
			return; 	
		}
		_globalTintAlpha = 0.0f; 
		_leaderboardController.FetchScores(); 
		this.enabled = true; 
	}
 
	public void Hide(){
		this.enabled = false; 
	}

代碼沒啥好說的,

菜單顯示的內容依據遊戲的狀態不同,內容也不同,比方當遊戲結束的時候菜單的內容就和暫停時顯示的菜單不一樣。

在OnGUI函數中加入以下的代碼:

GUI.DrawTexture( new Rect( 0, 0, Screen.width, Screen.height ), backgroundTex ); 
 
	if( _gameController.State == GameController.GameStateEnum.Paused ){				
		if (GUI.Button( new Rect ( 77 * _scaleOffset.x, 345 * _scaleOffset.y, 130 * _scale, 130 * _scale ), resumeButtonTex, GUIStyle.none) ){
			_gameController.ResumeGame(); 
		}
 
		if (GUI.Button( new Rect ( 229 * _scaleOffset.x, 357 * _scaleOffset.y, 100 * _scale, 100 * _scale ), restartButtonTex, GUIStyle.none) ){
			_gameController.StartNewGame(); 				
		}
	} else{
		if (GUI.Button( new Rect ( 77 * _scaleOffset.x, 345 * _scaleOffset.y, 130 * _scale, 130 * _scale ), playButtonTex, GUIStyle.none) )
		{
			if( _showInstructions || _gamesPlayedThisSession > 0 ){
				_showInstructions = false; 
				_gamesPlayedThisSession++; 
				_gameController.StartNewGame(); 
			} else{
				_showInstructions = true; 	
			}
		}
	}

你應該非常熟悉這些代碼,就是依據遊戲的狀態渲染相應的紋理和button。

暫停狀態下的兩個button分別同意玩家返回和又一次開始:

	if (GUI.Button( new Rect ( 77 * _scaleOffset.x, 345 * _scaleOffset.y, 130 * _scale, 130 * _scale ), resumeButtonTex, GUIStyle.none) ){
		_gameController.ResumeGame(); 
	}
 
	if (GUI.Button( new Rect ( 229 * _scaleOffset.x, 357 * _scaleOffset.y, 100 * _scale, 100 * _scale ), restartButtonTex, GUIStyle.none) ){
		_gameController.StartNewGame(); 				
	}


註:想知道我是怎麽知道那些精確的尺寸的?答案是使用GIMP!


還有一個狀態是GameOver,這個時候你須要渲染開始button。

註:你可能註意到了兩個變量 _showInstructions 和 _gamesPlayerdThisSession 。_gamesPlayerThisSession是用來記錄當前你玩了多少場遊戲的,假設是一次,那麽 _showInstructions 就為真。那麽我們就能夠在玩家開始玩遊戲之前給出一些遊戲提示。


(譯註:這兩個變量都作為GameMenuController的私有成員)


是時候測試了

在完畢GameMenuController之前。確保如今的每一個功能都如預期那樣工作。一切都設置好了之後。你就能夠看到和以下相似的畫面了:


技術分享圖片


完畢GameMenuController

最後要完畢的是標題,提示還有分數。

繪制標題還是提示是依據上面提到的?_showInstructions 標誌位。將以下的代碼加入在OnGUI方法的最以下:

if( _showInstructions ){		
	GUI.DrawTexture( new Rect( 67 * _scaleOffset.x, 80 * _scaleOffset.y, 510 * _scale, 309 * _scale ), instructionsTex );										
} else{
	GUI.DrawTexture( new Rect( 67 * _scaleOffset.x, 188 * _scaleOffset.y, 447 * _scale, 113 * _scale ), titleTex );
}

註意,最後的代碼是處理分數板的,OnGUI提供了groups。你能夠通過group將東西放在一起,至於某個層(豎著的或者橫著的)。以下的代碼是繪制leaderboard和一些

簡單的button,用於關聯facebook和Twitter,然後將全部分數一個個加起來。將以下的代碼加入在OnGUI方法的最以下:

	GUI.BeginGroup( new Rect( Screen.width - (214 + 10) * _scale, (Screen.height - (603 * _scale)) / 2, 215 * _scale, 603 * _scale ) ); 
 
	GUI.DrawTexture( new Rect( 0, 0, 215 * _scale, 603 * _scale ), leaderboardBgTex );
 
	Rect leaderboardTable = new Rect( 17 * _scaleOffset.x, 50 * _scaleOffset.y, 180 * _scale, 534 * _scale ); 
	if( _leaderboardController.IsFacebookAvailable && !_leaderboardController.IsLoggedIn ){			
		leaderboardTable = new Rect( 17 * _scaleOffset.x, 50 * _scaleOffset.y, 180 * _scale, 410 * _scale ); 
		GUI.DrawTexture( new Rect( 29* _scaleOffset.x, 477* _scaleOffset.y, 156 * _scale, 42 * _scale ), loginCopyTex );
		if (GUI.Button( new Rect ( 41 * _scaleOffset.x, 529 * _scaleOffset.y, 135 * _scale, 50 * _scale ), fbButtonTex, GUIStyle.none) )
		{
			_leaderboardController.LoginToFacebook(); 
		}			
	} 			
	GUI.BeginGroup( leaderboardTable ); 			
	if( _scores != null ){
		for( int i=0; i<_scores.Count; i++ ){
			Rect nameRect = new Rect( 5 * _scaleOffset.x, (20 * _scaleOffset.y) + i * 35 * _scale, 109 * _scale, 35 * _scale ); 
			Rect scoreRect = new Rect( 139 * _scaleOffset.x, (20 * _scaleOffset.y) + i * 35 * _scale, 52 * _scale, 35 * _scale ); 
 
			GUI.Label( nameRect, _scores[i].name ); 
			GUI.Label( scoreRect, _scores[i].points.ToString() ); 
		}
			}						
	GUI.EndGroup(); 	
	GUI.EndGroup();
 
}

這就是GameMenuController了,最後還要將GameMenuContrller關聯到GameController類上面。將GameController腳本打開,然後實現關聯。

聲明幾個變量:

private GameMenuController _menuController;
private LeaderboardController _leaderboardController;
public Alerter alerter;

在Awake函數中初始化一下:

	void Awake() {		
		_instance = this; 
		_menuController = GetComponent<GameMenuController>();
		_leaderboardController = GetComponent<LeaderboardController>();
	}

最明顯的變化時GameController中State的處理,用以下的代碼替代UpdateStatePlay的部分,後面我們會具體說代碼。

public GameStateEnum State{
	get{
		return _state; 	
	}
	set{
		_state = value; 
 
		// MENU 
		if( _state == GameStateEnum.Menu ){
			player.State = Player.PlayerStateEnum.BouncingBall;	
			_menuController.Show(); 	
		}
 
		// PAUSED 
		else if( _state == GameStateEnum.Paused ){
			Time.timeScale = 0.0f; 
			_menuController.Show(); 
		}
 
		// PLAY 
		else if( _state == GameStateEnum.Play ){
			Time.timeScale = 1.0f; 
			_menuController.Hide(); 								
 
			// notify user
			alerter.Show( "GAME ON", 0.2f, 2.0f ); 
		}
 
		// GAME OVER 
		else if( _state == GameStateEnum.GameOver ){
			// add score 
			if( _gamePoints > 0 ){
				_leaderboardController.AddPlayersScore( _gamePoints ); 	
			}
 
			// notify user
			alerter.Show( "GAME OVER", 0.2f, 2.0f ); 	
		}								
	}
}

代碼的意思就如它寫的那樣,當State為Menu或者Pause,你僅僅要用GameMenuController的show方法來讓自己顯示就能夠了,當state設為Play的時候,用hide方法來隱藏。終於state被設為GameOver的時候。將玩家的分數加入到leaderboard中(就如demo中你寫的代碼那樣)。

最後,註意這段代碼有依賴於一個Alerter對象。

所以為了讓它跑起來。創建一個空對象。將Alert腳本加入上去。然後將Alerter拖拽到GameController的相應屬性上。


編譯執行

就像之前的一樣,File->Build Setting打開編譯對話框。點擊編譯button來測試終於的遊戲!

技術分享圖片


編譯並執行XCode項目,你將會在你的設備上看到一個美膩的菜單!

技術分享圖片


優化

優化方面的內容能夠寫成一本書了!即使你認為遊戲的表現還能接受。你有考慮過那一大堆ipod touch和iPhone 3G的感受麽?你已經花了非常大的力氣去完畢一個遊戲,你應該不願意那些持有老設備的玩家認為你的遊戲非常卡吧。

以下的一些條款在開發的時候最好牢記在心:

最小化調用繪制函數 —— 盡可能少地調用繪制函數,你能夠共享紋理和材質。避免使用透明的shader - 使用mobile shader來替代。限制場景的光源數量。使用貼圖組合來實現HUD.

註意有些場景的復雜度 —— 使用優化的模型,意味著模型具有更少的圖元。

你通常能夠將模型的細節烘培到紋理之中,而不是使用高精度的模型,烘培對於光照相同適用。記住玩家玩的遊戲是在非常小的一個屏幕上,非常多細節都會被忽略。

適用假的陰影 —— 動態陰影在iOS中並不能適用,可是能夠使用projectors來做成一個假的陰影。唯一可能引起的問題就是projector會調用繪制函數。所以假設可能的話,盡可能用一個帶陰影紋理的平面加上一個特粒子Shader來模擬。

警惕在Update/FixexUpdate方法中的不論什麽代碼 —— 理想情況下,Update和FixedUpdate函數須要每秒跑30到60次,所以在調用這兩個函數之前,預處理好不論什麽能夠做的事情。

同一時候也要註意你加在當中的邏輯,特別是和物理相關的!

關閉全部不使用的東西 —— 假設一個腳本不須要執行,就關掉它,盡管它看起來沒那麽重要 —— app中全部的一切都會消耗CPU!

盡可能使用最簡單的組件 —— 假設你僅僅須要一個組件中非常小的一部分功能。其它大部分都用不著。那麽你能夠自己實現你最須要的那部分功能而不是直接拿來用。比方CharacterController就是一個非常誘人的組件,所以最好用Rigidbody來實現你自己的解決方式。

整個開發過程都使用真機來測試 —— 當執行遊戲的時候。打開console的debug log窗體,那樣就能夠看你的app消耗了多少cpu。

你須要這樣做:在XCode中找到iPhone_Profiler.h文件。而且將ENABLE_INTERNAL_PROFILER 設為1.這樣就能夠更加具體地看到你的app的執行情況。

若果你有Unity3D Advance版本號,裏面有個profiler能夠查看腳本中每一個方法消耗的時間。profiler的信息就像以下這樣:

技術分享圖片

幀率能夠表示遊戲執行的速度,默認的速度哦要麽是30,要麽60.遊戲的平均幀率應該接近這兩個值。

draw-call表示當前渲染調用的次數 - 就像前面提到的,通過共享紋理和材質。將這個數字保持得越低越好。

(譯註:一個 Draw Call,等於呼叫一次 DrawIndexedPrimitive (DX) or glDrawElements (OGL),等於一個 Batch。盡可能地降低Drawcall的數量。IOS設備上建議不超過100。降低的方法主要有例如以下幾種:Frustum Culling,Occlusion Culling,Texture Packing。

Frustum Culling是Unity內建的,我們須要做的就是尋求一個合適的遠裁剪平面;Occlusion Culling,遮擋剔除,Unity內嵌了Umbra,一個非常好OC庫。但Occlusion Culling也並非放之四海而皆準的。有時候進行OC反而比不進行還要慢,建議在OC之前先確定自己的場景是否適合利用OC來優化;Texture Packing,或者叫Texture Atlasing,是將同種shader的紋理進行拼合。依據Unity的static batching的特性來降低draw call。建議使用,但也有弊端,那就是一定要將場景中距離相近的實體紋理進行拼合。否則,拼合後非常可能會添加每幀渲染所需的紋理大小。加大內存帶寬的負擔。這也就是為什麼會出現“DrawCall降了,渲染速度也變慢了”的原因)

verts表示當前須要渲染多少頂點。

player-detail能夠告訴我們遊戲引擎的每一個部分消耗了多少時間。


你還能夠做非常多

你能夠下載完整的項目。然後再unity中打開。

(譯註:有點坑爹。非常多bug)

到如今為止。你已經做得非常好了。但我們的旅程遠不會到此為止!

:] 保持這股勢頭。你將會成為一個unity高手,當然,這也須要很多其它的各方面的技能。

以下是一些擴展遊戲的建議:

●?加入音效。聲音是交互內容的非常重要的一個內容。所以花些時間去找些音樂和音效加到遊戲中去吧。

● 關聯Facebook。

● 添加多玩家模式,讓玩家們能夠同一個設備上競技,輪流投球。

● 添加角色讓玩家選擇。

● 支持多種手勢,不同的手勢代表不同的投籃方式;

● 加入帶獎勵的籃球。這種籃球有不一樣的物理屬性,比方不同的重量;

● 加入新的關卡。每一個關卡有新的挑戰。

這些足夠讓你忙一陣了!

希望你喜歡這個系列的教程。而且能夠學習一些unity的僅僅是。我希望看到你們將來制作出屬於自己的unity app!


資源下載

Project part3

Data Control Resources


參考

Intermediate Unity 3D for iOS: Part 3/3 -?http://www.raywenderlich.com/20420/beginning-unity-3d-for-ios-part-3


其它

原工程的代碼導入到unity3d4.3無法正常執行。個人又一次編寫了一個android和pc上都能執行的完整版本號,點我下載。

Unity3D遊戲開發從零單排(四) - 制作一個iOS遊戲