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消消乐游戏的资料请关注我们其它相关文章!

(0)

相关推荐

  • Unity3d实现Flappy Bird游戏

    本文实例为大家分享了Unity3d实现Flappy Bird的具体代码,供大家参考,具体内容如下 一.小鸟 在游戏中,小鸟并不做水平位移,而是通过障碍物的移动让小鸟有水平运动的感觉,小鸟只需要对鼠标的点击调整竖直加速度就可以了,同时加上水平旋转模仿原版的FlappyBird的运动.同时,还要对竖直位置进行判断,否则游戏不能正常结束. 这里贴上小鸟上附加的脚本代码 Player.cs using UnityEngine; using System.Collections; public class

  • Unity3D实现飞机大战游戏(1)

    本文为大家分享了Unity3D飞机大战游戏第一部分的实现代码,供大家参考,具体内容如下 实现背景轮播 1.首先找两个背景图片,让两张图片竖直摆放且没有间隔 2.两个图片的下降的播放速度应当同步 public float moveSpeed = 3f;//指的是在unity里的移动速度 // Update is called once per frame void Update() { this.transform.Translate(Vector3.down * moveSpeed *Time.

  • Unity3D开发实战之五子棋游戏

    前言 经过前面<Unity3D入门教程>系列讲解,再加上我们自己的探索,相信大家已经掌握了Unity3D的相关知识和基本方法.本文将使用前面学到的知识,开发一款简单的五子棋程序.本文用到的东西其实不多,非常简单.在最后我们会把完整工程的源代码发布出来,以供初学者参考.先展示一下最后的运行效果吧. 1 准备工作 (1)开发环境:Win10 + Unity5.4.1 (2)图片素材准备: 黑棋子和白棋子 棋盘 获胜提示图片 2 开发流程 上文提到的素材可以直接下载我们给出的这些图,也可以自己制作.

  • Unity3D游戏开发数据持久化PlayerPrefs的用法详解

    小编今天研究了在Unity3D中的数据持久化问题.数据持久化在任何一个开发领域都是一个值得关注的问题,小到一个应用中配置文件的读写,大到数据库的管理维护,都可以看到数据持久化的身影.小编在<C#基于Linq和反射实现数据持久化框架Xml4DB>这篇文章中曾介绍了博主在寒假期间开发的Xml4DB框架,这是一个基于Xml的轻量级数据持久化框架,可以采用面向对象的方式来处理数据.数据持久化从某种意义上来说,就是序列化和反序列化化的过程.在.NET中我们可以将对象序列化为Xml.Json.二进制.然后

  • Unity3D实现飞机大战游戏(2)

    本文为大家分享了Unity3D飞机大战游戏第一部分的实现代码,供大家参考,具体内容如下 让飞机可以发射子弹 准备工作: 1.将子弹设置成预制体 2.在飞机下新建一个子物体Gun 3.调整好位置以后,将子弹设置成预制体 //发射子弹的速率 public float rate = 0.2f; public GameObject bullet;//子弹的类型 //发射子弹的方法 public void fire() { //初始化一个子弹预制体 GameObject.Instantiate(bulle

  • Unity3D实现经典小游戏Pacman

    目录 项目概况 整体布局 地图介绍 玩法介绍 相关知识 版本说明 项目源码 项目概况 整体布局 地图介绍 除了音效,游戏地图上的元素有: 普通糖豆(玩家通过移动,经过的普通糖豆会被吃掉,获得积分)  特殊糖豆(玩家吃到后,可以让所有敌方停止移动,产生幻影效果) 隔离墙(相当于迷宫的墙,在两堵墙之间的间隙才能移动)  剩余游戏时间Remain(共设300s,时间一到,游戏结束) 截止到现在花费的游戏时间Now(设在0~300之间) 截止到目前为止的游戏得分Score(越高越好) 敌方人机(分为四种

  • Unity3D实现甜品消消乐游戏

    目录 前言 项目效果展示 项目概况 素材展示 场景展示 场景元素 玩法介绍 版本说明 项目源码 前言 解释: 之前用的ScreenToGif录屏,因为上传的.gif最大不超过5MB,所以做了不少删帧和色彩弱化等处理,这才导致色彩看上去不是很舒服,不要盯着它看太久,不然会有点难受... 由于使用的素材是现成的,没有花时间精力去扒,所以细节方面可能不是做的很好. 说明: 这次的甜品消消乐虽然看上去好像挺简单普通的,但是相对于之前的坦克大战,某种程度上已然提升难度了,归类到了算法类层的游戏. 拉到最后

  • Vue实现开心消消乐游戏算法

    之前做过一个算法题,算法要求就是写一个开心消消乐的逻辑算法,当时也是考虑了一段时间才做出来.后来想了想,既然核心算法都有了,能不能实现一个开心消消乐的小游戏呢,于是花了两天时间做了一个小游戏出来. 效果展示# 先在这里放一个最终实现的效果,还是一个比较初级的版本,大家有什么想法欢迎评论哦 游戏规则: 初始时会给玩家十分的初始分,每拖动一次就减一分,每消除一个方块就加一分,直到最后分数为0游戏结束 任意两个方块都可以拖动 界面设计# 页面的布局比较简单,格子的数据是一个二维数组的形式,说到这里大家

  • C/C++百行代码实现热门游戏消消乐功能的示例代码

    游戏设计 首先我们需要使用第三方框架,这里我使用的是sfml,不会使用sfml在我的上几篇文章当中-扫雷(上)有详细的开发环境搭建介绍 首先准备图片资源 一张背景图片,一张宝石图片 窗口初始化加载图片 Texture t1; t1.loadFromFile("images/bg2.png"); 当鼠标第一次单击时,记录下位置,第二次单击又记录一下位置,如果两个小方块相邻就交换位置,如果不相邻如图c的位置则,不发生变化 判断行或列如果三张一样的图片相邻,清除一下图片,进行刷新 实列 #i

  • C语言实现消消乐小游戏

    本文实例为大家分享了C语言实现消消乐小游戏的具体代码,供大家参考,具体内容如下 代码: #include<iostream> #include<cstdlib> #include<bitset> #include<conio.h> #include<time.h> #include <windows.h> #include<queue> #include<algorithm> using namespace s

  • C语言实现消消乐游戏

    本文实例为大家分享了C语言实现消消乐游戏的具体代码,供大家参考,具体内容如下 问题描述 给定一个矩阵, 判断移动哪一个格子,可以实现消除.(定义连续三个即可消除) 据说是华为的笔试题. 分析 先写一个函数,判断包含(i, j)的格子是否可能实现消除. 然后就是向右向下交换,然后调用上面写好的函数判断 被交换的两个格子是否实现消除. 重点是: 1.只需要向右向下交换,因为遍历的时候,后面的交换会重复.前一个判断了向右交换是否消除,后一个遍历就不需要再判断向左交换是否重复了. 2.一定要对被交换的两

  • 使用python+pygame开发消消乐游戏附完整源码

    效果是这样的 ↓ ↓ ↓ 一.环境要求 windows系统,python3.6+ pip21+ 开发环境搭建地址 一起来学pygame吧 游戏开发30例(开篇词)--环境搭建+游戏效果展示 安装游戏依赖模块 pip install pygame 二.游戏简介 消消乐应该大家都玩过,或者看过.这个花里胡哨的小游戏 用python的pygame来实现,很简单. 今天带大家,用Python来实现一下这个花里胡哨的小游戏. 三.完整开发流程 1.项目主结构 首先,先整理一下项目的主结构,其实看一下主结构

  • Python实现消消乐小游戏

    本文实例为大家分享了Python实现消消乐小游戏的具体代码,供大家参考,具体内容如下 玩法:三个相连就能消除 源码分享: import os import sys import cfg import pygame from modules import * '''游戏主程序''' def main(): pygame.init() screen = pygame.display.set_mode(cfg.SCREENSIZE) pygame.display.set_caption('Gemgem

  • 基于Python编写一个宝石消消乐小游戏

    目录 开发工具 环境搭建 原理简介 开发工具 python版本:3.6.4 相关模块: pygame:以及一些python自带的模块. 环境搭建 安装python并添加到环境变量,pip安装需要的相关模块即可. 原理简介 游戏规则: 玩家通过鼠标交换相邻的拼图,若交换后水平/竖直方向存在连续三个相同的拼图,则这些拼图消失,玩家得分,同时生成新的拼图以补充消失的部分,否则,交换失败,玩家不得分.玩家需要在规定时间内获取尽可能高的得分. 实现过程: 首先加载一些必要的游戏素材: 加载背景音乐: py

  • C++实现消消乐游戏

    本文实例为大家分享了C++实现消消乐游戏的具体代码,供大家参考,具体内容如下 问题描述 给定一个矩阵, 判断移动哪一个格子,可以实现消除.(定义连续三个即可消除) 据说是华为的笔试题. 分析 先写一个函数,判断包含(i, j)的格子是否可能实现消除. 然后就是向右向下交换,然后调用上面写好的函数判断被交换的两个格子是否实现消除. 重点是: 1.只需要向右向下交换,因为遍历的时候,后面的交换会重复.前一个判断了向右交换是否消除,后一个遍历就不需要再判断向左交换是否重复了.2.一定要对被交换的两个格

  • 基于Python实现开心消消乐小游戏的示例代码

    目录 前言 一.准备 1.1 图片素材 1.2 音频素材 二.代码 2.1 导入模块 2.2 游戏音乐设置 2.3 制作树类 2.4 制作鼠标点击效果 2.5 制作出现元素 2.6 数组 2.7 制作人物画板 三.效果展示(仅部分) 3.1 初始页面 3.2 第一关画面 3.3 失败画面 3.4 第十关画面 穿过云朵升一级是要花6个金币的,有的时候金币真的很重要 前言 嗨喽,大家好呀!这里是魔王~ 一天晚上,天空中掉下一颗神奇的豌豆种子,正好落在了梦之森林的村长屋附近. 种子落地后吸收了池塘的水

随机推荐