Unity3D實現甜品消消樂遊戲
前言
解釋:
之前用的ScreenToGif錄屏,因為上傳的.gif最大不超過5MB,所以做瞭不少刪幀和色彩弱化等處理,這才導致色彩看上去不是很舒服,不要盯著它看太久,不然會有點難受…
由於使用的素材是現成的,沒有花時間精力去扒,所以細節方面可能不是做的很好。
說明:
這次的甜品消消樂雖然看上去好像挺簡單普通的,但是相對於之前的坦克大戰,某種程度上已然提升難度瞭,歸類到瞭算法類層的遊戲。
拉到最後看代碼你就能理解我的意思瞭,坦克大戰的所有代碼加起來還不如消消樂兩個類的代碼多,其他各種細節,坦克也隻能望其項背…
如果坦克大戰是低階的,那麼甜品消消樂就是中階的,有著不少的動畫效果和交互(碰撞檢測和甜品的控制等),遊戲運行的所有機制和功能需要在模型層上進行操控。
這次的消消樂需要一定的邏輯思維、算法基礎、Unity綜合能力和編程基礎。
方正粗圓的字體和佈靈佈靈的閃光特效會賦予遊戲可愛風的氛圍感。
我們把物體分為模型層和渲染層,這樣它們各司其職,降低工作的耦合性。
由於12.29日放假前還剩 兩門課設答辯和一門考試,不足之處以後再補充…
項目效果展示
項目概況
素材展示
遊戲資源(音頻、圖片、特效等)
場景和包(動畫。渲染精靈和控制器等)
遊戲腳本(UI、Runtime等)
……太多瞭,隻選擇瞭部分作為展示
場景展示
在Gizmos目錄下,可以找到對應按鈕隱藏攝像機,這樣處理場景的時候會舒服很多
Clone都放上會有些雜亂,都刪掉,隻放瞭一個背景圖
場景元素
開始按鈕(玩傢通過點擊開始按鈕,進入新的一局遊戲)
重玩按鈕(玩傢可以及時返回開始界面進行相應操作)
時鐘(顯示遊戲剩餘時間,一局遊戲初始化時間是60s)
計分板(顯示當前遊戲得分)
普通甜品(甜甜圈、糖果、起司…至少同時有3個在同一排或同一列時,可以消除)
特殊甜品(一定條件下會觸發2種特殊甜品道具,一種是帶有左右晃動特效的甜品,可以消除一整排的甜品;另一種是帶有上下晃動特效的甜品,可以消除一整列的甜品)
積分面板(遊戲時間結束後,會用類似飛躍的動畫效果產生得分界面窗口,逐漸變大顯示,最終定格。點擊重玩立即開始下一局遊戲,叉掉返回開始界面)
玩法介紹
- 點擊開始進入遊戲,每一局新開的遊戲設時60s(可以根據需要調整),用最快的速度消除出現在同一行或者同一列的相同的甜點會獲得相應積分。
- 盡量用最優的策略使得一定時間內的積分最大化(不過這一點,遊戲玩熟瞭可能才能漸漸領悟,屬於大師級別的操作瞭。可以用ACM相關算法寫個外掛,應該是用動態規劃算法處理)。
- 當符合特定消除條件的甜品被消除後,會隨機產生兩類特殊甜品的一種,這個甜品會瞬間清除一整行或者一整列的甜品,使得積分暴增。
- 相同時間內積分高者或者相同積分用時少者優勝。
版本說明
小蝦選用的是Unity個人版,采用的是Unity一個較新的版本-2021.1.16,這裡建議小夥伴們下載和教程相同版本的,不然真的會有可能遇到卡點消耗心情哈。
可以和我一樣在Unity Hub裡面安裝,Hub感覺挺好用的。
但是每次重啟後都要手動激活許可證,這是真的挺煩的。
項目源碼
小蝦在這裡主要介紹部分核心代碼實現,想知道其他部分實現的小夥伴在下方留言,我再添加~
UI-PropertyDrawers-MenuOptions.cs
using System; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using UnityEngine.SceneManagement; using UnityEditor.Experimental.SceneManagement; namespace UnityEditor.UI { /// <summary> /// This script adds the UI menu options to the Unity Editor. /// </summary> static internal class MenuOptions { private const string kUILayerName = "UI"; private const string kStandardSpritePath = "UI/Skin/UISprite.psd"; private const string kBackgroundSpritePath = "UI/Skin/Background.psd"; private const string kInputFieldBackgroundPath = "UI/Skin/InputFieldBackground.psd"; private const string kKnobPath = "UI/Skin/Knob.psd"; private const string kCheckmarkPath = "UI/Skin/Checkmark.psd"; private const string kDropdownArrowPath = "UI/Skin/DropdownArrow.psd"; private const string kMaskPath = "UI/Skin/UIMask.psd"; static private DefaultControls.Resources s_StandardResources; static private DefaultControls.Resources GetStandardResources() { if (s_StandardResources.standard == null) { s_StandardResources.standard = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath); s_StandardResources.background = AssetDatabase.GetBuiltinExtraResource<Sprite>(kBackgroundSpritePath); s_StandardResources.inputField = AssetDatabase.GetBuiltinExtraResource<Sprite>(kInputFieldBackgroundPath); s_StandardResources.knob = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath); s_StandardResources.checkmark = AssetDatabase.GetBuiltinExtraResource<Sprite>(kCheckmarkPath); s_StandardResources.dropdown = AssetDatabase.GetBuiltinExtraResource<Sprite>(kDropdownArrowPath); s_StandardResources.mask = AssetDatabase.GetBuiltinExtraResource<Sprite>(kMaskPath); } return s_StandardResources; } private class DefaultEditorFactory : DefaultControls.IFactoryControls { public static DefaultEditorFactory Default = new DefaultEditorFactory(); public GameObject CreateGameObject(string name, params Type[] components) { return ObjectFactory.CreateGameObject(name, components); } } private class FactorySwapToEditor : IDisposable { DefaultControls.IFactoryControls factory; public FactorySwapToEditor() { factory = DefaultControls.factory; DefaultControls.factory = DefaultEditorFactory.Default; } public void Dispose() { DefaultControls.factory = factory; } } private static void SetPositionVisibleinSceneView(RectTransform canvasRTransform, RectTransform itemTransform) { SceneView sceneView = SceneView.lastActiveSceneView; // Couldn't find a SceneView. Don't set position. if (sceneView == null || sceneView.camera == null) return; // Create world space Plane from canvas position. Vector2 localPlanePosition; Camera camera = sceneView.camera; Vector3 position = Vector3.zero; if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRTransform, new Vector2(camera.pixelWidth / 2, camera.pixelHeight / 2), camera, out localPlanePosition)) { // Adjust for canvas pivot localPlanePosition.x = localPlanePosition.x + canvasRTransform.sizeDelta.x * canvasRTransform.pivot.x; localPlanePosition.y = localPlanePosition.y + canvasRTransform.sizeDelta.y * canvasRTransform.pivot.y; localPlanePosition.x = Mathf.Clamp(localPlanePosition.x, 0, canvasRTransform.sizeDelta.x); localPlanePosition.y = Mathf.Clamp(localPlanePosition.y, 0, canvasRTransform.sizeDelta.y); // Adjust for anchoring position.x = localPlanePosition.x - canvasRTransform.sizeDelta.x * itemTransform.anchorMin.x; position.y = localPlanePosition.y - canvasRTransform.sizeDelta.y * itemTransform.anchorMin.y; Vector3 minLocalPosition; minLocalPosition.x = canvasRTransform.sizeDelta.x * (0 - canvasRTransform.pivot.x) + itemTransform.sizeDelta.x * itemTransform.pivot.x; minLocalPosition.y = canvasRTransform.sizeDelta.y * (0 - canvasRTransform.pivot.y) + itemTransform.sizeDelta.y * itemTransform.pivot.y; Vector3 maxLocalPosition; maxLocalPosition.x = canvasRTransform.sizeDelta.x * (1 - canvasRTransform.pivot.x) - itemTransform.sizeDelta.x * itemTransform.pivot.x; maxLocalPosition.y = canvasRTransform.sizeDelta.y * (1 - canvasRTransform.pivot.y) - itemTransform.sizeDelta.y * itemTransform.pivot.y; position.x = Mathf.Clamp(position.x, minLocalPosition.x, maxLocalPosition.x); position.y = Mathf.Clamp(position.y, minLocalPosition.y, maxLocalPosition.y); } itemTransform.anchoredPosition = position; itemTransform.localRotation = Quaternion.identity; itemTransform.localScale = Vector3.one; } private static void PlaceUIElementRoot(GameObject element, MenuCommand menuCommand) { GameObject parent = menuCommand.context as GameObject; bool explicitParentChoice = true; if (parent == null) { parent = GetOrCreateCanvasGameObject(); explicitParentChoice = false; // If in Prefab Mode, Canvas has to be part of Prefab contents, // otherwise use Prefab root instead. PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); if (prefabStage != null && !prefabStage.IsPartOfPrefabContents(parent)) parent = prefabStage.prefabContentsRoot; } if (parent.GetComponentsInParent<Canvas>(true).Length == 0) { // Create canvas under context GameObject, // and make that be the parent which UI element is added under. GameObject canvas = MenuOptions.CreateNewUI(); Undo.SetTransformParent(canvas.transform, parent.transform, ""); parent = canvas; } GameObjectUtility.EnsureUniqueNameForSibling(element); SetParentAndAlign(element, parent); if (!explicitParentChoice) // not a context click, so center in sceneview SetPositionVisibleinSceneView(parent.GetComponent<RectTransform>(), element.GetComponent<RectTransform>()); // This call ensure any change made to created Objects after they where registered will be part of the Undo. Undo.RegisterFullObjectHierarchyUndo(parent == null ? element : parent, ""); // We have to fix up the undo name since the name of the object was only known after reparenting it. Undo.SetCurrentGroupName("Create " + element.name); Selection.activeGameObject = element; } private static void SetParentAndAlign(GameObject child, GameObject parent) { if (parent == null) return; Undo.SetTransformParent(child.transform, parent.transform, ""); RectTransform rectTransform = child.transform as RectTransform; if (rectTransform) { rectTransform.anchoredPosition = Vector2.zero; Vector3 localPosition = rectTransform.localPosition; localPosition.z = 0; rectTransform.localPosition = localPosition; } else { child.transform.localPosition = Vector3.zero; } child.transform.localRotation = Quaternion.identity; child.transform.localScale = Vector3.one; SetLayerRecursively(child, parent.layer); } private static void SetLayerRecursively(GameObject go, int layer) { go.layer = layer; Transform t = go.transform; for (int i = 0; i < t.childCount; i++) SetLayerRecursively(t.GetChild(i).gameObject, layer); } // Graphic elements [MenuItem("GameObject/UI/Text", false, 2000)] static public void AddText(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreateText(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); } [MenuItem("GameObject/UI/Image", false, 2001)] static public void AddImage(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreateImage(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); } [MenuItem("GameObject/UI/Raw Image", false, 2002)] static public void AddRawImage(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreateRawImage(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); } // Controls // Button and toggle are controls you just click on. [MenuItem("GameObject/UI/Button", false, 2030)] static public void AddButton(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreateButton(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); } [MenuItem("GameObject/UI/Toggle", false, 2031)] static public void AddToggle(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreateToggle(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); } // Slider and Scrollbar modify a number [MenuItem("GameObject/UI/Slider", false, 2033)] static public void AddSlider(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreateSlider(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); } [MenuItem("GameObject/UI/Scrollbar", false, 2034)] static public void AddScrollbar(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreateScrollbar(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); } // More advanced controls below [MenuItem("GameObject/UI/Dropdown", false, 2035)] static public void AddDropdown(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreateDropdown(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); } [MenuItem("GameObject/UI/Input Field", false, 2036)] public static void AddInputField(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreateInputField(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); } // Containers [MenuItem("GameObject/UI/Canvas", false, 2060)] static public void AddCanvas(MenuCommand menuCommand) { var go = CreateNewUI(); SetParentAndAlign(go, menuCommand.context as GameObject); if (go.transform.parent as RectTransform) { RectTransform rect = go.transform as RectTransform; rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.anchoredPosition = Vector2.zero; rect.sizeDelta = Vector2.zero; } Selection.activeGameObject = go; } [MenuItem("GameObject/UI/Panel", false, 2061)] static public void AddPanel(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreatePanel(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); // Panel is special, we need to ensure there's no padding after repositioning. RectTransform rect = go.GetComponent<RectTransform>(); rect.anchoredPosition = Vector2.zero; rect.sizeDelta = Vector2.zero; } [MenuItem("GameObject/UI/Scroll View", false, 2062)] static public void AddScrollView(MenuCommand menuCommand) { GameObject go; using (new FactorySwapToEditor()) go = DefaultControls.CreateScrollView(GetStandardResources()); PlaceUIElementRoot(go, menuCommand); } // Helper methods static public GameObject CreateNewUI() { // Root for the UI var root = ObjectFactory.CreateGameObject("Canvas", typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster)); root.layer = LayerMask.NameToLayer(kUILayerName); Canvas canvas = root.GetComponent<Canvas>(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; // Works for all stages. StageUtility.PlaceGameObjectInCurrentStage(root); bool customScene = false; PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); if (prefabStage != null) { Undo.SetTransformParent(root.transform, prefabStage.prefabContentsRoot.transform, ""); customScene = true; } Undo.SetCurrentGroupName("Create " + root.name); // If there is no event system add one... // No need to place event system in custom scene as these are temporary anyway. // It can be argued for or against placing it in the user scenes, // but let's not modify scene user is not currently looking at. if (!customScene) CreateEventSystem(false); return root; } [MenuItem("GameObject/UI/Event System", false, 2100)] public static void CreateEventSystem(MenuCommand menuCommand) { GameObject parent = menuCommand.context as GameObject; CreateEventSystem(true, parent); } private static void CreateEventSystem(bool select) { CreateEventSystem(select, null); } private static void CreateEventSystem(bool select, GameObject parent) { StageHandle stage = parent == null ? StageUtility.GetCurrentStageHandle() : StageUtility.GetStageHandle(parent); var esys = stage.FindComponentOfType<EventSystem>(); if (esys == null) { var eventSystem = ObjectFactory.CreateGameObject("EventSystem"); if (parent == null) StageUtility.PlaceGameObjectInCurrentStage(eventSystem); else SetParentAndAlign(eventSystem, parent); esys = ObjectFactory.AddComponent<EventSystem>(eventSystem); ObjectFactory.AddComponent<StandaloneInputModule>(eventSystem); Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name); } if (select && esys != null) { Selection.activeGameObject = esys.gameObject; } } // Helper function that returns a Canvas GameObject; preferably a parent of the selection, or other existing Canvas. static public GameObject GetOrCreateCanvasGameObject() { GameObject selectedGo = Selection.activeGameObject; // Try to find a gameobject that is the selected GO or one if its parents. Canvas canvas = (selectedGo != null) ? selectedGo.GetComponentInParent<Canvas>() : null; if (IsValidCanvas(canvas)) return canvas.gameObject; // No canvas in selection or its parents? Then use any valid canvas. // We have to find all loaded Canvases, not just the ones in main scenes. Canvas[] canvasArray = StageUtility.GetCurrentStageHandle().FindComponentsOfType<Canvas>(); for (int i = 0; i < canvasArray.Length; i++) if (IsValidCanvas(canvasArray[i])) return canvasArray[i].gameObject; // No canvas in the scene at all? Then create a new one. return MenuOptions.CreateNewUI(); } static bool IsValidCanvas(Canvas canvas) { if (canvas == null || !canvas.gameObject.activeInHierarchy) return false; // It's important that the non-editable canvas from a prefab scene won't be rejected, // but canvases not visible in the Hierarchy at all do. Don't check for HideAndDontSave. if (EditorUtility.IsPersistent(canvas) || (canvas.hideFlags & HideFlags.HideInHierarchy) != 0) return false; return StageUtility.GetStageHandle(canvas.gameObject) == StageUtility.GetCurrentStageHandle(); } } }
Editor-EventSystem-EventTriggerEditors.cs
using System; using UnityEngine; using UnityEngine.EventSystems; namespace UnityEditor.EventSystems { [CustomEditor(typeof(EventTrigger), true)] public class EventTriggerEditor : Editor { SerializedProperty m_DelegatesProperty; GUIContent m_IconToolbarMinus; GUIContent m_EventIDName; GUIContent[] m_EventTypes; GUIContent m_AddButonContent; protected virtual void OnEnable() { m_DelegatesProperty = serializedObject.FindProperty("m_Delegates"); m_AddButonContent = EditorGUIUtility.TrTextContent("Add New Event Type"); m_EventIDName = new GUIContent(""); // Have to create a copy since otherwise the tooltip will be overwritten. m_IconToolbarMinus = new GUIContent(EditorGUIUtility.IconContent("Toolbar Minus")); m_IconToolbarMinus.tooltip = "Remove all events in this list."; string[] eventNames = Enum.GetNames(typeof(EventTriggerType)); m_EventTypes = new GUIContent[eventNames.Length]; for (int i = 0; i < eventNames.Length; ++i) { m_EventTypes[i] = new GUIContent(eventNames[i]); } } public override void OnInspectorGUI() { serializedObject.Update(); int toBeRemovedEntry = -1; EditorGUILayout.Space(); Vector2 removeButtonSize = GUIStyle.none.CalcSize(m_IconToolbarMinus); for (int i = 0; i < m_DelegatesProperty.arraySize; ++i) { SerializedProperty delegateProperty = m_DelegatesProperty.GetArrayElementAtIndex(i); SerializedProperty eventProperty = delegateProperty.FindPropertyRelative("eventID"); SerializedProperty callbacksProperty = delegateProperty.FindPropertyRelative("callback"); m_EventIDName.text = eventProperty.enumDisplayNames[eventProperty.enumValueIndex]; EditorGUILayout.PropertyField(callbacksProperty, m_EventIDName); Rect callbackRect = GUILayoutUtility.GetLastRect(); Rect removeButtonPos = new Rect(callbackRect.xMax - removeButtonSize.x - 8, callbackRect.y + 1, removeButtonSize.x, removeButtonSize.y); if (GUI.Button(removeButtonPos, m_IconToolbarMinus, GUIStyle.none)) { toBeRemovedEntry = i; } EditorGUILayout.Space(); } if (toBeRemovedEntry > -1) { RemoveEntry(toBeRemovedEntry); } Rect btPosition = GUILayoutUtility.GetRect(m_AddButonContent, GUI.skin.button); const float addButonWidth = 200f; btPosition.x = btPosition.x + (btPosition.width - addButonWidth) / 2; btPosition.width = addButonWidth; if (GUI.Button(btPosition, m_AddButonContent)) { ShowAddTriggermenu(); } serializedObject.ApplyModifiedProperties(); } private void RemoveEntry(int toBeRemovedEntry) { m_DelegatesProperty.DeleteArrayElementAtIndex(toBeRemovedEntry); } void ShowAddTriggermenu() { // Now create the menu, add items and show it GenericMenu menu = new GenericMenu(); for (int i = 0; i < m_EventTypes.Length; ++i) { bool active = true; // Check if we already have a Entry for the current eventType, if so, disable it for (int p = 0; p < m_DelegatesProperty.arraySize; ++p) { SerializedProperty delegateEntry = m_DelegatesProperty.GetArrayElementAtIndex(p); SerializedProperty eventProperty = delegateEntry.FindPropertyRelative("eventID"); if (eventProperty.enumValueIndex == i) { active = false; } } if (active) menu.AddItem(m_EventTypes[i], false, OnAddNewSelected, i); else menu.AddDisabledItem(m_EventTypes[i]); } menu.ShowAsContext(); Event.current.Use(); } private void OnAddNewSelected(object index) { int selected = (int)index; m_DelegatesProperty.arraySize += 1; SerializedProperty delegateEntry = m_DelegatesProperty.GetArrayElementAtIndex(m_DelegatesProperty.arraySize - 1); SerializedProperty eventProperty = delegateEntry.FindPropertyRelative("eventID"); eventProperty.enumValueIndex = selected; serializedObject.ApplyModifiedProperties(); } } }
Runtime-UIElements-ExecuteEvents.cs
using System; using System.Collections.Generic; using UnityEngine.Pool; namespace UnityEngine.EventSystems { public static class ExecuteEvents { public delegate void EventFunction<T1>(T1 handler, BaseEventData eventData); public static T ValidateEventData<T>(BaseEventData data) where T : class { if ((data as T) == null) throw new ArgumentException(String.Format("Invalid type: {0} passed to event expecting {1}", data.GetType(), typeof(T))); return data as T; } private static readonly EventFunction<IPointerMoveHandler> s_PointerMoveHandler = Execute; private static void Execute(IPointerMoveHandler handler, BaseEventData eventData) { handler.OnPointerMove(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IPointerEnterHandler> s_PointerEnterHandler = Execute; private static void Execute(IPointerEnterHandler handler, BaseEventData eventData) { handler.OnPointerEnter(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IPointerExitHandler> s_PointerExitHandler = Execute; private static void Execute(IPointerExitHandler handler, BaseEventData eventData) { handler.OnPointerExit(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IPointerDownHandler> s_PointerDownHandler = Execute; private static void Execute(IPointerDownHandler handler, BaseEventData eventData) { handler.OnPointerDown(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IPointerUpHandler> s_PointerUpHandler = Execute; private static void Execute(IPointerUpHandler handler, BaseEventData eventData) { handler.OnPointerUp(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IPointerClickHandler> s_PointerClickHandler = Execute; private static void Execute(IPointerClickHandler handler, BaseEventData eventData) { handler.OnPointerClick(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IInitializePotentialDragHandler> s_InitializePotentialDragHandler = Execute; private static void Execute(IInitializePotentialDragHandler handler, BaseEventData eventData) { handler.OnInitializePotentialDrag(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IBeginDragHandler> s_BeginDragHandler = Execute; private static void Execute(IBeginDragHandler handler, BaseEventData eventData) { handler.OnBeginDrag(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IDragHandler> s_DragHandler = Execute; private static void Execute(IDragHandler handler, BaseEventData eventData) { handler.OnDrag(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IEndDragHandler> s_EndDragHandler = Execute; private static void Execute(IEndDragHandler handler, BaseEventData eventData) { handler.OnEndDrag(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IDropHandler> s_DropHandler = Execute; private static void Execute(IDropHandler handler, BaseEventData eventData) { handler.OnDrop(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IScrollHandler> s_ScrollHandler = Execute; private static void Execute(IScrollHandler handler, BaseEventData eventData) { handler.OnScroll(ValidateEventData<PointerEventData>(eventData)); } private static readonly EventFunction<IUpdateSelectedHandler> s_UpdateSelectedHandler = Execute; private static void Execute(IUpdateSelectedHandler handler, BaseEventData eventData) { handler.OnUpdateSelected(eventData); } private static readonly EventFunction<ISelectHandler> s_SelectHandler = Execute; private static void Execute(ISelectHandler handler, BaseEventData eventData) { handler.OnSelect(eventData); } private static readonly EventFunction<IDeselectHandler> s_DeselectHandler = Execute; private static void Execute(IDeselectHandler handler, BaseEventData eventData) { handler.OnDeselect(eventData); } private static readonly EventFunction<IMoveHandler> s_MoveHandler = Execute; private static void Execute(IMoveHandler handler, BaseEventData eventData) { handler.OnMove(ValidateEventData<AxisEventData>(eventData)); } private static readonly EventFunction<ISubmitHandler> s_SubmitHandler = Execute; private static void Execute(ISubmitHandler handler, BaseEventData eventData) { handler.OnSubmit(eventData); } private static readonly EventFunction<ICancelHandler> s_CancelHandler = Execute; private static void Execute(ICancelHandler handler, BaseEventData eventData) { handler.OnCancel(eventData); } public static EventFunction<IPointerMoveHandler> pointerMoveHandler { get { return s_PointerMoveHandler; } } public static EventFunction<IPointerEnterHandler> pointerEnterHandler { get { return s_PointerEnterHandler; } } public static EventFunction<IPointerExitHandler> pointerExitHandler { get { return s_PointerExitHandler; } } public static EventFunction<IPointerDownHandler> pointerDownHandler { get { return s_PointerDownHandler; } } public static EventFunction<IPointerUpHandler> pointerUpHandler { get { return s_PointerUpHandler; } } public static EventFunction<IPointerClickHandler> pointerClickHandler { get { return s_PointerClickHandler; } } public static EventFunction<IInitializePotentialDragHandler> initializePotentialDrag { get { return s_InitializePotentialDragHandler; } } public static EventFunction<IBeginDragHandler> beginDragHandler { get { return s_BeginDragHandler; } } public static EventFunction<IDragHandler> dragHandler { get { return s_DragHandler; } } public static EventFunction<IEndDragHandler> endDragHandler { get { return s_EndDragHandler; } } public static EventFunction<IDropHandler> dropHandler { get { return s_DropHandler; } } public static EventFunction<IScrollHandler> scrollHandler { get { return s_ScrollHandler; } } public static EventFunction<IUpdateSelectedHandler> updateSelectedHandler { get { return s_UpdateSelectedHandler; } } public static EventFunction<ISelectHandler> selectHandler { get { return s_SelectHandler; } } public static EventFunction<IDeselectHandler> deselectHandler { get { return s_DeselectHandler; } } public static EventFunction<IMoveHandler> moveHandler { get { return s_MoveHandler; } } public static EventFunction<ISubmitHandler> submitHandler { get { return s_SubmitHandler; } } public static EventFunction<ICancelHandler> cancelHandler { get { return s_CancelHandler; } } private static void GetEventChain(GameObject root, IList<Transform> eventChain) { eventChain.Clear(); if (root == null) return; var t = root.transform; while (t != null) { eventChain.Add(t); t = t.parent; } } public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler { var internalHandlers = ListPool<IEventSystemHandler>.Get(); GetEventList<T>(target, internalHandlers); // if (s_InternalHandlers.Count > 0) // Debug.Log("Executinng " + typeof (T) + " on " + target); var internalHandlersCount = internalHandlers.Count; for (var i = 0; i < internalHandlersCount; i++) { T arg; try { arg = (T)internalHandlers[i]; } catch (Exception e) { var temp = internalHandlers[i]; Debug.LogException(new Exception(string.Format("Type {0} expected {1} received.", typeof(T).Name, temp.GetType().Name), e)); continue; } try { functor(arg, eventData); } catch (Exception e) { Debug.LogException(e); } } var handlerCount = internalHandlers.Count; ListPool<IEventSystemHandler>.Release(internalHandlers); return handlerCount > 0; } /// <summary> /// Execute the specified event on the first game object underneath the current touch. /// </summary> private static readonly List<Transform> s_InternalTransformList = new List<Transform>(30); public static GameObject ExecuteHierarchy<T>(GameObject root, BaseEventData eventData, EventFunction<T> callbackFunction) where T : IEventSystemHandler { GetEventChain(root, s_InternalTransformList); var internalTransformListCount = s_InternalTransformList.Count; for (var i = 0; i < internalTransformListCount; i++) { var transform = s_InternalTransformList[i]; if (Execute(transform.gameObject, eventData, callbackFunction)) return transform.gameObject; } return null; } private static bool ShouldSendToComponent<T>(Component component) where T : IEventSystemHandler { var valid = component is T; if (!valid) return false; var behaviour = component as Behaviour; if (behaviour != null) return behaviour.isActiveAndEnabled; return true; } /// <summary> /// Get the specified object's event event. /// </summary> private static void GetEventList<T>(GameObject go, IList<IEventSystemHandler> results) where T : IEventSystemHandler { // Debug.LogWarning("GetEventList<" + typeof(T).Name + ">"); if (results == null) throw new ArgumentException("Results array is null", "results"); if (go == null || !go.activeInHierarchy) return; var components = ListPool<Component>.Get(); go.GetComponents(components); var componentsCount = components.Count; for (var i = 0; i < componentsCount; i++) { if (!ShouldSendToComponent<T>(components[i])) continue; // Debug.Log(string.Format("{2} found! On {0}.{1}", go, s_GetComponentsScratch[i].GetType(), typeof(T))); results.Add(components[i] as IEventSystemHandler); } ListPool<Component>.Release(components); // Debug.LogWarning("end GetEventList<" + typeof(T).Name + ">"); } /// <summary> /// Whether the specified game object will be able to handle the specified event. /// </summary> public static bool CanHandleEvent<T>(GameObject go) where T : IEventSystemHandler { var internalHandlers = ListPool<IEventSystemHandler>.Get(); GetEventList<T>(go, internalHandlers); var handlerCount = internalHandlers.Count; ListPool<IEventSystemHandler>.Release(internalHandlers); return handlerCount != 0; } /// <summary> /// Bubble the specified event on the game object, figuring out which object will actually receive the event. /// </summary> public static GameObject GetEventHandler<T>(GameObject root) where T : IEventSystemHandler { if (root == null) return null; Transform t = root.transform; while (t != null) { if (CanHandleEvent<T>(t.gameObject)) return t.gameObject; t = t.parent; } return null; } } }
以上就是Unity3D實現甜品消消樂遊戲的詳細內容,更多關於Unity3D消消樂遊戲的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Unity UI實現拖拽旋轉
- unity實現方向盤轉動效果
- 關於Unity中RectTransform與transform的區別
- Unity2D實現遊戲回旋鏢
- Unity3D實現經典小遊戲Pacman