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


提要

       此篇是一個國外教程的翻譯,盡管有點老,可是適合新手入門。

自己去寫代碼。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上都能執行的完整版本號,點我下載。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM