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

在之前的两篇中,我们使用 public 静态方法对之前的内容进行了一个抽取,有了 public 静态方法这个工具,我们的学习行为也发生了一点变化。

在没使用 public 关键字之前呢,每一个示例仅仅是一个知识的记录作用。而我们用了 public 关键字之后,我们可以把知识作为一个可以复用的方法。但是呢,这样就有了一个顺序的问题。

我们是先写方法在写 MenuItem?还是先写 MenuItem 还是在写方法?

笔者给出的答案是,在学习新的 API 或者新的知识点的时候建议先写 MenuItem 示例,等掌握这个知识之后,再去设计方法。其他的情况我们遇到了再说。

接下来要学什么?

我们的知识库有一个问题,就是存在重复代码,第八个示例和之前的示例都重复了。有点经验的童鞋早就有把它们一口气整理的冲动了吧?不过,还不是整理的时候,还不是时候。因为我们的规则和约定经常改的话会非常不稳定,会徒增工作量,所以呢,我们要等待一个比较合适的时机。时机成熟了就进行整理。但是在整理之前呢先按照这种接着收集我们的示例。

不过到这里,笔者就迷茫了。在之前我们的知识点都是有目的的,这些知识点组合起来可以为我们解决一些问题,比如导出功能最初是为了让自己在家和在公司之间或者在项目之间进行无缝切换的。这个问题已经解决了,那么还有什么我们身边问题通过编程解决呢?

笔者要好好思考一下,在教程的开头,笔者说要选择的知识点是搭建框架需要的知识点,或者笔者认为比较重要的知识点。而导出功能所需要的知识点是框架中比较常用的 Unity API。而我们每个示例的规则和约定则是架构相关的内容。然后在导出功能之后应用了 C# 语法中的 public 关键字,也就是访问权限,访问权限对一个框架来说也是非常重要的东西。我们到目前为止的目标呢,只是打造一个知识库,这个目标还是在第一篇的时候定的,目前看来只是完成了一个知识库使用的流程,并没有积累很多的知识点。好吧,又回到了刚才提出的要学什么知识点的问题了。

虽然又回到了原点,不过这样梳理一遍思路还是很有帮助的。最起码可以得到一个具体的分类,将以上的几个关键点列出来如下:

  • 框架常用的 Unity API 与功能(比如导出功能)。
  • 架构的内容:约定、规则。
  • C# 程序设计:访问权限与方法设计。

有了以上这样的一个列表,结构就清晰了很多。在 Unity 开发者中,大多数的童鞋都是做项目,少部分童鞋专职做插件、框架或者渲染等工作。所以呢,笔者要思考知识点的方向选什么最合适?

对于专栏来讲,用最少的时间完成一个最简版的框架或许可以马上迎合教程的主题,但是市面上写最简框架的教程和文章多得数不胜数,如果只是为了搞个简易框架而写这篇专栏,不如去看 2017 版本的专栏。

对于读者来讲,专栏要保证阅读体验,并且掌握文章的知识点和方法论的同时能够从文章中获得启发,这样是最好的。而如果一个专栏或者书籍太过系统很影响阅读体验。

所以经过综合思考,接下来学习一些更贴近项目的小知识点。

第九个示例(一)

在上一篇文章中,经过大量的思考我们得出了一个学习方向,那就是在项目中比较实用的小知识点。

我们大部分 Unity 做的项目呢都是移动端的项目,这里包括 iPhone、iPad 以及各种 Android 端的设备。而经过笔者统计大部分的设备屏幕宽高比都是 16:9(iPhone 5s 至 iPhone 8) 和 4:3 (iPad)。而少部分的则是接近 2:1(iPhone X) 和 3:2(iPhone 4s),还有一些比较奇葩的分辨率,比如魅族和华为的 Pad。

而我们在进行屏幕适配的时候多多少少会通过代码来写一些特定分辨率的逻辑(因为总有那么几个比较奇葩的设备)。OK,到此我们要做的事情比较明确了。

我们来做一个用来区分当前设备分辨率的工具。

我们先来写一个最简单的,判断是否是 Pad 分辨率(4:3)。

第九个示例

在开始写判断逻辑之前呢,我们先要获取当前设备的宽和高。

Unity 提供了 Screen.height 和 Screen.width 这两个 API 来为我们提供当前设备的高和宽。

判断横竖屏

设备有可能是横屏也可能是竖屏,所以我们要判断当前是横屏还是竖屏。

判断代码如下:

#if UNITY_EDITOR
		[MenuItem("QFramework/9.屏幕宽高比判断")]
#endif
		private static void MenuClicked()
		{
			var isLandscape = Screen.width > Screen.height;
			Debug.Log(isLandscape ? "横屏" : "竖屏");
		}

如下图所示,当将 Game 视图的分辨率改成 4:3 时。

输出结果为:横屏

而改成如下图所示的 3:4 时

则输出结果为:竖屏。

计算分辨率

现在我们知道了屏幕的方向,这样我们就比较好判断当前屏幕的宽高比了。

代码如下:

#if UNITY_EDITOR
		[MenuItem("QFramework/9.屏幕宽高比判断")]
#endif
		private static void MenuClicked()
		{
			var isLandscape = Screen.width > Screen.height;

			float aspect;

			if (isLandscape)
			{
				aspect = (float) Screen.width / Screen.height;
			}
			else
			{
				aspect = (float) Screen.height / Screen.width;

			}

			Debug.Log(aspect);
		}

由于 Screen.width 和 Screen.height 都是 int 类型的。相除可能结果也只能是整数,所以要在前边转成 float 类型。

以上的这个代码不管是将 Game 视图的分辨率设置成 4:3 还是 3:4,输出的宽高比值都是 1.333 左右,而这个宽高比值的小数点第三位都有一点浮动。所以要在判断是否是 Pad 分辨率的时候要把这个浮动范围考虑进去。

计算是否是 Pad 分辨率

有了以上准备,我们的 Pad 分辨率就比较容易写了。

代码如下

#if UNITY_EDITOR
		[MenuItem("QFramework/9.屏幕宽高比判断")]
#endif
		private static void MenuClicked()
		{
			var aspect = Screen.width > Screen.height ? (float) Screen.width / Screen.height : (float) Screen.height / Screen.width;

			var isPad = aspect > (4.0f / 3 - 0.05) && aspect < (4.0f / 3 + 0.05);

			Debug.Log(isPad ? "是 Pad 分辨率" : "不是 Pad 分辨率");
		}

关于 aspect 的计算做了一步简化,核心代码还是下边的代码,不过也比较好理解了,不多讲了。

代码的执行结果为:Game 视图的宽高比设置成 4:3 或者 3:4 的时候,则输出“是 Pad 分辨率”。如果设置成其他的则输出“不是 Pad 分辨率”。

基本上的一个功能我们算是实现完了,而且测试的结果也是正确的。

提取成方法。

我们来观察一下这几行代码

#if UNITY_EDITOR
		[MenuItem("QFramework/9.屏幕宽高比判断")]
#endif
		private static void MenuClicked()
		{
			var aspect = Screen.width > Screen.height ? (float) Screen.width / Screen.height : (float) Screen.height / Screen.width;

			var isPad = aspect > (4.0f / 3 - 0.05) && aspect < (4.0f / 3 + 0.05);

			Debug.Log(isPad ? "是 Pad 分辨率" : "不是 Pad 分辨率");
		}

其实可以提取成两个方法。一个是计算 aspect (宽高比)的,一个是判断是否是 Pad 分辨率的。

提取后的代码如下:

using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace QFramework
{
	public class ResolutionCheck
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/9.屏幕宽高比判断")]
#endif
		private static void MenuClicked()
		{
			Debug.Log(IsPadResolution() ? "是 Pad 分辨率" : "不是 Pad 分辨率");
		}

		/// <summary>
		/// 获取屏幕宽高比
		/// </summary>
		/// <returns></returns>
		public static float GetAspectRatio()
		{
			return Screen.width > Screen.height ? (float) Screen.width / Screen.height : (float) Screen.height / Screen.width;
		}

		public static bool IsPadResolution()
		{
			var aspect = GetAspectRatio();

			return aspect > (4.0f / 3 - 0.05) && aspect < (4.0f / 3 + 0.05);
		}
	}
}

代码执行的结果与之前的一致。

第九个示例(二)

在上一篇文章中,我们完成了 Pad 设备分辨率的判断。我们今天把剩下的其他分辨率都搞定。

16:9 手机分辨率

大部分手机是 16 : 9 的。

所以代码如下。

		/// <summary>
		/// 是否是手机分辨率 16:9
		/// </summary>
		/// <returns></returns>
		public static bool IsPhoneResolution()
		{
			var aspect = GetAspectRatio();
			return aspect > 16.0f / 9 - 0.05 && aspect < 16.0f / 9 + 0.05;
		}

3:2 (iPhone 4s)

		/// <summary>
		/// 是否是手机分辨率 3:2 3 / 2 = 1.5
		/// </summary>
		/// <returns></returns>
		public static bool IsPhone15Resolution()
		{
			var aspect = GetAspectRatio();
			return aspect > 3.0f / 2 - 0.05 && aspect < 3.0f / 2 + 0.05;
		}

2436:1125 (iPhone X)

		/// <summary>
		/// 是否是iPhone X 分辨率 2436:1125
		/// </summary>
		/// <returns></returns>
		public static bool IsiPhoneXResolution()
		{
			var aspect = GetAspectRatio();
			return aspect > 2436.0f / 1125 - 0.05 && aspect < 2436.0f / 1125 + 0.05;
		}

其他

相信扩展机型的规律大家应该掌握了,这里就不多说了。

完整示例代码如下:

using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace QFramework
{
	public class ResolutionCheck
	{
#if UNITY_EDITOR
		[MenuItem("QFramework/9.屏幕宽高比判断")]
#endif
		private static void MenuClicked()
		{
			Debug.Log(IsPadResolution() ? "是 Pad 分辨率" : "不是 Pad 分辨率");
			Debug.Log(IsPhoneResolution() ? "是 Phone 分辨率" : "不是 Phone 分辨率");
			Debug.Log(IsiPhoneXResolution() ? "是 iPhone X 分辨率" : "不是 iPhone X 分辨率");
		}

		/// <summary>
		/// 获取屏幕宽高比
		/// </summary>
		/// <returns></returns>
		public static float GetAspectRatio()
		{
			return Screen.width > Screen.height ? (float) Screen.width / Screen.height : (float) Screen.height / Screen.width;
		}

		/// <summary>
		/// 是否是 Pad 分辨率 4 : 3
		/// </summary>
		/// <returns></returns>
		public static bool IsPadResolution()
		{
			var aspect = GetAspectRatio();
			return aspect > 4.0f / 3 - 0.05 && aspect < 4.0f / 3 + 0.05;
		}

		/// <summary>
		/// 是否是手机分辨率 16:9
		/// </summary>
		/// <returns></returns>
		public static bool IsPhoneResolution()
		{
			var aspect = GetAspectRatio();
			return aspect > 16.0f / 9 - 0.05 && aspect < 16.0f / 9 + 0.05;
		}

		/// <summary>
		/// 是否是iPhone X 分辨率 2436:1125
		/// </summary>
		/// <returns></returns>
		public static bool IsiPhoneXResolution()
		{
			var aspect = GetAspectRatio();
			return aspect > 2436.0f / 1125 - 0.05 && aspect < 2436.0f / 1125 + 0.05;
		}
	}
}

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

今天内容就这些。

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

更多内容

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

时间: 2024-10-06 15:35:53

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

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

第一章小结 为了强化教程的重点,会在合适的时候进行总结与快速复习. 第二章 简介 在第一章我们做了知识库的准备,从而让我们更高效地收集示例. 在第二章,我们就用准备好的导出工具试着收集几个示例,这些示例中有的是我们后续库的基础工具,也有的是在项目中非常实用的小工具,还有一些示例是实践了在框架搭建方向上非常重要的 C# 语法知识. 第二章大纲如下. 第八个示例(一) 在之前,我们完成了一个导出的功能.但是在完成这个功能的过程中,我们也遇到了一些问题.我们回忆一下,在<MenuItem 复用>的这

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

先列出上一篇的总结: 要做的事情: 备份:导出文件,并取一个合理的名字. 遗留问题: 第八个示例与之前的示例代码重复,功能重复. 约定和规则: 每个示例在 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

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】学习笔记四十五:游戏实例——击垮围墙

用这个游戏实例来总结之前我们复习的所有关于物理引擎的知识.在游戏中,发送一个球形的炮弹来击垮前面的墙.给炮弹与墙都添加了刚体组件,给炮弹绑定了粒子系统,并且在炮弹的粒子动画中添加了5组不同的颜色,显示移动轨迹. using UnityEngine; using System.Collections; public class Script_06_14 : MonoBehaviour { //炮弹对象 private GameObject obj; //准心贴图 public Texture te

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

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

Unity 游戏框架:命名的力量--变量

变量的命名入门 大家先来试着理解一下这段代码: var todoList = new TodoList(); todoList.Todos = new List<Todo>(); var todo = new Todo() { Id = 0, Finished = false, Content = "测试" }; todoList.Todos.Add(todo) todo.Finished = true; 代码本身很简单,就算不用去看 TodoList 类和 Todo 类的