void OnGUI(){ if(GUI.Button(Rect position, string text)){ //點擊後當即執行 }
每一個手指觸控是經過Input.touches數據結構描述的:html
Phase can be one of the following:android
相位(狀態)多是下列之一:ios
下面的例子,只要用戶在屏幕上點擊,將射出一條光線:緩存
var particle : GameObject; function Update () { for (var touch : Touch in Input.touches) { if (touch.phase == TouchPhase.Began) { // Construct a ray from the current touch coordinates //從當前的觸摸座標建一條光線 var ray = Camera.main.ScreenPointToRay (touch.position); if (Physics.Raycast (ray)) { // Create a particle if hit //若是觸摸就建立一個例子 Instantiate (particle, transform.position, transform.rotation); } } } }
UICamera主要負責監聽,分發全部此Camera渲染的GameObject。數據結構
事件源:鼠標,觸屏,鍵盤和手柄app
事件包括:懸停,按下/擡起,選中/取消選中,點擊,雙擊,拖拽,釋放,文本輸入,tips顯示,滾輪滑動,鍵盤輸入。ide
EventType:包括3D UI,3D world,2D UI,3D World用於區分UICamera處理UI事件的對象是UI空間仍是3D物體。函數
EventMask:能夠過濾到一些不須要接受UI事件的對象。源碼分析
EventSource:只處理指定事件源,如touchui
Thresholds:是指事件偏差的範圍。
直接將MonoBehaviour的腳本上的方法綁定至Notifiy上面。這種方法不夠靈活,不推薦。
過時方式,不建議使用。
在須要接收事件的gameobject上附加Event Listener。添加component->NGUI->Internal->Event Listener。
在任何一個腳本或者類中便可獲得按鈕的點擊事件、把以下代碼放在任意類中或者腳本中。
void Awake () { //獲取須要監聽的按鈕對象 GameObject button = GameObject.Find("UI Root (2D)/Camera/Anchor/Panel/LoadUI/MainCommon/Button"); //設置這個按鈕的監聽,指向本類的ButtonClick方法中。 UIEventListener.Get(button).onClick = ButtonClick; } //計算按鈕的點擊事件 void ButtonClick(GameObject button) { Debug.Log("GameObject " + button.name); }
UIEventListener.Get(gameObject).onClick = ButtonClick; //一、獲取GameObject對應的UIEventListener的組件 static public UIEventListener Get (GameObject go) { UIEventListener listener = go.GetComponent<UIEventListener>(); if (listener == null) listener = go.AddComponent<UIEventListener>(); return listener; } //二、註冊事件委託 public class UIEventListener : MonoBehaviour { public delegate void VoidDelegate (GameObject go); public VoidDelegate onClick; void OnClick (){ if (onClick != null) onClick(gameObject); } }
觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象在狀態發生變化時,會通知全部的觀察者對象,使他們可以執行本身的相關行爲。
能夠看出,在觀察者模式的結構圖有如下角色:
一、委託定義
在C#中定義一個委託很是簡單,只要包含關鍵詞delegate,其餘的與普通方法一致。
public delegate void GreetingDelegate(string name);
委託是一個類,它定義了方法的類型,使得能夠將方法看成另外一個方法的參數來進行傳遞,這種將方法動態地賦給參數的作法,能夠避免在程序中大量使用If-Else(Switch)語句,同時使得程序具備更好的可擴展性。(與Java中的接口很是類似)。
二、方法綁定委託
上面的綁定onclick便是一個方法綁定。
UIEventListener.Get(gameObject).onClick = ButtonClick;
委託方法能夠綁定多個方法,調用時會一次調用綁定的方法。
UIEventListener.Get(gameObject).onClick += ButtonClick2;
委託還能夠經過-=的方式解除綁定。
注意:第一次綁定必須用賦值=,若是使用+=將會發生編譯錯誤。
設置fallThrough爲攝像機節點的UI Root節點或者攝像機節點或者當前自己gameobject。
Unity提供了Input接口,可以從觸屏中獲取各種輸入事件。Update的時候查看事件輸入狀況,並經過ProcessTouches處理觸屏事件。
ProcessTouches函數
public void ProcessTouches () { currentScheme = ControlScheme.Touch; for (int i = 0; i < Input.touchCount; ++i) { Touch touch = Input.GetTouch(i); currentTouchID = allowMultiTouch ? touch.fingerId : 1; //根據TouchID獲取touch事件,若是是begin的則建立新對象加入緩存 currentTouch = GetTouch(currentTouchID); //設置當前輸入的相位 bool pressed = (touch.phase == TouchPhase.Began) || currentTouch.touchBegan; bool unpressed = (touch.phase == TouchPhase.Canceled) || (touch.phase == TouchPhase.Ended); currentTouch.touchBegan = false; // Although input.deltaPosition can be used, calculating it manually is safer (just in case) //若是不是開始按下,就須要計算與上一次的偏移狀況 currentTouch.delta = pressed ? Vector2.zero : touch.position - currentTouch.pos; currentTouch.pos = touch.position; // Raycast into the screen //經過射線獲取能夠點擊的gameobject if (!Raycast(currentTouch.pos)) hoveredObject = fallThrough; if (hoveredObject == null) hoveredObject = mGenericHandler; currentTouch.last = currentTouch.current; currentTouch.current = hoveredObject; lastTouchPosition = currentTouch.pos; // We don't want to update the last camera while there is a touch happening if (pressed) currentTouch.pressedCam = currentCamera; else if (currentTouch.pressed != null) currentCamera = currentTouch.pressedCam; // Double-tap support //ios的屢次點擊,則須要設置時間戳 if (touch.tapCount > 1) currentTouch.clickTime = RealTime.time; // Process the events from this touch ProcessTouch(pressed, unpressed); // If the touch has ended, remove it from the list if (unpressed) RemoveTouch(currentTouchID); currentTouch.last = null; currentTouch = null; // Don't consider other touches if (!allowMultiTouch) break; } if (Input.touchCount == 0) { if (useMouse) ProcessMouse(); #if UNITY_EDITOR else ProcessFakeTouches(); #endif } }
這裏須要重點介紹Raycast(Vector3 inpos)和ProcessTouch()。
list中緩存這當前場景中,全部的攝像機,並按照深度來排序。
主要處理World_3D、UI_3D、World_2D和UI_2D4種不一樣類型的。
static public bool Raycast (Vector3 inPos) { for (int i = 0; i < list.size; ++i) { UICamera cam = list.buffer[i]; // Skip inactive scripts //沒有激活的,所有跳過 if (!cam.enabled || !NGUITools.GetActive(cam.gameObject)) continue; // Convert to view space currentCamera = cam.cachedCamera; Vector3 pos = currentCamera.ScreenToViewportPoint(inPos);//找到屏幕座標 if (float.IsNaN(pos.x) || float.IsNaN(pos.y)) continue; // If it's outside the camera's viewport, do nothing if (pos.x < 0f || pos.x > 1f || pos.y < 0f || pos.y > 1f) continue; // Cast a ray into the screen Ray ray = currentCamera.ScreenPointToRay(inPos); // Raycast into the screen //UI層和事件層都OK的 int mask = currentCamera.cullingMask & (int)cam.eventReceiverMask; float dist = (cam.rangeDistance > 0f) ? cam.rangeDistance : currentCamera.farClipPlane - currentCamera.nearClipPlane; if (cam.eventType == EventType.World_3D) { if (Physics.Raycast(ray, out lastHit, dist, mask)) { lastWorldPosition = lastHit.point; hoveredObject = lastHit.collider.gameObject; //若是父節點上有剛體,則返回 Rigidbody rb = FindRootRigidbody(hoveredObject.transform); if (rb != null) hoveredObject = rb.gameObject; return true; } continue; } else if (cam.eventType == EventType.UI_3D) { RaycastHit[] hits = Physics.RaycastAll(ray, dist, mask); if (hits.Length > 1) { //碰到多個colider for (int b = 0; b < hits.Length; ++b) { GameObject go = hits[b].collider.gameObject; UIWidget w = go.GetComponent<UIWidget>(); //根據UIWidget或者UIRect來判斷,落點是否是在節點裏面 if (w != null) { if (!w.isVisible) continue; if (w.hitCheck != null && !w.hitCheck(hits[b].point)) continue; } else { UIRect rect = NGUITools.FindInParents<UIRect>(go); if (rect != null && rect.finalAlpha < 0.001f) continue; } //計算射線的深度 mHit.depth = NGUITools.CalculateRaycastDepth(go); if (mHit.depth != int.MaxValue) { mHit.hit = hits[b]; mHit.point = hits[b].point; mHit.go = hits[b].collider.gameObject; mHits.Add(mHit); } } //根據深度排序 mHits.Sort(delegate(DepthEntry r1, DepthEntry r2) { return r2.depth.CompareTo(r1.depth); }); for (int b = 0; b < mHits.size; ++b) { #if UNITY_FLASH if (IsVisible(mHits.buffer[b])) #else //最上層且可見的,爲返回的節點 if (IsVisible(ref mHits.buffer[b])) #endif { lastHit = mHits[b].hit; hoveredObject = mHits[b].go; lastWorldPosition = mHits[b].point; mHits.Clear(); return true; } } mHits.Clear(); } else if (hits.Length == 1) { GameObject go = hits[0].collider.gameObject; UIWidget w = go.GetComponent<UIWidget>(); if (w != null) { if (!w.isVisible) continue; if (w.hitCheck != null && !w.hitCheck(hits[0].point)) continue; } else { UIRect rect = NGUITools.FindInParents<UIRect>(go); if (rect != null && rect.finalAlpha < 0.001f) continue; } if (IsVisible(hits[0].point, hits[0].collider.gameObject)) { lastHit = hits[0]; lastWorldPosition = hits[0].point; hoveredObject = lastHit.collider.gameObject; return true; } } continue; } else if (cam.eventType == EventType.World_2D) { //用Plane射線獲取 if (m2DPlane.Raycast(ray, out dist)) { Vector3 point = ray.GetPoint(dist); Collider2D c2d = Physics2D.OverlapPoint(point, mask); if (c2d) { lastWorldPosition = point; hoveredObject = c2d.gameObject; Rigidbody2D rb = FindRootRigidbody2D(hoveredObject.transform); if (rb != null) hoveredObject = rb.gameObject; return true; } } continue; } else if (cam.eventType == EventType.UI_2D) { if (m2DPlane.Raycast(ray, out dist)) { lastWorldPosition = ray.GetPoint(dist); Collider2D[] hits = Physics2D.OverlapPointAll(lastWorldPosition, mask); if (hits.Length > 1) { for (int b = 0; b < hits.Length; ++b) { GameObject go = hits[b].gameObject; UIWidget w = go.GetComponent<UIWidget>(); if (w != null) { if (!w.isVisible) continue; if (w.hitCheck != null && !w.hitCheck(lastWorldPosition)) continue; } else { UIRect rect = NGUITools.FindInParents<UIRect>(go); if (rect != null && rect.finalAlpha < 0.001f) continue; } mHit.depth = NGUITools.CalculateRaycastDepth(go); if (mHit.depth != int.MaxValue) { mHit.go = go; mHit.point = lastWorldPosition; mHits.Add(mHit); } } mHits.Sort(delegate(DepthEntry r1, DepthEntry r2) { return r2.depth.CompareTo(r1.depth); }); for (int b = 0; b < mHits.size; ++b) { #if UNITY_FLASH if (IsVisible(mHits.buffer[b])) #else if (IsVisible(ref mHits.buffer[b])) #endif { hoveredObject = mHits[b].go; mHits.Clear(); return true; } } mHits.Clear(); } else if (hits.Length == 1) { GameObject go = hits[0].gameObject; UIWidget w = go.GetComponent<UIWidget>(); if (w != null) { if (!w.isVisible) continue; if (w.hitCheck != null && !w.hitCheck(lastWorldPosition)) continue; } else { UIRect rect = NGUITools.FindInParents<UIRect>(go); if (rect != null && rect.finalAlpha < 0.001f) continue; } if (IsVisible(lastWorldPosition, go)) { hoveredObject = go; return true; } } } continue; } } return false; }
ProcessTouch根據閥值,判斷須要通知的事件類型。直接調用RasyCast返回的GameObject上UIEventListen註冊的事件。
經過直接執行事件委託(onClick),或者SendMessage給返回的GameObject上的相關事件委託。
遊戲界面中所顯示的內容是攝像機照射到得場景部分。攝像機能夠設置自身的位置、照射方向、照射的面積(相似於顯示中照射廣度)和照射的圖層(只看到本身想看到的層次)。
Clear Flags:背景內容,默認爲Skybox
Background:Clear Flag沒設置,將顯示純色
Culling Mask:用於選擇是否顯示某些層,默認爲「EveryThing」
Projection:攝像機類型,透視和正交。正交適合2D,沒有距離感。
Clipping Planes:開始攝像的最近點和最遠點
Viewport Rect:設置顯示區域。多攝像機能夠設置不一樣的區域,來進行分屏顯示。
Depth:深度大的會,畫在小的上面。
Rendering Path:渲染方式。
Colider是全部碰撞器的基類,包括BoxColider,SphereColider,CapsuleColider,MeshColider,PhysicMaterial,Rigidbody。
剛體能夠附加物理屬性如物體質量、摩擦力和碰撞係數。
Mass:質量
Drag:阻力
Angular Drag:旋轉阻力,越大旋轉減慢越快
Use Gravity:是否用重力
Is Kinematic:是否受物理的影響
Collision Detection:碰撞檢測
Constraints:凍結,某個方向上的物理效果
經過sendMessage調用改方法
OnCollisionEnter(Collision collision):開始時,馬上調用
OnCollisionStay(Collision collision):碰撞中,每幀調用
OnCollisionExit(Collision collision):結束時調用
BoxColider(盒子碰撞器),SphereColider(球體碰撞器),CapsuleColider(膠囊碰撞器),MeshColider(自定義模型自身網格決定),WheelMaterial(車輪碰撞器)。
碰撞器之間能夠添加物理材質,用於設定物理碰撞後的效果。如反彈。
射線是3D世界中一個點向一個方向發射的一條無終點的線。在發射的軌跡中,一旦與其餘模型發生碰撞,它將中止發射(也能夠是All)。
建立一個射線首先要知道射線的起點和終點在3D世界中的座標。Ray即爲起點和終點的封裝。ScreenPointToRay,是由攝像機當前位置向鼠標位置發射的射線。
http://game.ceeger.com/Manual/Input.html