void OnGUI(){if(GUI.Button(Rect position, string text)){ //點(diǎn)擊后立即執(zhí)行}
每個手指觸控是通過Input.touches數(shù)據(jù)結(jié)構(gòu)描述的:
Phase can be one of the following:
相位(狀態(tài))可能是下列之一:
下面的例子,只要用戶在屏幕上點(diǎn)擊,將射出一條光線:
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 //從當(dāng)前的觸摸坐標(biāo)建一條光線 var ray = Camera.main.ScreenPointToRay (touch.position); if (Physics.Raycast (ray)) { // Create a particle if hit //如果觸摸就創(chuàng)建一個例子 Instantiate (particle, transform.position, transform.rotation); } } }}
UICamera主要負(fù)責(zé)監(jiān)聽,分發(fā)所有此Camera渲染的GameObject。
事件源:鼠標(biāo),觸屏,鍵盤和手柄
事件包括:懸停,按下/抬起,選中/取消選中,點(diǎn)擊,雙擊,拖拽,釋放,文本輸入,tips顯示,滾輪滑動,鍵盤輸入。
EventType:包括3D UI,3D world,2D UI,3D World用于區(qū)分UICamera處理UI事件的對象是UI空間還是3D物體。
EventMask:可以過濾到一些不需要接受UI事件的對象。
EventSource:只處理指定事件源,如touch
Thresholds:是指事件誤差的范圍。
直接將MonoBehaviour的腳本上的方法綁定至Notifiy上面。這種方法不夠靈活,不推薦。
過期方式,不建議使用。
在需要接收事件的gameobject上附加Event Listener。添加component->NGUI->Internal->Event Listener。
在任何一個腳本或者類中即可得到按鈕的點(diǎn)擊事件、把如下代碼放在任意類中或者腳本中。
void Awake () { //獲取需要監(jiān)聽的按鈕對象 GameObject button = GameObject.Find("UI Root (2D)/Camera/Anchor/Panel/LoadUI/MainCommon/Button"); //設(shè)置這個按鈕的監(jiān)聽,指向本類的ButtonClick方法中。 UIEventListener.Get(button).onClick = ButtonClick; } //計算按鈕的點(diǎn)擊事件 void ButtonClick(GameObject button) { Debug.Log("GameObject " + button.name); }
UIEventListener.Get(gameObject).onClick = ButtonClick;//1、獲取GameObject對應(yīng)的UIEventListener的組件static public UIEventListener Get (GameObject go) { UIEventListener listener = go.GetComponent<UIEventListener>(); if (listener == null) listener = go.AddComponent<UIEventListener>(); return listener; }//2、注冊事件委托public class UIEventListener : MonoBehaviour{ public delegate void VoidDelegate (GameObject go); public VoidDelegate onClick; void OnClick (){ if (onClick != null) onClick(gameObject); }}
觀察者模式定義了一種一對多的依賴關(guān)系,讓多個觀察者對象同時監(jiān)聽某一個主題對象,這個主題對象在狀態(tài)發(fā)生變化時,會通知所有的觀察者對象,使他們能夠執(zhí)行自己的相關(guān)行為。
可以看出,在觀察者模式的結(jié)構(gòu)圖有以下角色:
1、委托定義
在C#中定義一個委托非常簡單,只要包含關(guān)鍵詞delegate,其他的與普通方法一致。
public delegate void GreetingDelegate(string name);
委托是一個類,它定義了方法的類型,使得可以將方法當(dāng)作另一個方法的參數(shù)來進(jìn)行傳遞,這種將方法動態(tài)地賦給參數(shù)的做法,可以避免在程序中大量使用If-Else(Switch)語句,同時使得程序具有更好的可擴(kuò)展性。(與java中的接口非常相似)。
2、方法綁定委托
上面的綁定onclick即是一個方法綁定。
UIEventListener.Get(gameObject).onClick = ButtonClick;
委托方法可以綁定多個方法,調(diào)用時會一次調(diào)用綁定的方法。
UIEventListener.Get(gameObject).onClick += ButtonClick2;
委托還可以通過-=的方式解除綁定。
注意:第一次綁定必須用賦值=,如果使用+=將會發(fā)生編譯錯誤。
設(shè)置fallThrough為攝像機(jī)節(jié)點(diǎn)的UI Root節(jié)點(diǎn)或者攝像機(jī)節(jié)點(diǎn)或者當(dāng)前本身gameobject。
Unity提供了Input接口,能夠從觸屏中獲取各類輸入事件。Update的時候查看事件輸入情況,并通過PRocessTouches處理觸屏事件。
ProcessTouches函數(shù)
public void ProcessTouches () { currentScheme = ControlScheme.Touch; for (int i = 0; i < Input.touchCount; ++i) { Touch touch = Input.GetTouch(i); currentTouchID = allowMultiTouch ? touch.fingerId : 1; //根據(jù)TouchID獲取touch事件,如果是begin的則創(chuàng)建新對象加入緩存 currentTouch = GetTouch(currentTouchID); //設(shè)置當(dāng)前輸入的相位 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 //通過射線獲取可以點(diǎn)擊的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的多次點(diǎn)擊,則需要設(shè)置時間戳 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 } }
這里需要重點(diǎn)介紹Raycast(Vector3 inpos)和ProcessTouch()。
list中緩存這當(dāng)前場景中,所有的攝像機(jī),并按照深度來排序。
主要處理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);//找到屏幕坐標(biāo) 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; //如果父節(jié)點(diǎn)上有剛體,則返回 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>(); //根據(jù)UIWidget或者UIRect來判斷,落點(diǎn)是不是在節(jié)點(diǎn)里面 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); } } //根據(jù)深度排序 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 //最上層且可見的,為返回的節(jié)點(diǎn) 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根據(jù)閥值,判斷需要通知的事件類型。直接調(diào)用RasyCast返回的GameObject上UIEventListen注冊的事件。
通過直接執(zhí)行事件委托(onClick),或者SendMessage給返回的GameObject上的相關(guān)事件委托。
游戲界面中所顯示的內(nèi)容是攝像機(jī)照射到得場景部分。攝像機(jī)可以設(shè)置自身的位置、照射方向、照射的面積(類似于顯示中照射廣度)和照射的圖層(只看到自己想看到的層次)。
Clear Flags:背景內(nèi)容,默認(rèn)為Skybox
Background:Clear Flag沒設(shè)置,將顯示純色
Culling Mask:用于選擇是否顯示某些層,默認(rèn)為“EveryThing”
Projection:攝像機(jī)類型,透視和正交。正交適合2D,沒有距離感。
Clipping Planes:開始攝像的最近點(diǎn)和最遠(yuǎn)點(diǎn)
Viewport Rect:設(shè)置顯示區(qū)域。多攝像機(jī)可以設(shè)置不同的區(qū)域,來進(jìn)行分屏顯示。
Depth:深度大的會,畫在小的上面。
Rendering Path:渲染方式。
Colider是所有碰撞器的基類,包括BoxColider,SphereColider,CapsuleColider,MeshColider,PhysicMaterial,Rigidbody。
剛體可以附加物理屬性如物體質(zhì)量、摩擦力和碰撞系數(shù)。
Mass:質(zhì)量
Drag:阻力
Angular Drag:旋轉(zhuǎn)阻力,越大旋轉(zhuǎn)減慢越快
Use Gravity:是否用重力
Is Kinematic:是否受物理的影響
Collision Detection:碰撞檢測
Constraints:凍結(jié),某個方向上的物理效果
通過sendMessage調(diào)用改方法
OnCollisionEnter(Collision collision):開始時,立刻調(diào)用
OnCollisionStay(Collision collision):碰撞中,每幀調(diào)用
OnCollisionExit(Collision collision):結(jié)束時調(diào)用
BoxColider(盒子碰撞器),SphereColider(球體碰撞器),CapsuleColider(膠囊碰撞器),MeshColider(自定義模型自身網(wǎng)格決定),WheelMaterial(車輪碰撞器)。
碰撞器之間可以添加物理材質(zhì),用于設(shè)定物理碰撞后的效果。如反彈。
射線是3D世界中一個點(diǎn)向一個方向發(fā)射的一條無終點(diǎn)的線。在發(fā)射的軌跡中,一旦與其他模型發(fā)生碰撞,它將停止發(fā)射(也可以是All)。
創(chuàng)建一個射線首先要知道射線的起點(diǎn)和終點(diǎn)在3D世界中的坐標(biāo)。Ray即為起點(diǎn)和終點(diǎn)的封裝。ScreenPointToRay,是由攝像機(jī)當(dāng)前位置向鼠標(biāo)位置發(fā)射的射線。
http://game.ceeger.com/Manual/Input.html
http://blog.csdn.net/onerain88/article/details/18963539
http://wetest.QQ.com
新聞熱點(diǎn)
疑難解答