Unity學習匯總
一、簡述
1.1. 渲染管線
渲染管線是指將虛擬3D世界場景中的各個要素轉換成2D平面圖像的過程。主要功能包括一是將物體3D坐標轉變為屏幕空間2D坐標,二是為屏幕每個像素點進行着色。
在這個過程中,CPU與GPU並行協調進行工作,要經歷以下幾個過程:
1)CPU將場景中的物體進行計算,變成場景數據,此過程又稱為數據准備階段,數據准備完畢后,發送Draw Call命令給GPU,通知GPU執行渲染任務,其中包括了物體的頂點數據,坐標數據等。
注意:Draw Call次數即為CPU准備數據發送命令的次數,CPU工作是根據物體數量進行分批准備以及通知的,當物體數量過多,Draw Call過多,CPU就會很多額外開銷用於准備工作,影響性能。優化方案:(1)合批,就是把能合並的都合並起來,盡量減少Draw Call。(肯定有不能合並的,比如場景中的一個大樹和主角,還有好多渲染狀態啊透明啊之類的,篇幅有限不展開講了,真感興趣應該可以自己搜得到)。(2)instance,GPU硬件算法。使用與大量需要重復繪制的模型,比如草地。但是instance是有上限的,並且只能減少Draw Call,對於增加的面數來說是無解的。
2)GPU接收數據后進行頂點處理,包括坐標的轉換、圖元的組裝(三角形)。
3)進行光柵化,也就是計算圖元的像素以及為像素着色。。
4)混合測試后進行緩存。
、
1.2. 遮擋剔除(occlusion Culling)
當物體被送進渲染流水線之前,將攝像機視角內看不到的物體進行剔除,從而減少每幀渲染量,提高渲染性能。
實際中,遮擋剔除的實現方法多種多樣,關於instanceOC插件的方法是發射射線進行檢測。
1.3. 多細節層次(Levels of Detail)
LOD技術指根據物體模型的節點在顯示環境中所處的位置和重要度,決定了物體渲染的資源分配,降低非重要物體的面數和細節度,從而獲得高效率的渲染運算。
量化渲染運算速度的指標可以參考三角數以及頂點數。
1.4. 性能指標參考
路徑:Windows-Analysis-profiler
1.5. GI
Global Illuminnation,簡稱GI,即全局光照。能夠計算直接光,間接光,環境光以及反射光的光照系統。
直接光照,通過組件Light發出的光照就是直接光照。
—Directional Light :方向光,與光源位置無關,只與方向有關的光照
—Point Light:點光源,類似燈泡
—spot: 方向射燈。
—Area Light :區域光,注意:及其消耗性能,只能烘焙使用
1.6. RealTime GI
是指場景在運行期間,可以實時修改任意光源,變化會立即更新。
GI Cache 實時光照的緩存
1.7. 烘焙Lightmap
當場景中包含大量物體時,實時光照和陰影對游戲的性能有極大的影響,使用烘焙技術將光線效果預渲染成貼圖再作用到物體上模擬光照效果,從而提高性能。適用於性能較低的設備。
.NET dotnet 是Microsoft的新一代多語言的開發平台,用於應用程序的開發以及運行。
C#是專門為.NET推出的高級編程語言,從語言技術風格,嚴謹性上來說,C#是諸多語言中最為優秀的一款,甚至由它引發的計算機語言界的多種新規范和新特征。
Mono支持在其他操作系統下開發.NET程序的框架。Unity借助Mono實現了跨平台,核心是.NET Framework。
二、Unity腳本
1、生命周期
注意:
1)Update與FixedUpdate之間的區別,update與FPS(即每秒渲染幀數相關):
Update是每次渲染新的的一幀的時候會進行調用,因此,調用頻率受不同機器顯卡的性能影響,同時每幀調用的時間間隔也不定,在實際中這個因素會導致FPS高的update固定時間內運行次數多,FPS低的運行次數少,因此在做移動、旋轉效果的時候可以添加Time.deltatime來保證不同機器不同FPS下的游戲效果一致。
FixedUpdate是物理固定頻率執行,FixedUpdate的時間間隔可以在項目設置中更改,點擊 Edit - Project Setting - time - Fixed timestep,默認為0.02s
2)輸入事件是用於獲取玩家的輸入的,OnMouseXXX系列。
3)yieldWWW,關於協程的后續進入,注意是在update之后進入的。
Unity官方API:https://docs.unity3d.com/Manual/ExecutionOrder.html。
2、序列化
轉自:https://www.cnblogs.com/fzuljz/p/11168131.html
unity的序列化在unity的開發中起着舉重足輕的地位,許多核心的功能都是基於序列化和反序列化來實現的。序列化簡單來講就是就是將我們所要保存的數據進行二進制存儲,然后當我們需要的時候,在讀取二進制文件,反序列化回來。下面是一些常用的序列化的例子:
- 存儲腳本化的數據。在我們的c#代碼中,可以將我們所要存儲的數據進行序列化,進行存儲
- prefab與初始化。在unity開發過程中我們會制作很多的預制體(prefab),這些prefab都是序列化,以二進制的形式保存的。當你要對預制體進行初始化的時候,unity根據之前序列化的信息新建出一個物體,然后將物體上的信息反序列化回去,實現類似於clone的效果。
- 在unity編輯器的拓展功能,AssetBundle等等,都可以看到序列化的身影。
可序列化對象:
- 公有的,或者有[SerializeField]屬性,非靜態,非常量,非只讀
- 自定義非抽象類,並且有Serializable屬性
- 繼承自unity.object的類
- 數組和List
注意:
- 字典不能通過添加Serializable屬性進行序列化
- 如果一個類基類不能被序列化,那它即便添加了序列化特性也無法被序列化
- 序列化不能保存另一個要反序列化的對象指針,因為反序列化是new一個新的對象,指針指向的內存將不會是原對象
可采用unity編輯器的序列化類ScriptableObject,當我們繼承這個基類,我們就可以調用unity給我們的接口進行序列化了。具體的序列化接口可以到unity的官方接口文檔上查看使用方法,這里不具體介紹。
3、常用的Attribute
舉兩個例子,在變量上使用[SerializeFiled]屬性,可以強制讓變量進行序列化,可以在Unity的Editor上進行賦值。
在Class上使用[RequireComponent]屬性,就會在Class的GameObject上自動追加所需的Component。
以下是Unity官網文檔中找到的所有Attribute,下面將按照順序,逐個對這些Attribute進行說明和小的測試。
部分例子使用了Unity官方的示例。
UnityEngine
AddComponentMenu
可以在UnityEditor的Component的Menu中增加自定義的項目。菜單可以設置多級,使用斜線/分隔即可。在Hierarchy中選中GameObject的時候,點擊該菜單項,就可以在GameObject上追加該Component。
例如如下代碼可以完成下圖的效果。
[AddComponentMenu("TestMenu/TestComponet")] public class TestMenu : MonoBehaviour { }
匯編級屬性,使用該屬性的Class會被認為是EditorClass。具體用法不明。
可以在Inspector的ContextMenu中增加選項。
例如,如下代碼的效果
public class TestMenu : MonoBehaviour { [ContextMenu ("Do Something")] void DoSomething () { Debug.Log ("Perform operation"); } }
這個屬性是Unity4.5之后提供的新功能,可以在Inspector上面對變量追加一個右鍵菜單,並執行指定的函數。
例子:
public class Sample : MonoBehaviour { [ContextMenuItem("Reset", "ResetName")] public string name = "Default"; void ResetName() { name = "Default"; } }
對一個MonoBehaviour的子類使用這個屬性,那么在同一個GameObject上面,最多只能添加一個該Class的實例。
嘗試添加多個的時候,會出現下面的提示。
默認狀態下,MonoBehavior中的Start,Update,OnGUI等方法,需要在Play的狀態下才會被執行。
這個屬性讓Class在Editor模式(非Play模式)下也能執行。
但是與Play模式也有一些區別。
例如:
Update方法只在Scene編輯器中有物體產生變化時,才會被調用。
OnGUI方法只在GameView接收到事件時,才會被調用。
這個屬性可以在Inspector中變量的上面增加Header。
例子:
public class ExampleClass : MonoBehaviour { [Header("生命值")] public int CurrentHP = 0; public int MaxHP = 100; [Header("魔法值")] public int CurrentMP = 0; public int MaxMP = 0; }
在變量上使用這個屬性,可以讓public的變量在Inspector上隱藏,也就是無法在Editor中進行編輯。
在OnRenderImage上使用,可以讓渲染順序在非透明物體之后,透明物體之前。
例子
[ImageEffectOpaque] void OnRenderImage (RenderTexture source, RenderTexture destination){ }
渲染從從HDR變為LDR 具體使用方法不明。
在string類型上使用,可以在Editor上輸入多行文字。
public class TestString : MonoBehaviour { [MultilineAttribute] public string mText; }
在變量上使用,可以指定該變量在build的時候,不要轉換為目標平台的類型。
在變量上使用,在Flash平台build的時候,對該變量不進行類型檢查。
Unity5.0中已經移除了這個屬性。
禁止對變量和方法進行重命名。
Unity5.0中已經移除了這個屬性。
在int或者float類型上使用,限制輸入值的范圍
public class TestRange : MonoBehaviour { [Range(0, 100)] public int HP; }
在Class上使用,添加對另一個Component的依賴。
當該Class被添加到一個GameObject上的時候,如果這個GameObject不含有依賴的Component,會自動添加該Component。
且該Componet不可被移除。
例子
[RequireComponent(typeof(Rigidbody))] public class TestRequireComponet : MonoBehaviour { }
如果嘗試移除被依賴的Component,會有如下提示
在方法上添加該屬性,可以網絡通信中對該方法進行RPC調用。
[RPC] void RemoteMethod(){ }
RuntimeInitializeOnLoadMethodAttribute
此屬性僅在Unity5上可用。
在游戲啟動時,會自動調用添加了該屬性的方法。
class MyClass { [RuntimeInitializeOnLoadMethod] static void OnRuntimeMethodLoad () { Debug.Log("Game loaded and is running"); } }
當一個GameObject含有使用了該屬性的Component的時候,在SceneView中選擇該GameObject,Hierarchy上面會自動選中該GameObject的Parent。
SerializeField
在變量上使用該屬性,可以強制該變量進行序列化。即可以在Editor上對變量的值進行編輯,即使變量是private的也可以。
在UI開發中經常可見到對private的組件進行強制序列化的用法。
例子
public class TestSerializeField : MonoBehaviour { [SerializeField] private string name; [SerializeField] private Button _button; }
SharedBetweenAnimatorsAttribute
用於StateMachineBehaviour上,不同的Animator將共享這一個StateMachineBehaviour的實例,可以減少內存占用。
SpaceAttribute
使用該屬性可以在Inspector上增加一些空位。 例子:
public class TestSpaceAttributeByLvmingbei : MonoBehaviour { public int nospace1 = 0; public int nospace2 = 0; [Space(10)] public int space = 0; public int nospace3 = 0; }
TextAreaAttribute
該屬性可以把string在Inspector上的編輯區變成一個TextArea。
例子:
public class TestTextAreaAttributeByLvmingbei : MonoBehaviour { [TextArea] public string mText; }
這個屬性可以為變量上生成一條tip,當鼠標指針移動到Inspector上時候顯示。
public class TestTooltipAttributeByLvmingbei : MonoBehaviour { [Tooltip("This year is 2015!")] public int year = 0; }
UnityAPICompatibilityVersionAttribute
用來聲明API的版本兼容性
UnityEngine.Serialization
FormerlySerializedAsAttribute
該屬性可以令變量以另外的名稱進行序列化,並且在變量自身修改名稱的時候,不會丟失之前的序列化的值。
例子:
using UnityEngine; using UnityEngine.Serialization; public class MyClass : MonoBehaviour { [FormerlySerializedAs("myValue")] private string m_MyValue; public string myValue { get { return m_MyValue; } set { m_MyValue = value; } } }
UnityEngine.Editor
該package為Editor開發專用
CallbackOrderAttribute
定義Callback的順序
CanEditMultipleObjects
Editor同時編輯多個Component的功能
CustomEditor
聲明一個Class為自定義Editor的Class
CustomPreviewAttribute
將一個class標記為指定類型的自定義預覽
Unity4.5以后提供的新功能
例子:
[CustomPreview(typeof(GameObject))] public class MyPreview : ObjectPreview { public override bool HasPreviewGUI() { return true; } public override void OnPreviewGUI(Rect r, GUIStyle background) { GUI.Label(r, target.name + " is being previewed"); } }
CustomPropertyDrawer
標記自定義PropertyDrawer時候使用。
當自己創建一個PropertyDrawer或者DecoratorDrawer的時候,使用該屬性來標記。 TODO: 如何創建屬於自己的Attribute
DrawGizmo
可以在Scene視圖中顯示自定義的Gizmo
下面的例子,是在Scene視圖中,當掛有MyScript的GameObject被選中,且距離相機距離超過10的時候,便顯示自定義的Gizmo。
Gizmo的圖片需要放入Assets/Gizmo目錄中。
例子:
using UnityEngine; using UnityEditor; public class MyScript : MonoBehaviour { } public class MyScriptGizmoDrawer { [DrawGizmo (GizmoType.Selected | GizmoType.Active)] static void DrawGizmoForMyScript (MyScript scr, GizmoType gizmoType) { Vector3 position = scr.transform.position; if(Vector3.Distance(position, Camera.current.transform.position) > 10f) Gizmos.DrawIcon (position, "300px-Gizmo.png"); } }
在Class上使用,可以在Unity啟動的時候,運行Editor腳本。
需要該Class擁有靜態的構造函數。
做一個創建一個空的gameobject的例子。
例子:
using UnityEditor; using UnityEngine; [InitializeOnLoad] class MyClass { static MyClass () { EditorApplication.update += Update; Debug.Log("Up and running"); } static void Update () { Debug.Log("Updating"); } }
InitializeOnLoadMethodAttribute
在Method上使用,是InitializeOnLoad的Method版本。
Method必須是static的。
MenuItem
在方法上使用,可以在Editor中創建一個菜單項,點擊后執行該方法,可以利用該屬性做很多擴展功能。 需要方法為static。
例子:
using UnityEngine; using UnityEditor; using System.Collections; public class TestMenuItem : MonoBehaviour { [MenuItem ("MyMenu/Create GameObject")] public static void CreateGameObject() { new GameObject("lvmingbei's GameObject"); } }
PreferenceItem
使用該屬性可以定制Unity的Preference界面。
在這里就使用官方的例子:
using UnityEngine; using UnityEditor; using System.Collections; public class OurPreferences { // Have we loaded the prefs yet private static bool prefsLoaded = false; // The Preferences public static bool boolPreference = false; // Add preferences section named "My Preferences" to the Preferences Window [PreferenceItem ("My Preferences")] public static void PreferencesGUI () { // Load the preferences if (!prefsLoaded) { boolPreference = EditorPrefs.GetBool ("BoolPreferenceKey", false); prefsLoaded = true; } // Preferences GUI boolPreference = EditorGUILayout.Toggle ("Bool Preference", boolPreference); // Save the preferences if (GUI.changed) EditorPrefs.SetBool ("BoolPreferenceKey", boolPreference); } }
UnityEditor.Callbacks
這個package中是三個Callback的屬性,都需要方法為static的。
OnOpenAssetAttribute
在打開一個Asset后被調用。
例子:
using UnityEngine; using UnityEditor; using UnityEditor.Callbacks; public class MyAssetHandler { [OnOpenAssetAttribute(1)] public static bool step1(int instanceID, int line) { string name = EditorUtility.InstanceIDToObject(instanceID).name; Debug.Log("Open Asset step: 1 ("+name+")"); return false; // we did not handle the open } // step2 has an attribute with index 2, so will be called after step1 [OnOpenAssetAttribute(2)] public static bool step2(int instanceID, int line) { Debug.Log("Open Asset step: 2 ("+instanceID+")"); return false; // we did not handle the open } }
PostProcessBuildAttribute
該屬性是在build完成后,被調用的callback。
同時具有多個的時候,可以指定先后順序。
例子:
using UnityEngine; using UnityEditor; using UnityEditor.Callbacks; public class MyBuildPostprocessor { [PostProcessBuildAttribute(1)] public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) { Debug.Log( pathToBuiltProject ); } }
PostProcessSceneAttribute
使用該屬性的函數,在scene被build之前,會被調用。
具體使用方法和PostProcessBuildAttribute類似。
4、常用的輸入類KPI
1)獲取鼠標輸入(也適用與觸摸屏)
01、當鼠標按鈕被按下時返回true.
1 bool result = Input.GetMouseButton(0);
02、當按下指定鼠標按鈕的第一幀返回true.
1 bool result = Input.GetMouseButtonDown(0);
03、當釋放鼠標按鍵的第一幀返回true.
1 bool result = Input.GetMouseButtonUp(0);
2)獲取鍵盤輸入(PC)
01、當通過名稱指定的按鍵被用戶按住時返回true
1 bool result = Input.GetKey(KeyCode.XXX);
02、當通過名稱指定的按鍵被用戶按住下時返回true
1 bool result = Input.GetKeyDown(KeyCode.XXX);
03、當釋放按鍵時返回true
1 bool result = Input.GetKeyDown(KeyCode.XXX);
3)虛擬軸
路徑:Edit-Project Settings-Input
可以自定義虛擬軸
獲取虛擬軸的輸入可以用
1 float Axis01 = Input.GetAxis("Name"); 2 float Axis02 = Input.GetAxisRaw("Name"); 3 bool button01 = Input.GetButton("Name"); 4 bool button02 = Input.GetButtonDown("Name"); 5 bool button03 = Input.GetButtonUp("Name");
4、常用的獲取對象用的API(待補充)
這里就記錄一個工具類獲取一個對象中的子對象的工具
1 /// <Summary> 2 ///根據名字查詢自身以及自身的子孫物體的引用 3 ///</Summary> 4 public static class FindGrandSonByName 5 { 6 private static Transform FindSon02(Transform parenTF, string name) 7 { 8 Transform childTF = parenTF.Find(name); 9 if (childTF != null) return childTF; 10 11 int count = parenTF.childCount; 12 for (int i = 0; i < count; i++) 13 { 14 childTF = FindSon02(parenTF.GetChild(i), name); 15 if (childTF != null) return childTF; 16 } 17 return null; 18 } 19 20 }
5、3Dmath與Vector結構體
1 private void Demo01() 2 { 3 Vector3 A = this.transform.position; 4 Debug.DrawLine(Vector3.zero, this.transform.position,Color.red); 5 } 6 7 /// <summary> 8 /// 向量相加 9 /// </summary> 10 private void Demo02() 11 { 12 Vector3 Abc = T1.position - T2.position; 13 if (Input.GetKeyDown(KeyCode.A)) 14 //this.T3.Translate(Abc.normalized); 15 T3.transform.position = T3.transform.position + Abc.normalized; 16 Debug.DrawLine(T1.position, T2.position); 17 } 18 19 /// <summary> 20 /// 計算物體右前方30度,10m遠的坐標 21 /// </summary> 22 private void Demo03() 23 { 24 // Vector3 A = new Vector3(10 * Mathf.Sin(Mathf.Deg2Rad * 30), 0, 10 * Mathf.Cos(Mathf.Deg2Rad * 30)); 25 //Vector3 B = this.transform.position + A; 26 Vector3 B = this.transform.TransformPoint(10 * Mathf.Sin(Mathf.Deg2Rad * 30), 0, 10 * Mathf.Cos(Mathf.Deg2Rad * 30)); 27 28 Debug.DrawLine(this.transform.position, B); 29 30 } 31 /// <summary> 32 /// 方案二_計算物體右前方30度,10m遠的坐標 33 /// </summary> 34 private void Demo03Copy() 35 { 36 // Vector3 destination = this.transform.position + Quaternion.Euler(0, 30, 0) * this.transform.forward.normalized * 10;//transform.forward是自身坐標系,則目標點會隨自身旋轉而旋轉 37 Vector3 destination = this.transform.position + Quaternion.Euler(0, 30, 0) * this.transform.rotation * new Vector3(0, 0, 1) * 10;//new Vector3(0,0,1)是世界坐標系。則不會旋轉,如果改為自身坐標系,則會旋轉 38 Debug.DrawLine(this.transform.position, destination); 39 } 40 41 /// <summary> 42 /// 向量弧長與角度的轉換,點乘角度(0-180/0-PI) 43 /// </summary> 44 public float degree; 45 public float radiu; 46 private void Demo04() 47 { 48 radiu = Mathf.Acos(Vector3.Dot(T3.position.normalized,T2.position.normalized)); 49 degree = radiu * Mathf.Rad2Deg; 50 // print($"{degree}"); 51 } 52 /// <summary> 53 /// 叉乘角度(0-90/0-PI/2) 54 /// </summary> 55 private void Demo05() 56 { 57 radiu = Mathf.Asin(Vector3.Cross(T3.position.normalized, T2.position.normalized).magnitude); 58 degree = radiu * Mathf.Rad2Deg; 59 Debug.DrawLine(Vector3.zero, T2.position); 60 Debug.DrawLine(Vector3.zero, T3.position); 61 // print($"{degree}"); 62 } 63 64 65 /// <summary> 66 /// 判斷炸彈的攻擊范圍 67 /// </summary> 68 public Transform Player; 69 public float area = 10; 70 private void Demo06() 71 { 72 //Quaternion. 73 float degree01 = Mathf.Acos(Player.GetComponent<CapsuleCollider>().radius / (Player.transform.position - this.transform.position).magnitude) * Mathf.Rad2Deg; 74 75 76 Vector3 JudgePoint01 = Player.transform.position + Quaternion.Euler(0, degree01, 0) * ((Player.transform.position - this.transform.position).normalized * Player.GetComponent<CapsuleCollider>().radius); 77 Vector3 JudgePoint02 = Player.transform.position + Quaternion.Euler(0, -degree01, 0) * ((Player.transform.position - this.transform.position).normalized * Player.GetComponent<CapsuleCollider>().radius); 78 79 Debug.DrawLine(JudgePoint01, this.transform.position); 80 Debug.DrawLine(JudgePoint02, this.transform.position); 81 82 if (Input.GetKeyDown(KeyCode.A)) 83 { 84 // this.transform.position += new Vector3(0,0,1); 85 if (Vector3.SqrMagnitude(JudgePoint01 - this.transform.position) <= Mathf.Pow(area, 2)) print("擊中"); 86 else print("未擊中"); 87 } 88 89 } 90 91 /// <summary> 92 /// 判斷forward,up,right的自身坐標以及世界坐標的情況 93 /// </summary> 94 private void Demo07() 95 { 96 Vector3 A = new Vector3(0, 0, 5); 97 Debug.DrawLine(Vector3.zero, A); 98 99 this.transform.position += A; 100 } 101 /// <summary> 102 /// 直接移動,勻速移動,變速移動 103 /// </summary> 104 public Transform target; 105 private void Demo08() 106 { 107 108 //直接移動 109 //this.transform.position = target.position; 110 //勻速移動 111 //this.transform.position = Vector3.MoveTowards(this.transform.position, target.position, 10 * Time.deltaTime); 112 //變速移動 113 this.transform.position = Vector3.Lerp(this.transform.position, target.position, 0.01f);//使用Lerp要注意設定閾值 114 AnimationCurve curve; //這個動態數值可以用於設置移動比例 115 } 116 117 private void Demo09() 118 { 119 //直接旋轉(注視旋轉) 120 //this.transform.LookAt(target); 121 //this.transform.rotation = Quaternion.LookRotation(target.position - this.transform.position); 122 //勻速旋轉 123 Quaternion targetQua = Quaternion.LookRotation(target.position - this.transform.position); 124 this.transform.rotation = Quaternion.RotateTowards(this.transform.rotation, targetQua, 0.1f); 125 } 126 127 /// <summary> 128 /// 圍繞旋轉 129 /// </summary> 130 /// 轉速 131 private Vector3 airx; 132 private void Demo10() 133 { 134 this.transform.RotateAround(target.position, airx ,30 * Time.deltaTime); 135 Debug.DrawLine(target.position, target.position + new Vector3(0, 10, 0)); 136 Debug.DrawLine(this.transform.position, target.position, Color.red); 137 138 } 139 140 /// <summary> 141 /// 繞橢圓運動。 142 /// </summary> 143 private void Demo11() 144 { 145 int a = 10; 146 int b = 5; 147 float degree = 30 * Mathf.Deg2Rad * Time.time; 148 Vector3 change = new Vector3(a * Mathf.Cos(degree), 0, b * Mathf.Sin(degree)); 149 this.transform.position = target.position + change; 150 }
旋轉(歐拉角與四元數)
注意在歐拉角的旋轉中,Unity為了保證任意方位都只有獨一無二的表示,Unity引擎限制了角度范圍,即沿X軸旋轉限制在-90~90之間,沿Y軸與Z軸限制在0~360之間,從而確保一個(X,Y,Z)的值代表獨一無二的方位。
同時,歐拉角的旋轉會出現萬向節死鎖的情況,即由於歐拉角旋轉時Y軸上的旋轉保持是世界坐標系的Y軸,而不是自身坐標系,因此,在物體沿X軸旋轉到90或者-90的時候,自身的Z軸與世界的Y軸重合,這個時候,Y,Z軸向上的旋轉保持一致或者相反。
而四元數的旋轉就不會存在這個問題。
理解四元數:極力推薦:https://www.3dgep.com/understanding-quaternions/
中文翻譯版:https://www.qiujiawei.com/understanding-quaternions/
常用的API如下:
1 private void Demo01() 2 { 3 //1.歐拉角--》四元數 4 this.transform.rotation *= Quaternion.Euler(0, 10, 0); 5 } 6 7 private void Demo02() 8 { 9 //2.四元數--》歐拉角 10 Quaternion qt = this.transform.rotation; 11 Vector3 euler = qt.eulerAngles; 12 } 13 14 private void Demo03() 15 { 16 //3.軸/角 17 this.transform.rotation *= Quaternion.AngleAxis(50, this.transform.up); 18 19 } 20 21 22 public Transform target01; 23 private void Demo04() 24 { 25 //4.Z軸注視旋轉 26 this.transform.rotation = Quaternion.LookRotation(target01.position - this.transform.position); 27 this.transform.LookAt(target01); 28 //5.勻速旋轉 29 //this.transform.rotation = Quaternion.RotateTowards(); 30 31 //6.變速旋轉 32 //this.transform.rotation = Quaternion.Lerp(); 33 } 34 35 private void Demo05() 36 { 37 Quaternion dir = Quaternion.LookRotation(target01.position - this.transform.position); 38 this.transform.rotation = Quaternion.Lerp(this.transform.rotation, dir,0.5f * Time.deltaTime); 39 //6.由於Lerp值無法最終抵達,因此需要設定閾值 40 if (Quaternion.Angle(this.transform.rotation, dir) < 1) this.transform.rotation = dir; 41 } 42 43 private void Demo06() 44 { 45 //7.X軸注視旋轉。 46 //this.transform.right = target01.position - this.transform.position; 47 Quaternion dir = Quaternion.FromToRotation(Vector3.right, target01.position - this.transform.position); 48 this.transform.rotation = dir; 49 }
計時器Demo
1 private int gameTimeSecound03; 2 private int gameTimeMinute; 3 private int gameRemainedSecound; 4 private Text textTimer; 5 6 private void Start() 7 { 8 textTimer = this.GetComponent<Text>(); 9 gameTimeSecound03 = 120; 10 //重復調用(要執行的方法名稱,開始調用時間,調用間隔) 11 InvokeRepeating("TimeCalcutor03", 0, 1); 12 //延遲調用 13 //Invoke("需要調用的方法名稱", 調用時間); 14 } 15 16 private void TimeCalcutor03() 17 { 18 if (gameTimeSecound03 <= 0) enabled = false; 19 if (textTimer.color != Color.red && gameTimeSecound03 <= 10) textTimer.color = Color.red; 20 gameTimeMinute = (int)(gameTimeSecound03 / 60); //取商取整 21 gameRemainedSecound = (int)(gameTimeSecound03 % 60);//取余取整 22 textTimer.text = $"{gameTimeMinute:D2}:{gameRemainedSecound:D2}"; 23 gameTimeSecound03--; 24 }
6、UI(UGUI&NGUI)
1)UGUI相機渲染模式詳解以及分辨率自適應的問題
轉自:https://blog.csdn.net/qq_15020543/article/details/82594332
一、Canvas簡介
Canvas畫布是承載所有UI元素的區域。Canvas實際上是一個游戲對象上綁定了Canvas組件。所有的UI元素都必須是Canvas的自對象。如果場景中沒有畫布,那么我們創建任何一個UI元素,都會自動創建畫布,並且將新元素置於其下。
二、Canvas畫布參數與應用
1.創建畫布
當你創建任何一個UI元素的時候,都會自動創建畫布。也可以主動創建一張畫布:點擊GameObject->UI->Canvas即可在Hierarchy面板創建一張畫布。
2.畫布參數
下面介紹一下Canvas畫布的參數:
第一個參數RenderMode的渲染模式有三種:Screen Space-Overlay、Screen Space-Camera以及World Space。
1.Screen Space-Overlay模式
Screen Space-Overlay(屏幕控件-覆蓋模式)的畫布會填滿整個屏幕空間,並將畫布下面的所有的UI元素置於屏幕的最上層,或者說畫布的畫面永遠“覆蓋”其他普通的3D畫面,如果屏幕尺寸被改變,畫布將自動改變尺寸來匹配屏幕,如下圖效果
(在此模式下,雖然在Canvas前放置了3D人物,但是在Game窗口中並不能觀察到3D人物)
Screen Space-Overlay模式的畫布有Pixel Perfect和Sort Layer兩個參數:
(1)Pixel Perfect:只有RenderMode為Screen類型時才有的選項。使UI元素像素對應,效果就是邊緣清晰不模糊。
(2)Sort Layer: Sort Layer是UGUI專用的設置,用來指示畫布的深度。
************************************************************************************************************************************************
總結:此模式只適合單純的UI開發,比如游戲的排行榜,游戲結束之后的界面,並且會自動適應屏幕大小,但是要注意,所謂的適應屏幕,不是說你把圖片設置到攝像機所顯示游戲的界面一樣大,他就會自動適應。
我們在Canvas下面新建一個Image
這樣才能達到自適應的目的。
*************************************************************************************************************************************************
2.Screen Space-Camera模式
Screen Space-Camera(屏幕空間-攝影機模式)和Screen Space-Overlay模式類似,畫布也是填滿整個屏幕空間,如果屏幕尺寸改變,畫布也會自動改變尺寸來匹配屏幕。所不同的是,在該模式下,畫布會被放置到攝影機前方。在這種渲染模式下,畫布看起來 繪制在一個與攝影機固定距離的平面上。所有的UI元素都由該攝影機渲染,因此攝影機的設置會影響到UI畫面。在此模式下,UI元素是由perspective也就是視角設定的,視角廣度由Filed of View設置。
這種模式可以用來實現在UI上顯示3D模型的需求,比如很多MMO游戲中的查看人物裝備的界面,可能屏幕的左側有一個運動的3D人物,左側是一些UI元素。通過設置Screen Space-Camera模式就可以實現上述的需求,效果如下圖所示:
它比Screen Space-Overlay模式的畫布多了下面幾個參數:
(1)Render Camera:渲染攝像機
(2)Plane Distance:畫布距離攝像機的距離
(3)Sorting Layer: Sorting Layer是UGUI專用的設置,用來指示畫布的深度。可以通過點擊該欄的選項,在下拉菜單中點擊“Add Sorting Layer”按鈕進入標簽和層的設置界面,或者點擊導航菜單->edit->Project Settings->Tags and Layers進入該頁面。
可以點擊“+”添加Layer,或者點擊“-”刪除Layer。畫布所使用的Sorting Layer越排在下面,顯示的優先級也就越高。
(4)Order in Layer:在相同的Sort Layer下的畫布顯示先后順序。數字越高,顯示的優先級也就越高。
****************************************************************************************************************************************************
總結:對於Order in Layer,可以理解為棧,先進去的后顯示,后進去的先顯示。也就是說,數值越大,就越靠前,這個模式需要單獨的渲染攝像機,這也是大多數游戲所使用的渲染模式,如果游戲元素不多,可以把Main Camera設置為渲染相機,否則就單獨創建一個相機用於渲染。
默認狀態下創建的UGUI的原點和世界坐標的原點是重合的,這樣其實非常不方便。
解決方法就是創建一個Camera專門用於繪制UI。具體步驟如下:
1.新建一個Camera,參數如下
盡量拉到一個比較遠的位置
Canvas需要設置一下Canvas Component
這下UI就不會和場景中的物體有重合了。
*************************************************************************************************************************************************
3.World Space
World Space即世界控件模式。在此模式下,畫布被視為與場景中其他普通游戲對象性質相同的類似於一張面片(Plane)的游戲物體。畫布的尺寸可以通過RectTransform設置,所有的UI元素可能位於普通3D物體的前面或者后面顯示。當UI為場景的一部分時, 可以使用這個模式。
它有一個單獨的參數Event Camera,用來指定接受事件的攝像機,可以通過畫布上的GraphicRaycaster組件發射射線產生事件。
這種模式可以用來實現跟隨人物移動的血條或者名稱,如下圖所示:
我們通過下面的表格可以對比一下三種渲染模式的區別:
渲染模式 | 畫布對應屏幕 | 攝像機 | 像素對應 | 適合類型 |
Screen Space-Overlay | 是 | 不需要 | 可選 | 2D UI |
Screen Space-Camera | 是 | 需要 | 可選 | 2D UI |
World Space | 否 | 需要 | 不可選 | 3D UI |
在UI開發的時候要注意以下幾個參數的設置:
一、Constant Pixel Size:
像素大小始終不變,即一個100*100的圖片在任何的分辨率下都占用100*100的像素。簡單比較好理解。Scale Factor是表示縮放倍數。比如是2時,即將上面圖片整體是縮放兩倍是不變形的。
二、Scale With Screen Size
這種模式應用場景多一點。首先逐個說明下:
1)Reference Resolution是開發時的分辨率。以后縮放就參考它。
2)Screen Match Mode 又包含三種模式
* Match Width Or Height。下面包含一個Macht屬性,當處於最左邊時,屏幕高度對於UI大小完全沒有任何影 響,只有寬度會對UI大小產生影響。假設寬度為Reference Resolution寬度的x倍,則UI整體縮放為Reference Resolution設置參數的x倍。也就是說只有寬度等於Reference Resolution寬度時,才能做到pixel perfect,否則像素就會有拉伸 ,當處於最右邊時,與上述情況正好相反,決定整體縮放值的是高度,而寬度則沒有任何影響 ,處於中間某處時,對上述兩者的影響進行權重加成 。所以一般我們都把其放在0.5的位置(0.618也很舒服哦)。
* Expand 縮放不剪切:當屏幕分辨率與設定不同時,選擇變化較小的一個方向(橫向還是縱向),進行縮放顯示
,它會保證設計時分辨率能顯示出來的縮放后依然能顯示出來。
* Shrink 縮放剪切:當屏幕分辨率與設定不同時,選擇變化較大的一個方向(橫向還是縱向)進行縮放顯示
,對於超出的部分剪切不顯示。
三、Constant Physical Size
保持物理上不變的方式,這個應用場景較少,具體是這樣的,比如你電腦分辨率是 1000*2000而你的手機分辨率也是1000*2000。雖然電腦屏幕比手機屏幕大的多,但是他們最后顯示出來圖片的物理大小是一樣的。
*****************************************************************************************************************************************************
首先我們設置好Canvas參數,假設我們開發基准為480x800的分辨率。
然后在Canvas下面創建4個Button,並設置錨點分別對應四個角落,對UGUI的RectTransFrom不熟悉的同學可以去看下這位博主的文章。http://www.cocoachina.com/game/20160602/16570.html
這是480x800的顯示效果
這是1920x1080的顯示效果,大功告成!
2)UGUI事件的綁定
01、通過編輯器綁定方法
02、AddListener方法
通過代碼為含有事件方法的組件注冊事件。
03、通過接口實現,常用接口如下:
鼠標指針類
• IPointerEnterHandler • IPointerExitHandler • IPointerDownHandler • IPointerUpHandler • PointerClickHandler
拖拽類
• IBeginDragHandler • IDragHandler • IEndDragHandler • IDropHandler
點選類
• IUpdateSelectedHandler • ISelectHandler • IDeselectHandler
輸入類
• IScrollHandler • IMoveHandler • ISubmitHandler • ICancelHandler
(待繼續補充)
七、Unity3D中的協程
簡述:協程也是一種程序組件,相比一般方法,協程更為靈活,方法只有一個入口,而協程有多個入口以及出口點,可以使用協程實現合作式多任務,開啟協程的時候從方法調用StartCoroutine(開始協程)的位置進入,然后從協程綁定的方法中的Yield return處返回。注意:協程是單線程,並非多線程,即為同步執行的。
協程的使用:
協程的停止:
注意點:
01、在程序中調用StopCoroutine()方法只能終止以字符串形式啟動(開始)的協程。
02、多個協程可以同時運行
03、IEnumerator類型的方法不能帶ref或者out類型的參數
04、多腳本訪問一個協程的時候,建議將協程定義為static靜態。
DEMO01:
1 /// <Summary> 2 /// 改變顏色一段時候后變回原來的顏色 3 ///</Summary> 4 public class CoroutineDemo : MonoBehaviour 5 { 6 7 private MeshRenderer myRenderer; 8 9 private IEnumerator currentCoroutine; 10 11 Color currentColor; 12 private void Start() 13 { 14 myRenderer = this.GetComponent<MeshRenderer>(); 15 16 } 17 private void Update() 18 { 19 if(Input.GetKeyDown(KeyCode.Space)) 20 this.Attack(); 21 } 22 23 24 private void Attack() 25 { 26 //print("1"); 27 ColorControl(); 28 29 } 30 31 private void ColorControl() 32 { 33 if (currentCoroutine != null) 34 { 35 StopCoroutine(currentCoroutine); 36 } 37 38 currentCoroutine = ChangeColor(Color.red); 39 StartCoroutine(currentCoroutine); 40 } 41 42 IEnumerator ChangeColor(Color targetColor) 43 { 44 if(myRenderer.material.color != targetColor) 45 { 46 currentColor = myRenderer.material.color; 47 myRenderer.material.color = targetColor; 48 yield return new WaitForSeconds(2f); 49 myRenderer.material.color = currentColor; 50 } 51 else 52 { 53 54 yield return new WaitForSeconds(2f); 55 myRenderer.material.color = currentColor; 56 } 57 } 58 }
DEMO02:
1 /// <Summary> 2 /// 自動尋路 3 ///</Summary> 4 public class CoroutineDemo02 : MonoBehaviour 5 { 6 public Transform[] wayPoints; 7 private float speed; 8 9 private void Start() 10 { 11 speed = 2; 12 StartCoroutine(move()); 13 } 14 15 private IEnumerator move() 16 { 17 foreach (var item in wayPoints) 18 { 19 yield return StartCoroutine(PathRoutine(item)); 20 yield return new WaitForSeconds(2f); 21 } 22 } 23 24 private IEnumerator PathRoutine(Transform item) 25 { 26 while((this.transform.position - item.position).sqrMagnitude >0.09f) 27 { 28 transform.position = Vector3.MoveTowards(this.transform.position, item.position, speed * Time.deltaTime); 29 yield return null; 30 } 31 transform.position = item.position; 32 } 33 }
八、IO
1)創建文件夾以及文件,文件的移動與剪切
1 public class IoText : MonoBehaviour 2 { 3 //文件夾路徑 4 private string directorypath01 = @"F:/aa"; 5 private string directoryPath = @"F:/aa/bb"; 6 //文件路徑 7 private string filePath = @"F:/aa/bb/text.txt"; 8 //Move和Copy 剪切和復制 9 private string destinationPath = @"F:/cc/dd"; 10 private string destinationFilePath = @"F:/cc/dd/text.txt"; 11 private string destinationFilePath02 = @"F:/cc/dd/text01.txt"; 12 13 private void Start() 14 { 15 // MoveFile(filePath, destinationFilePath,destinationPath); 16 CopyFile(filePath, destinationFilePath02); 17 } 18 19 20 //創建文件夾 21 private void DirectoryCreat(string path) 22 { 23 //創建文件夾,注意創建文件夾時不能帶上文件夾后面的文件名,否則會將文件以文件夾的方式進行創建。 24 if (!Directory.Exists(path)) 25 Directory.CreateDirectory(path); 26 //刪除文件夾以及其子文件夾,true刪除文件夾以及子文件夾,false在刪除時會報錯 27 Directory.Delete(path, true); 28 } 29 30 private void FileCreat(string filePath) 31 { 32 //創建文件夾以及文件 33 DirectoryInfo newDirectoryPath = new DirectoryInfo(directoryPath); 34 if (!newDirectoryPath.Exists) newDirectoryPath.Create(); 35 if (!File.Exists(filePath)) File.Create(filePath); 36 } 37 38 private void MoveFile(string filePath,string destinationFilePath,string destinationPath) 39 { 40 //Directory.CreateDirectory(destinationPath); 41 //創建目標文件夾路徑 42 DirectoryInfo newDir = new DirectoryInfo(destinationPath); 43 if (!newDir.Exists) newDir.Create(); 44 //剪切 45 if (File.Exists(filePath)) File.Move(filePath, destinationFilePath); 46 else throw new Exception("文件夾為空!"); 47 } 48 49 private void CopyFile(string filePath,string desFilePath) 50 { 51 string[] newstringArr = desFilePath.Split('/'); 52 string desDirPath =null; 53 for (int i = 0; i < newstringArr.Length-1; i++) 54 { 55 desDirPath += newstringArr[i]; 56 desDirPath += "/"; 57 58 } 59 60 desDirPath = desDirPath.Substring(0, desDirPath.Length - 1); 61 62 if (File.Exists(filePath) && Directory.Exists(desDirPath) && !File.Exists(desFilePath)) 63 File.Copy(filePath, desFilePath); 64 else throw new Exception("there is a error!"); 65 66 } 67 }
2)使用Streaming I/O讀取StreamingAssets下面的文本文件,注意文件需要放置在如圖所示的文件夾中
1 public class IoConfigText : MonoBehaviour 2 { 3 private Dictionary<string, Dictionary<string, string>> dic; 4 private string configFilePath; 5 6 private void Start() 7 { 8 configFilePath = Path.Combine(Application.streamingAssetsPath, "Config.txt"); 9 dic = new Dictionary<string, Dictionary<string, string>>(); 10 GetConfigLines(configFilePath, ref dic); 11 } 12 13 private void OnGUI() 14 { 15 16 if (GUILayout.Button("生成")) 17 { 18 print(dic["Money"]["Gold"]); 19 } 20 21 } 22 23 private void GetConfigLines(string Filepath,ref Dictionary<string, Dictionary<string, string>> dic) 24 { 25 string[] fileLines = null; 26 int dicIndex = 0; 27 if (File.Exists(Filepath)) 28 { 29 fileLines = File.ReadAllLines(Filepath); 30 } 31 for (int i = 0; i < fileLines.Length; i++) 32 { 33 if (fileLines[i].StartsWith("[")) 34 { 35 dicIndex = i; 36 CutLine(ref fileLines[i]); 37 Dictionary<string, string> sonDic = new Dictionary<string, string>(); 38 dic.Add(fileLines[i], sonDic); 39 } 40 else if( !fileLines[i].StartsWith("[") && !string.IsNullOrEmpty(fileLines[i])) 41 { 42 string stringLeft; 43 string stringRight; 44 CutLine(fileLines[i], out stringLeft, out stringRight); 45 dic[fileLines[dicIndex]].Add(stringLeft, stringRight); 46 } 47 } 48 } 49 50 /// <summary> 51 /// 根據字符串中的[]進行截取,只保留原字符串中[]中包括的部分。 52 /// </summary> 53 /// <param name="fileLine">需要變更的字符串</param> 54 private void CutLine(ref string fileLine) 55 { 56 //string newLine = fileLine.Substring(1, fileLine.IndexOf(']') - 1);可以用此句代替 57 string[] newLine = fileLine.Split('[', ']'); 58 fileLine = newLine[1]; 59 } 60 /// <summary> 61 /// 根據字符串的文本=進行截取,保留左右兩邊的部分。 62 /// </summary> 63 /// <param name="fileLine"></param> 64 private void CutLine(string fileLine,out string string01,out string string02) 65 { 66 //fileLine.Split(new char[] { '=' }, System.StringSplitOptions.RemoveEmptyEntries);可以用這一句代替Replace 67 fileLine = fileLine.Replace(" ", ""); 68 string[] newLine = fileLine.Split('='); 69 string01 = newLine[0]; 70 string02 = newLine[1]; 71 } 72 }
九、尋路系統
常用參數:
Radius 尋路的碰撞半徑
Height尋路的碰撞高度
BaseOffset 尋路碰撞的位置
Speed 尋路物體的速度
Acceleration 轉彎時的加速度
AngularSpeed 轉彎時物體的角速度
StoppingDistance 停止的距離
AvoidancePriority 躲避系數
Nav網格尋路DEMO:實現點擊地面以及小地圖能夠自動尋路
1 [RequireComponent(typeof(NavMeshAgent))] 2 public class NavText : MonoBehaviour 3 { 4 //private Transform target; 5 6 private NavMeshAgent myNavMesh; 7 8 private Ray mainRay; 9 private RaycastHit mainHit; 10 11 private Ray mapRay; 12 private RaycastHit mapHit; 13 private void Start() 14 { 15 myNavMesh = GetComponent<NavMeshAgent>(); 16 } 17 18 private void Update() 19 { 20 21 if(Input.GetMouseButtonDown(0)) 22 { 23 24 mainRay = Camera.main.ScreenPointToRay(Input.mousePosition); 25 Physics.Raycast(mainRay, out mainHit, 100); 26 if(mainHit.collider != null && mainHit.collider.gameObject.layer == 4) 27 { 28 print(mainHit.point); 29 CalculatePath(mainHit.point); 30 } 31 32 if(Camera.allCameras[1] != null) 33 { 34 mapRay = Camera.allCameras[1].ScreenPointToRay(Input.mousePosition); 35 Physics.Raycast(mapRay, out mapHit, 100); 36 if (mapHit.collider != null && mapHit.collider.gameObject.layer == 1) 37 { 38 print(mapHit.point); 39 CalculatePath(mapHit.point); 40 } 41 } 42 } 43 } 44 private void CalculatePath(Vector3 target) 45 { 46 if(myNavMesh != null) 47 myNavMesh.SetDestination(target); 48 49 } 50 }
十、動畫系統Animator
轉自:https://www.cnblogs.com/DGJS/p/11051525.html
新建Animator Controller文件
AnyState:任意狀態;常用作播放死亡狀態,不管當前角色在播放什么狀態,都可以被殺死然后播放死亡動作;
Entry/Exit:進入狀態機和退出狀態機,進入狀態機默認連接默認狀態動畫;
Idle:橙色(名字可以改),一般是默認動畫,一般播放待機動畫;
Run:一般狀態(名字可以改)
動畫狀態機的層和參數:
Layer:動畫狀態機中還可以嵌套一個動畫狀態機;
Paramters:狀態切換參數(int float bool trigger);
動畫狀態切換
Solo:動畫切換優先;
Mute:動畫切換禁止;
Has Exit time :勾選上會在切換動畫時上一動作結束后再播放下一動畫
Setting: ExitTime:動作切換上一動作退出時間;
Fixed Duration/Transtion Duration:動作切換時間長度;
Transtion offset:下一動作所在上一動作比例;(動手測試下);
Interruption sources:打斷動畫切換來源:
重要:conditions:這里面的切換動作參數是paramers里面定義的,條件可以使大於、等於、不等於、小於
Animator組件:
Controller:AnimatorController文件;
Avatar:放骨骼文件;
Apply Root motion:如果勾選代表使用動畫中的位移;如果當前游戲物體上的代碼組件中有OnAnimatorMove內置函數,位移就受代碼控制;
Update Mode:正常更新、物理更新(FixUpdata更新)、不受時間縮放影響;
Culling Mode:
始終有動畫;
當攝像機沒有渲染該物體,就會停止部分Transform相關功能;
當攝像機沒有渲染該物體,整個動畫都不會被渲染;
代碼操作Animator
戰斗攻擊流程圖
十一、物理引擎(待補充)
射線的常見三個用法:
檢測鼠標點擊位置,線性檢測,球形檢測
1 public class ExplodeEffect : MonoBehaviour 2 { 3 4 private void Start() 5 { 6 7 } 8 9 private void Update() 10 { 11 if (Input.GetKeyDown(KeyCode.Space)) OverlapSphereCast(); 12 13 // Debug.DrawLine(this.transform.position, TargetTran.position, Color.red); 14 } 15 16 public Transform TargetTran; 17 private RaycastHit hit; 18 private void LineRayCast() 19 { 20 //線性檢測,將檢測過程途中的第一個物體進行輸出 21 int layer = (1 << 9) | (1 << 8); 22 if (Physics.Linecast(this.transform.position, TargetTran.position, out hit, layer)) 23 hit.collider.GetComponent<MeshRenderer>().material.color = Color.red; 24 } 25 26 27 private void ScreenRayCast() 28 { 29 int layer = (1 << 9) | (1 << 8); 30 //相機發射射線的應用,可以用於獲取鼠標的位置 31 //通過相機類中的ScreenPointToRay方法返回一個射線。 32 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 33 //發射射線 34 if (Physics.Raycast(ray, out hit, layer)) 35 hit.collider.GetComponent<MeshRenderer>().material.color = Color.red; 36 //實現效果,鼠標移動到物體,物體變為紅色。 37 } 38 39 public float upwardsModifier;//決定了爆炸力給予的Y軸分量 40 public float force; 41 42 private void OverlapSphereCast() 43 { 44 int layer = (1 << 9) | (1 << 8); 45 //球型檢測,范圍檢測,可用於制作爆炸效果 46 Collider[] exColliders = Physics.OverlapSphere(this.transform.position, 20, layer); 47 if (exColliders != null) 48 { 49 foreach (var item in exColliders) 50 { 51 item.GetComponent<MeshRenderer>().material.color = Color.red; 52 Rigidbody rig = item.GetComponent<Rigidbody>(); 53 //添加爆炸力效果 54 rig.AddExplosionForce(force, this.transform.position, 20, upwardsModifier, ForceMode.Impulse); 55 } 56 } 57 } 58 59 }
Demo01:https://pan.baidu.com/s/1BzZlvZU7RTQq_WyAhRCkTg llcl
Demo02:https://pan.baidu.com/s/1ffqdV7VnL0L90kMMBWH9NA q02o
十二、Itween
轉自:https://www.cnblogs.com/martianzone/p/3397422.html
一.iTween 介紹
iTween是一個動畫庫,目的是最小的投入實現最大的產出.讓你做開發更輕松,用它可以輕松實現各種動畫,晃動,旋轉,移動,褪色,上色,控制音頻等等。
二.iTween 原理
iTween的核心是數值插值,簡單說就是給iTween兩個數值(開始值,結束值),它會自動生成一些中間值,例如:, 開始值-> 中間值 -> 中間值 …. -> 結束值。
這里的數值可以理解為: 數字,坐標點,角度,物體大小,物體顏色,音量大小等。
三.主要文件有兩個iTween.cs 和 iTweenPath.unitypackage(編輯路徑才需要這個包)
http://l6.yunpan.cn/lk/Qv44q7AV7emHG
四.如何將iTween 加入項目:
在項目中建立Plugins目錄, 然后將下載的iTween.cs放到Plugins目錄即可。
如果需要編輯路徑, 使用import package->custom package菜單功能加入iTweenPath.unitypackage。
五.幾種效果演示
1. 物體移動
iTween.MoveTo(gameObject,new Vector3(100,200,0),2);
其中第一個參數是要移動的物體
第二個參數是要移動到的目標點坐標
第三個參數是移動需要的時間,然后物體將在2秒之內移動到坐標點為(x=100,y=200,z=0)的位置。
如果你需要在物體移動過程中更好的控制,我們可以添加更多的參數(所有函數可用的參數列表可以參考http://itween.pixelplacement.com/documentation.php):
1
|
iTween.MoveTo(gameObject,iTween.Hash(
"position"
,
new
Vector3(100,200,0),
"time"
,2));
|
這一段代碼的效果與第一個例子效果是一樣的,只是第二個參數是一個字典類型的數據,可以設置更多的參數。
通用的參數介紹如下:
position:坐標,包括x,y,z三個軸向
path:路徑,是一個坐標數組,后面會講到iTweenPath腳本的使用,配合着itweenPath可以讓物體沿着路徑點移動。
x:x軸向的位置,如果只設置了x軸,物體就只移動x軸,y,z軸不會改變
orienttopath:如果設置為true,物體移動到目標點的過程中,z軸會一直朝向下一個目標點
looktarget:物體朝向,物體在移動過程中會一直朝向我們設置的坐標點的坐標
looktime:物體看向looktarget或orienttopath設置坐標的時間
islocal:當物體的目標點是相對於父節點的坐標,需要把isLocal設置為true,否則為false
time speed:這兩個參數都可以控制物體移動的快慢
delay:延遲時間,當物體開始移動之前等待時間
easetype:移動模式,我們可以設置一些加速度的效果,這個參數值是一個枚舉iTween.Easetype
looptype:循環模式,一共有三種模式
iTween.LoopType.none:不循環
iTween.LoopType.loop:循環,物體移動到終點后會跳到起點重新移動
iTween.LoopType.pingPong:來回循環,物體移動到終點后會再以相同的模式和時間再移動到起點,然后再移動到終點,一直循環
onstart:物體開始移動之前的回調函數
onstarttarget:回調函數接收對象,默認開始之前會向iTween.MoveTo函數的第一個參數的物體發送回調,根據需要在這里設置合適的回調接收者
onstartparams:回調方法的參數
onupdate:物體在移動過程中的回調函數
onupdatetarget:物體在移動過程中回調函數的接收者
onupdateparams:移動過程中回調函數的參數
oncomplete:物體移動完成后的回調
oncompletetarget:物體移動完成后的回調函數的接收者
oncompleteparams:物體移動完成后的回調函數的參數
ignoretimescale:忽略時間縮放,時間縮放是Time.timeScale = 0.5f; 默認值為1,如果我們把時間縮放值設置小於1,我們游戲的整體時間都會放慢,就像播放慢鏡頭一樣,如果設置ignoretimescale為true,無論我們時間怎么縮放,對物體的移動都沒有影響。
只要我們了解了itween的其中一個使用方式,其他的都是一樣的做法。
我們可以做的動畫有:位移,旋轉,縮放,音量漸變,攝像機淡入淡出,顏色的漸變,物體振動等很多有用的動畫。
2. 數值過渡
iTween.ValueTo(gameObject, iTween.Hash( "from", y, "to", toY, "easetype", easeType, "loopType", loopType, "onupdate", "onupdate", "time", tm ));
3. 振動
iTween.ShakePosition(target, new Vector3(0, 0.1f, 0), 1);
4. 按路徑移動
var path = GameObject.Find("Plane").GetComponent("iTweenPath").GetPath("myPath"); iTween.MoveTo(gameObject, iTween.Hash(//"position", Vector3(0, 0, 0), "path", path, "time", 20, "easetype", "linear"));
以下是iTween插件各方法的大致用法,每個方法都有簡單傳參和Hashtable定制兩種用法,Hashtable可用iTween.Hash()生成,每個方法所需參數及其功能請參考iTween內部提示。
常用方法簡介:
AudioFrom:pitch和volum屬性提供的是初始值
audioTo: pitch和volum屬性提供的是終結值
audioUpdate:pitch和volum屬性提供的是終結值 此方法用於Update()方法中
stab:播放AudioClip一次,不用手動加載AudioSource組件
CameraFadeAdd:創建一個對象可以模擬攝相機的淡入淡出。
CameraFadeSwap:改變攝相機的淡入淡出背景圖(對象為CameraFadeAdd返回對象)
CameraFadeFrom:立即改變攝相淡入淡出的透明度然后隨時間返回.amount:當執行淡入淡出時,其透明度的變化速度。(透明度越大,淡入淡出越快,個人認為100為滿,如果速度較快,時間較長,漸變效果會在時間快要結束時出現。此方法配合CameraFadeAdd使用,只有在CameraFadeAdd前提下,才可以進行淡入淡出操作。此方法為從CameraFadeAdd返回的對象出淡出到原來的界面。
CameraFadeTo:隨時間改變攝相機淡入淡出透明度,此方法為從本界面淡入到CameraFadeAdd返回的對象
ColorFrom:即刻改變對象的顏色值然后隨着時間改變其回原來的顏色(總的來說,就是對GUIText和GUITexture的顏色的淡入淡出效果)。Color:此屬性代表對象變化初始值。與audioFrom有異曲同工之效
ColorTo:隨着時間改變對象的顏色組。同上例一樣。Color:此屬性代表對象變化最終值,與audioTo有異曲同工之效
(注意,ColorFrom和ColorTo還有后面的ColorUpdate方法的NamedColorValue屬性,有一些對象不具有NamedColorValue里的屬性,運行時會有提示)
ColorUpdate:跟ColorTo類似,但花銷的成本較少,此方法在Update方法中被調用
FadeFrom:即刻改變對象的的阿爾法值,然后隨着時間將其阿爾法值變回原值。如果對象上有掛載
a Light, GUIText or GUITexture這些組件,這些組件將成為被執行的對象。
注:阿爾法值可以粗略理解為對象的透明度,值越小,透明度越大。這里的 alpha或者 amount 是變化初值
FadeTo:同上,alpha或amount是變化終值。
FadeUpdate :同FadeTo類似,在Update()方法中調用,提供時刻改變屬性值的環境。不局限於 EaseType
LookFrom:即刻旋轉物體讓其看提供的Vector3或都Transfrom,然后隨時間旋轉回原來的角度值
注:物體的臉部一般以本地坐標(即物體坐標)的Z軸,臉部朝向方法,即Z軸指向方法。
LookTo:隨時間旋轉物體讓其臉部朝向所提供的Vector3或Transform位置。
LookUpdate:同LookTo類似,在Update()方法中調用。
MoveAdd:隨時間改變游戲對象的位置(原理還有點蒙,感覺跟MoveBy有點像)amount:是改變物體位置的一個值,不是目標位置的坐標。
MoveBy:增加提供的坐標到游戲對象的位置
MoveFrom:立即改變游戲對象的位置為提供的,然后隨時間改變游戲對象位置到初始位置
屬性:movetopath:Boolean值 ,是否自動將物體置於Ptah的起始點,默認值為真
Path:目標文件可用路徑編緝器獲得
PunchPosition:對物體的位置添加一個搖晃的力,使其搖晃最終歸於原來的位置 其晃動大小和方法由提供的amount(Vector3)決定(方法由Vector3的x,y,z共同決定,晃動大小,由各個方法的值的大小決定)
PunchRotation:對物體的旋轉添加一個搖晃的力,使其旋轉最終歸於初始值。其旋轉角度大小和方向由提供的Vector3決定,建議用單軸而不是整個Vector3,例如(0,1,0)是繞Y軸旋轉,角度大小由Vector3Y軸值大小決定
PunchScale:對物體的大小比例添加一個搖晃的力,使其大小比例變化最終歸於初始值。其大小比例變
化方向和大小由提供的Vector3決定。例如(0,1,0)是在Y軸方向對物體大小變化(即變化物體的高)
,大小由該方向的值大小決定
PutOnPath :根據提供的百分比將游戲物體置於所提供路徑上(1為百分之百)。
PointOnPath:根據提供的百分比返回一條路徑上的Vector3的位置
RectUpdate:返回一個RECT在提供的兩個值之間,大小變化根據提供的速度
Vector3Update:返回一個Vector3在提供的兩個值之間,大小變化根據提供的速度
Vector2Update:返回一個Vector3在提供的兩個值之間,大小變化根據提供的速度
FloatUpdate:返回一個float在提供的兩個值之間,大小變化根據提供的速度
RotateAdd:對游戲物體的旋轉角度隨着時間增加所提供的歐拉角(順時針旋轉。Vector3三個值解析:
X,Y,Z各代表圍繞哪個軸轉動。其轉動角度就是X,Y,Z、的值的大小。amount:歐拉角大小)
RotateBy:把提供的值乘以360,然后隨着時間旋轉游戲物體的角度按計算得的值。例 如(0,1,0)就是繞Y軸旋轉360度。 順時針旋轉
RotateFrom:立即改變游戲物體角度的歐拉角,然后隨着時間旋轉回原來的角度,屬性提供的歐拉角為變化初始值
RotateTo:旋轉游戲物體角度到我們所提供的歐拉角角度。屬性提供的歐拉角為變化終結值
RotateUpdate:跟RotateTo類似,該方法在Update中被調用,提供一個可改變屬性值的環境。不用局限EaseType
ScaleAdd:隨着時間根據提供的amount(Vector3)增加游戲物體的大小
ScaleBy:隨着時間變形游戲物體,游戲物體最終變形大小由我們提供的amount(Vector3)值決定 算法:
最終變形大小=游戲物體初始的sacle * 我們提供的 amount值
ScaleFrom:立即改變游戲物體的比例大小,然后隨時間返回游戲物體原本的大小。amount:為物體變形的初始大小
ScaleTo:隨着時間改變物體的比例大小到我們提供的Scale大小(scale值)
ScaleUpdate:跟ScaleTo類似,此方法用於Update中,提供可改變屬性值的環境 ,不用局限於EaeType
ShakePosition:根據提供的amount衰減其值隨機搖動游戲物體的位置,其晃動大小和方向由提供的amount(Vector3)決定(方向根據Vector3隨機,晃動大小,由各個方向的值的大小決定)
ShakeRotation:根據提供的amount衰減其值隨機擺動旋轉游戲物體的角度 。Vector3三個值解析:X,Y,Z各代表圍繞哪個軸旋轉。其轉動角度就是X,Y,Z、的值的大小
ShakeScale:根據提供的amount衰減其值隨機擺動改變游戲物體的大小。其大小比例變化方向和大小由提供的Vector3決定。例如(0,1,0)是在Y軸方向對物體大小變化(即變化物體的高),大小由該方向的值大小決定
Pause:停止iTween 如果一個iTween以ignoreTimeScale定制且設為True停止工作。 參考不同參數Pause的說明。
Stop:停止iTweens,和Pause一樣,不同的參數有不同作用。
Stop By Name:停止指定名字的iTween
ValueTo:返回一個插值在兩件值之間的回調函數的值(作用不明)
(Returns a value to a callback method interpolated between the supplied 'from' and 'to'
values for application as desired. Requires an 'onupdate' callback that accepts the same
type as the supplied 'from' and 'to' properties.)