zoukankan      html  css  js  c++  java
  • Unity 游戏框架搭建 2019 (四十二、四十三) MonoBehaviour 简化 & 定时功能

    MonoBehaviour 简化

    在前两篇,我们完成了第九个示例。为了完善第九个示例,我们复习了类的继承,又学习了泛型和 params 关键字。

    我们已经接触了类的继承了。接触继承之前,把类仅仅当做是方法的集合,接触了继承之后,我们的类还可以使用继承来解决一些问题。

    第十个示例

    在 Unity 中,我们的脚本都往往继承自 MonoBehaviour,继承了之后我们就可以在脚本内编写很多功能。比如访问 transform/gameObject,再比如控制动画接收碰撞事件等等。另外我们继承了 MonoBehaviour 才能被作为脚本挂到 GameObject 上。

    仅仅是通过继承,MonoBehaviour 的很多功能都能够进行复用。所以继承的一个作用就是代码复用。而我们知道方法也可以代码复用,泛型可以对结构进行复用。那么继承能是复用什么?

    继承既能复用代码也能复用结构。不过术业有专攻,有的情况下使用方法进行复用更合理,有的情况下适用于泛型,当然也有适用继承的情况。

    像 GameObjectSimplify 和 TransformSimplify,这两种方法集,目前其实通过继承来实现会更好一点。因为这两个类中的方法全部都是要传一个固定的对象进去的,比如 GameObjectSimiplify 的每个方法第一个参数都是 GameObject 参数,而 TransformSimplify 也是如此。他们使用起来也不是很方便。

    使用代码如下:

    GameObjectSimplify.Show(gameObject);
    TriansformSimplify.Identity(transform);
    

    可以看出都需要把所有的类名字全部打出来,而使用继承就会好很多。

    我们先实现第十个示例代码,如下

    MonoBehaviourSimplify.cs

    using UnityEngine;
    
    namespace QFramework
    {    
        public partial class MonoBehaviourSimplify : MonoBehaviour
        {
            public void Show()
            {
                GameObjectSimplify.Show(gameObject);
            }
    
            public void Hide()
            {
                GameObjectSimplify.Hide(gameObject);
            }
    
            public void Identity()
            {
                TransformSimplify.Identity(transform);
            }
        }
        
        public class Hide : MonoBehaviourSimplify
        {        
            private void Awake()
            {
                Hide();
            }
            
    #if UNITY_EDITOR
            [UnityEditor.MenuItem("QFramework/10.MonoBehaviour 简化", false, 11)]
            static void MenuClicked()
            {
                UnityEditor.EditorApplication.isPlaying = true;
                
                var gameObj = new GameObject("Hide");
                gameObj.AddComponent<Hide>();
            }
    #endif
        }
    }
    

    MonoBehaviourSimplify 为了可以在之后的示例中进行扩展,所以加上了 partial 关键字。而其中的 Show、Hide 等方法这次没有使用 static 关键字,那么这种方法叫做成员方法。成员方法必须通过对象来调用。而有 static 关键字的叫做静态方法,静态方法必须通过类来调用。

    示例就是代码中的 Hide 脚本。

    而 MenuItem 中有一行代码:

    UnityEditor.EditorApplication.isPlaying = true;
    

    这行代码执行之后,UnityEditor 就会自动运行。

    其他的都很简单,MenuItem 执行之后如下所示:
    006tNc79gy1fzfsg3oncxj30ls0b475d.jpg

    示例是正确的。

    OK,这个示例就完成了。

    菜单如下:
    006tNc79gy1fzfsg7lffdj30hk0dqwle.jpg

    目录结构如下:
    006tNc79gy1fzfsgddemfj30eo0b675s.jpg

    今天的内容就这些,我们接触了继承之后,又强化了一次继承的使用,这样我们之后每次写示例的时候会有很多设计工具选择。

    定时功能

    在上一篇我们完成了 MonoBehaviour 的简化示例,通过做这个示例,强化了一次继承的使用。
    而为了让示例脚本自动运行,就接触了 EditorApplication.isPlaying 这个 API,有了这个 API 我们之后所有需要运行 UnityEditor 的脚本都可以按照这种格式去做。

    今天我们再接着往下学习。

    第十一个示例

    我们都知道,在项目中,我们会遇到非常多的定时需求。而定时功能在 Unity 中最容易实现的方式是通过 Coroutine(协程)实现。在这个示例中我们实现一个简单的定时工具。

    在实现在哪里呢?

    我们目前有两个选择:

    • 一是写一个工具类,比如 TimerUtil 或者 DelayUtil,或者干脆卸载 CommonUtil 里。
    • 二是实现到 MonoBehaviourSimplify 里。

    考虑到,执行协程是需要通过 MonoBehaviour 启动的,所以方法在 MonoBehaviourSimplify 中定义更好一点。而实现的部分需要定义一个协程方法。这个协程方法并不希望被子类或者外部类调用,所以这个协程方法应该使用 private 权限。

    实现之后的示例代码如下:

    using System;
    using System.Collections;
    using UnityEngine;
    
    namespace QFramework
    {
        public partial class MonoBehaviourSimplify
        {
            public void Delay(float seconds, Action onFinished)
            {
                StartCoroutine(DelayCoroutine(seconds, onFinished));
            }
            
            private static IEnumerator DelayCoroutine(float seconds, Action onFinished)
            {
                yield return new WaitForSeconds(seconds);
    
                onFinished();
            }
        }
    
        public class DelayWithCoroutine : MonoBehaviourSimplify
        {
            private void Start()
            {
                Delay(5.0f, () =>
                {
                    UnityEditor.EditorApplication.isPlaying = false;
                });
            }
    
    #if UNITY_EDITOR
            [UnityEditor.MenuItem("QFramework/11.定时功能", false, 11)]
            private static void MenuClickd()
            {
                UnityEditor.EditorApplication.isPlaying = true;
    
                new GameObject("DelayWithCoroutine")
                    .AddComponent<DelayWithCoroutine>();
            }
    #endif
        }
    }
    

    以上代码中,大家可能对 Action 比较陌生。Action 其实是 C# 自定义的委托。
    定义如下:

    namespace System
    {
    	public delegate void Action();
    }
    

    至于委托是什么…,理解成动态方法就好了,在初期呢,我们用它来做回调函数。

    还有这样的一个写法也可能比较陌生: () => { } ,这种写法叫做 lambda 表达式,相当于实现了一个没有名字的方法。详细的使用方法可以自己用搜索引擎查一下,这里笔者只要能看懂以上代码就行。当然在以后的文章中会非常深入地讲 委托、lambda 表达式在库/框架中的使用的。

    示例代码执行之后,如下:
    DraggedImage.aba351c681524dfab0a1f5b8f01ff01f.png
    过了五秒后,UnityEditor 运行会自动停止。
    如下:

    DraggedImage.dcb427502b394946810177e994b3f3ae.png

    结果是正确的。

    这篇文章的示例就写完了。

    菜单栏如下:
    006tNc79gy1fzfsh7n2yrj308r07ujtj.jpg

    文件目录如下:
    006tNc79gy1fzfshacdguj30f60bytab.jpg

    我们可以进行一次导出了。

    我们一篇文章再见,拜拜~

    转载请注明地址:凉鞋的笔记:liangxiegame.com

    更多内容

  • 相关阅读:
    拥抱webpack4,有效缩减构建时间57%+
    可能是最详细的UMD模块入门指南
    Chrome远程调试手机端UC浏览器
    sea.js的同步魔法
    在Linux和Windows系统中输出目录结构
    从部署上做到前后端分离
    一种在地图中处理曲线的通用方法
    vue项目中引入iconfont
    前端路上的自我怀疑----------自我突破
    表格布局----基于bootstrap样式 布局
  • 原文地址:https://www.cnblogs.com/liangxiegame/p/12825475.html
Copyright © 2011-2022 走看看