Unity 游戏框架搭建 2019 (九~十二) 第一章小结&第二章简介&第八个示例

第一章小结

为了强化教程的重点,会在合适的时候进行总结与快速复习。

第二章 简介

在第一章我们做了知识库的准备,从而让我们更高效地收集示例。

在第二章,我们就用准备好的导出工具试着收集几个示例,这些示例中有的是我们后续库的基础工具,也有的是在项目中非常实用的小工具,还有一些示例是实践了在框架搭建方向上非常重要的 C# 语法知识。

第二章大纲如下。

第八个示例(一)

在之前,我们完成了一个导出的功能。但是在完成这个功能的过程中,我们也遇到了一些问题。我们回忆一下,在《MenuItem 复用》的这篇文章中,我们想对如下代码进行复用。

using System;
#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;

namespace QFramework
{
	public class ExportUnityPackage : MonoBehaviour
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/4.导出 UnityPackage")]
		private static void MenuClicked()
		{
			var assetPathName = "Assets/QFramework";
			var fileName = "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh") + ".unitypackage";
			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);
		}
#endif
	}
}

这个方法被声明为 private 权限,所以是不可以被访问的。不过还好,MenuItem 可以复用,问题就勉强解决了。但是每次复用的时候要手打或复制一遍字符串未免也太麻烦了,而且也容易出错。那么还有其他的方式么?

这就是今天要解决的问题。当别的示例想调用以上的方法的时候,由于是 private 类型,所以只能通过 MenuItem 的方式进行调用,而 MenuItem 这种方式比较麻烦。

解决方案大家很容易就想到,把 private 改成 public 就行了。这样从达成代码复用这个目的的这个角度来说,问题是算是解决了,但是以笔者的经验来讲,这样还会有一些问题,就到这样就好。我们好好享受这个胜利的果实。

到这里如果有不知道 private 和 public 关键字的作用是什么的童鞋,那么笔者就简单提一句,使用 private 定义的方法只能在类的内部或者内部类中被调用,则不可以被子类和外部类调用,而使用 public 定义的方法,如果所在类也是 public 类型的,那么在任意地方可以被调用。

我们要怎么用这个 public 关键字呢?是在写示例的时候,仅仅把 private 改成 public 就行了嘛?有没有更好用的方法?

如果仅仅是把 private 改成 public 不是最好的方法,因为通过 MenuItem 修饰的方法,不能传参数,也没有返回值。不能传参或不能返回值的话,一个方法的使用就会受限。

所以笔者给出的方案是,再创建一个静态的 public 方法,而这个方法被 MenuItem 调用。这样的好处是,我们在创建一个方法的时候,可以好好地利用参数和返回值进行设计。

说了这么多,终于得到了一个明确的方案。我们来通过今天的第八个示例快速试一下。

第八个示例

第八个示例是什么呢,就是在第八个示例中,把所有的示例都提取成方法,并再次完成导出的功能。

首先第一个示例代码如下:

#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;
using System;

namespace QFramework
{
	public static class LogFileName
	{
		#if UNITY_EDITOR
		[MenuItem("QFramework/1.生成 unitypackage 名字")]
		#endif
		private static void GenerateUnityPackageName()
		{
			Debug.Log("QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh"));
		}
	}
}

这个示例的核心是 DateTime.Now.ToString() 这个代码。之所以是核心,是因为没用过它的人,第一次用会感觉很陌生,而且 Unity 和 C# 的 API 有那么多,怎么可能一个一个全部记住呢?所以就写了这样的一个示例,以便日后,要用的时候迅速翻阅这个代码就可以知道怎么用。随着时间,这个 API 用的次数会越来越多,慢慢自己就记住了。但是就算记住了,也有可能会忘的那一天,所以还有得让它在我们的库中存在。

OK,我们直接看提取后的代码。

#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;
using System;

namespace QFramework
{
	public class PreviousFunctions : MonoBehaviour
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/1.获取文件名")]
#endif
		private static void MenuClicked()
		{
			Debug.Log(GenerateUnityPackageName());
		}

		public static string GenerateUnityPackageName()
		{
			return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh");
		}
	}
}

首先注意,MenuItem,由于第八个示例是有很多的东西,所以就又加了一级菜单。

点击以上菜单,执行结果正确。

第八个示例(二)

在上一篇我们抽取了第一个示例的方法,我们在这篇在接着往下抽取。

提取第二个示例

先看第二个示例的代码。

#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;

namespace QFramework
{
	public static class CopyText2Clipboard
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/2.复制文本到剪切板")]
#endif
		private static void CopyText()
		{
			GUIUtility.systemCopyBuffer = "要复制的关键字";
		}
	}
}

核心 API 是 GUIUtility.systemCopyBuffer,而后边的内容,应该是使用的时候自己填的。所以要创建一个 string 类型的参数,用来接收要复制的内容。抽取后的方法如下。

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/2.复制文本到剪切板")]
#endif
		private static void MenuClicked2()
		{
			CopyText("要复制的关键字");
		}

		public static void CopyText(string text)
		{
			GUIUtility.systemCopyBuffer = text;
		}

提取第三示例

我们接着看第三个示例

using System;
#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;

namespace QFramework
{
	public class GenerateUnityPackageName2ClipBoard
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/3.生成文件名到剪切板")]
#endif
		private static void MenuClicked()
		{
			GUIUtility.systemCopyBuffer = "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh");
		}
	}
}

第三个示例和第一个和第二个示例重复了所以没有抽取的必要。不过,我们还是要实现与第三个 MenuItem 同等的功能的。

代码如下:

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/3.生成文件名到剪切板")]
#endif
		private static void MenuClicked3()
		{
			CopyText(GenerateUnityPackageName());
		}

提取第四示例

第四个示例代码如下:

using System;
#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;

namespace QFramework
{
	public class ExportUnityPackage : MonoBehaviour
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/4.导出 UnityPackage")]
		private static void MenuClicked()
		{
			var assetPathName = "Assets/QFramework";
			var fileName = "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh") + ".unitypackage";
			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);
		}
#endif
	}
}

核心是 AssetDatabase.ExportPackage 这个 API。一般情况下 ExportPackageOptions 都是用 Recurse。所以只声明两个参数就好了。一个是 assetPathNam,一个是 fileName。抽取后的方法如下。

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/4.导出 UnityPackage")]
		private static void MenuClicked4()
		{
			ExportPackage("Assets/QFramework",GenerateUnityPackageName() + ".unitypackage");
		}
#endif

		public static void ExportPackage(string assetPathName,string fileName)
		{
			#if UNITY_EDITOR
			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);
			#endif
		}

提取第五个示例

首先看代码:

using System;
#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;

namespace QFramework
{
	public class OpenInFolder
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/5.打开所在文件夹")]
		private static void MenuClicked()
		{
			Application.OpenURL("file:///" +  Application.dataPath);
		}
#endif
	}
}

核心的 API 就是 OpenURL,在打开文件夹的时候,一般路径的前缀是固定的。提取成如下:

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/5.打开所在文件夹")]
		private static void MenuClicked5()
		{
			OpenInFolder(Application.dataPath);
		}
#endif
		public static void OpenInFolder(string folderPath)
		{
			Application.OpenURL("file:///" +  folderPath);

		}

提取第六个示例

先看代码

using System.IO;
#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;

namespace QFramework
{
	public class ReuseMenuItem : MonoBehaviour
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/6.MenuItem 复用")]
		private static void MenuClicked()
		{
			EditorApplication.ExecuteMenuItem("QFramework/4.导出 UnityPackage");
			Application.OpenURL("file:///" + Path.Combine(Application.dataPath, "../"));
		}
#endif
	}
}

核心 API 是 EditorApplication.ExecuteMenuItem。

提取方法后的代码如下。

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/6.MenuItem 复用")]
		private static void MenuClicked6()
		{
			CallMenuItem("QFramework/8.总结之前的方法/4.导出 UnityPackage");
			OpenInFolder(Path.Combine(Application.dataPath, "../"));
		}

		public static void CallMenuItem(string menuPath)
		{
			EditorApplication.ExecuteMenuItem(menuPath);
		}
#endif

提取第七个示例

先看代码:

#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;

namespace QFramework
{
	public class CustomShortCut : MonoBehaviour
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/7.自定义快捷键 %e")]
		private static void MenuClicked()
		{
			EditorApplication.ExecuteMenuItem("QFramework/6.MenuItem 复用");
		}
#endif
	}
}

这个呢是自定义快捷键,所以目前没有办法复用,只能记在代码里了。在这里我们直接输出一句话就好。

代码如下:

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/7.自定义快捷键")]
		private static void MenuClicked7()
		{
			Debug.Log("%e 意思是快捷键 cmd/ctrl + e");
		}
#endif

到此呢,第八个示例的代码算写完了。

如下:

#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;
using System;
using System.IO;

namespace QFramework
{
	public class PreviousFunctions : MonoBehaviour
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/1.获取文件名")]
#endif
		private static void MenuClicked()
		{
			Debug.Log(GenerateUnityPackageName());
		}

		public static string GenerateUnityPackageName()
		{
			return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh");
		}

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/2.复制文本到剪切板")]
#endif
		private static void MenuClicked2()
		{
			CopyText("要复制的关键字");
		}

		public static void CopyText(string text)
		{
			GUIUtility.systemCopyBuffer = text;
		}

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/3.生成文件名到剪切板")]
#endif
		private static void MenuClicked3()
		{
			CopyText(GenerateUnityPackageName());
		}

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/4.导出 UnityPackage")]
		private static void MenuClicked4()
		{
			ExportPackage("Assets/QFramework",GenerateUnityPackageName() + ".unitypackage");
		}
#endif

		public static void ExportPackage(string assetPathName,string fileName)
		{
			#if UNITY_EDITOR
			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);
			#endif
		}

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/5.打开所在文件夹")]
		private static void MenuClicked5()
		{
			OpenInFolder(Application.dataPath);
		}
#endif
		public static void OpenInFolder(string folderPath)
		{
			Application.OpenURL("file:///" +  folderPath);
		}

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/6.MenuItem 复用")]
		private static void MenuClicked6()
		{
			CallMenuItem("QFramework/8.总结之前的方法/4.导出 UnityPackage");
			OpenInFolder(Path.Combine(Application.dataPath, "../"));
		}

		public static void CallMenuItem(string menuPath)
		{
			EditorApplication.ExecuteMenuItem(menuPath);
		}
#endif

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/7.自定义快捷键")]
		private static void MenuClicked7()
		{
			Debug.Log("%e 意思是快捷键 cmd/ctrl + e");
		}
#endif

	}
 }

代码有点辣眼睛,因为宏定义太多了,并且 MenuItem 方法和 public 方法交叉使用,所以我们整理一下,整理后的代码如下。

#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;
using System;
using System.IO;

namespace QFramework
{
	public class PreviousFunctions : MonoBehaviour
	{
		public static string GenerateUnityPackageName()
		{
			return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh");
		}

		public static void CopyText(string text)
		{
			GUIUtility.systemCopyBuffer = text;
		}

		public static void CallMenuItem(string menuPath)
		{
			EditorApplication.ExecuteMenuItem(menuPath);
		}

		public static void OpenInFolder(string folderPath)
		{
			Application.OpenURL("file:///" +  folderPath);
		}

#if UNITY_EDITOR
		public static void ExportPackage(string assetPathName,string fileName)
		{
			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);
		}
#endif		

#if UNITY_EDITOR
		[MenuItem("QFramework/8.总结之前的方法/1.获取文件名")]
		private static void MenuClicked()
		{
			Debug.Log(GenerateUnityPackageName());
		}

		[MenuItem("QFramework/8.总结之前的方法/2.复制文本到剪切板")]
		private static void MenuClicked2()
		{
			CopyText("要复制的关键字");
		}

		[MenuItem("QFramework/8.总结之前的方法/3.生成文件名到剪切板")]
		private static void MenuClicked3()
		{
			CopyText(GenerateUnityPackageName());
		}

		[MenuItem("QFramework/8.总结之前的方法/4.导出 UnityPackage")]
		private static void MenuClicked4()
		{
			ExportPackage("Assets/QFramework",GenerateUnityPackageName() + ".unitypackage");
		}

		[MenuItem("QFramework/8.总结之前的方法/5.打开所在文件夹")]
		private static void MenuClicked5()
		{
			OpenInFolder(Application.dataPath);
		}

		[MenuItem("QFramework/8.总结之前的方法/6.MenuItem 复用")]
		private static void MenuClicked6()
		{
			CallMenuItem("QFramework/8.总结之前的方法/4.导出 UnityPackage");
			OpenInFolder(Path.Combine(Application.dataPath, "../"));
		}

		[MenuItem("QFramework/8.总结之前的方法/7.自定义快捷键")]
		private static void MenuClicked7()
		{
			Debug.Log("%e 意思是快捷键 cmd/ctrl + e");
		}
#endif
	}
 }

逐个执行菜单,运行结果全部正确。

到此呢,我们可以进行一次导出了。

ok,今天的内容就这些。

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

更多内容

原文地址:https://www.cnblogs.com/liangxiegame/p/12579604.html

时间: 2024-11-06 22:52:32

Unity 游戏框架搭建 2019 (九~十二) 第一章小结&第二章简介&第八个示例的相关文章

Unity 游戏框架搭建 2019 (十三~十五) 接下来要学什么?& 第九个示例

在之前的两篇中,我们使用 public 静态方法对之前的内容进行了一个抽取,有了 public 静态方法这个工具,我们的学习行为也发生了一点变化. 在没使用 public 关键字之前呢,每一个示例仅仅是一个知识的记录作用.而我们用了 public 关键字之后,我们可以把知识作为一个可以复用的方法.但是呢,这样就有了一个顺序的问题. 我们是先写方法在写 MenuItem?还是先写 MenuItem 还是在写方法? 笔者给出的答案是,在学习新的 API 或者新的知识点的时候建议先写 MenuItem

Unity 游戏框架搭建 2019 (二十三、二十四) 备份与版本号&危险的操作

先列出上一篇的总结: 要做的事情: 备份:导出文件,并取一个合理的名字. 遗留问题: 第八个示例与之前的示例代码重复,功能重复. 约定和规则: 每个示例在 QFramework 目录下创建一个文件夹,文件夹的格式是: 数字.示例的功能 每个示例写一个脚本,脚本中包含可复用的静态方法和 MenuItem 方法. 每写一个示例进行一次导出,导出的文件名后边加上日期和时间,这个功能已经在导出功能里内置了. 示例分类: 知识学习&收集 API 收集 C# 语法实践 库本身的功能 规则实现 使用流程提供及

Unity 游戏框架搭建 2019 (五) 打开所在文件夹

在上一篇中我们搞定了直接导出的功能,这算是一个巨大的进步了.那么在这篇我们再接着往下分析. 这样我们目前的导出步骤为: 点击菜单栏 QFramework/4.导出 UnityPackage. 我们是不是没有可以优化的空间了? 对于导出步骤的数量来说,确实没有了.只需要一步就可以导出了.但是从一个所花费的时间角度来讲其实还有空间的.也就是说,我们还可以节省时间. 我们跳出导出步骤这个角度,而是思考下导出之后我们做了什么事情? 答案是:打开 unitypackage 所在的文件夹. 这步其实也比较耗

Unity 游戏框架搭建 2018(八)小结

Unity 游戏框架搭建 2018,是笔者在 gitchat 平台发布的 2018 年版本的框架搭建. 在 2018 年的时候 QFramework 已经集成了 UI Kit 和 Res Kit 这两个强大且好用的套件. 可以说 框架搭建 2018 版本是 对 2017 年版本的一个补充,主要补充的内容这是 UI Kit.Res Kit.和一个关于变量命名的讨论. 而在 2018 年,笔者首次发表了对变量命名的一个看法,其实在这一年,笔者从变量的命名研究中收益颇多,远大于 UI Kit 和 Re

Welcome to Swift (苹果官方Swift文档初译与注解十二)---77~83页(第二章)

Optionals (可选类型) 当一个值可能有值,也可能没有值,这种情况你可以使用可选类型.可选类型的意思是: 有个一个值,它等于x,或者,根本没有任何值. 注意点: 可选类型的概念在C和OC中都是没有的.在OC中最相似的情况是,一个方法返回nil或者返回一个对象.OC中返回nil意思是没有合法的对象.然而,这只能针对对象,不能用在结构体,基本 数据类型,或者枚举值.对于这些类型,OC的方法只能返回固定的某个值(比如NSNotFound)来提示没有某个值.这要去方法的调用者清楚的记得返回的固定

Unity 游戏框架搭建 (二十一) 使用对象池时的一些细节

上篇文章使用SafeObjectPool实现了一个简单的Msg类.代码如下: class Msg : IPoolAble,IPoolType { #region IPoolAble 实现 public void OnRecycled() { Log.I("OnRecycled"); } public bool IsRecycled { get; set; } #endregion #region IPoolType 实现 public static Msg Allocate() { r

Unity游戏框架搭建 (一) 概述

??为了重构手头的一款项目,翻出来当时未接触Unity时候收藏的视频<Unity项目架构设计与开发管理>,对于我这种初学者来说全是干货.简单的总结了一下,以后慢慢提炼. 关于Unity的架构有如下几种常用的方式. 1.EmptyGO: ??在Hierarchy上创建一个空的GameObject,然后挂上所有与GameObject无关的逻辑控制的脚本.使用GameObject.Find()访问对象数据. 缺点:逻辑代码散落在各处,不适合大型项目. 2.Simple GameManager: ??

【Unity 3D】学习笔记三十二:游戏元素——游戏光源

游戏光源 在3D游戏中,光源是一个非常具有特色的游戏组件.用来提升游戏画面质感的.如果没有加入光源,游戏场景可能就会显得很昏暗.在unity中提供了三种不同的光源类型:点光源,聚光灯,平行光. 点光源 顾名思义,点光源是从一个点向周围散发出光的光源,就像电灯一样.创建点光源在hierarchy视图中点击create--point light: 创建完以后,点击点光源对象,在右侧inspector视图中可以看到点光源的所有信息: type:光源的类型.有point(点光源),directional

Cocos2d-x项目的游戏框架搭建

本篇所用的Cocos2d-x版本为:Cocos2d-x 3.2 Cocos2d-x项目的游戏框架搭建 游戏与应用项目其实差别不是很大,甚至有许多地方都是一样的,无非侧重点不同,手机游戏更侧重于用户的体验,更加的娱乐化.情感化.让玩家感觉“爽”.而手机应用更侧重于简单.明了,优先完成业务为重. 在以Cocos2d-x引擎为基础上,其实我们要做的准备工作还是很多的: 一.分析项目 首先,我们要知道,我们这个游戏是什么样类型的游戏,游戏机制是什么,按照目前市场上来说可以分成如下类型与机制: 1. 游戏