系列文章目录
麦田物语第十八天
文章目录
- 系列文章目录
- 一、(Editor)制作 [SceneName] Attribute 特性
- 二、场景切换淡入淡出和动态 UI 显示
一、(Editor)制作 [SceneName] Attribute 特性
在本节课我们编写Unity的特性Attribute来更好的完善我们项目,具体是什么呢,就是当我们在Inspector面板看到的属性面板类似于滑动条一样的类型(本来Sell Percentage只是float的类型的值,因为我们在其前面加上了[Range(0,1)]的Attribute),所有我们自己编写一个新的特性,用作我们跳转场景脚本的场景选择可以使用下拉框的形式进行选择而不是手动输入,这样可以避免因为输入错误导致无法跳转场景等问题,从而使得我们在开发过程中获得更多的便捷。
注意:我们要添加的是Editor的功能,但是我们编写代码的文件夹位置不能放在Editor中,否则就无法使用。
首先我们先创建脚本,该脚本的命名由固定的方法(以Attribute结尾,一定不要拼写错误),然后创建Scripts->Utilities->Attribute->SceneNameAttribute脚本,打开该脚本,在这个脚本中我们不需要写其他的代码,只是将其改成继承自PropertyAttribute即可。
SceneNameAttribute脚本代码如下:
using UnityEngine;public class SceneNameAttribute : PropertyAttribute
{}
解释:Property代表我们Inspector面板的每一个变量,一个String类型,int类型,Vector3类型都是一个Property。
除了上述的代码之外,我们还需要更改Property的绘制,创建Scripts->Utilities->Attribute->SceneNameDrawer脚本,麦扣老师使用的是自动填写的模板,但是我不知道怎么使用,这里我就自己手敲出来了,模板截图如下:
同时将报红的地方更改为我们编写的SceneNameAttribute即可,下面就需要编写这个代码啦!
解释:Rect包括其高度,宽度,xyz的值
SerializedProperty代表的是我们对应标记了SceneName的那个Property,此处我们会在TransitionManager和Teleport中使用。
GUIContent在Unity官方文档的解释就是“构建一个仅包含文本的 GUIContent 对象,同时可以在其里面添加代码使其具备其他的功能”,和Eclipse里面的内容比较相似,如果可以了解的话自己查一下Unity官方文档也可以。
接着我们就可以在TransitionManager脚本的StartSceneName变量上添加我们最新定义的Attribute,还有Teleport脚本的SceneToGo变量也要添加,虽然添加之后我们会发现啥都没有,这是因为我们还没有编写具体代码但是覆盖了原有的写法,接着我们来编写具体的代码吧!
首先我们需要定义一个场景编号sceneIndex,并初始值为-1,还要定义一个GUIContent的数组sceneNames,将每一个场景(名称)都被保存为GUIContent,最后由于我们要将取得的场景的名称从文件目录的形式中分离出来,我们就必须定义分隔符scenePathSplit。
然后是OnGUI代码的编写,首先,如果我们发现Build Setting中的场景数量为0,那么代表此时不能进行这个操作,直接return。
我们怎么拿到场景的名称呢,这是就需要找到Scene变量,它的描述是*.unity 文件的运行时数据结构,通过这个我们就可以得到其位置,然后通过String的方法去获得场景的名称。这个我们在GetSceneNameArray方法中编写。
这个也可以查看官方文档:
https://docs.unity.cn/cn/2021.3/ScriptReference/SceneManagement.Scene.html
在GetSceneNameArray中我们需要先得到在Build Setting中场景的目录scenes(类型为EditorBuildSettingsScene[]),然后在将sceneNames数组初始化,即初始化数组的大小为场景数量,接着我们需要遍历scenes变量,将其通过split方法分割成只有场景名称的字符串(删除后面的.unity以及前面的/),分割成字符串后我们要判断其长度是否大于0,如果大于0,那么将其赋值给sceneNames,反之将其text设置为Deleted Scene,代表虽然找到了,但是被删除了。
Split方法具有多个重载,我们使用我们定义的分隔符,并且舍去空余的部分,我们可以查找Unity官方文档去看看其他的使用方法。
接着我们还要判断如果没有发现场景,代表我们Build Setting中没有添加场景,我们编写这段代码提醒自己:
sceneNames = new[] { new GUIContent(“Check Your Build Settings”) };
其实还有问题,就是当我们重新添加脚本时会发现,刚开始没有赋初值的话应该为空,导致无法选择,那么我们就需要对这个空值进行调整:
我们先进行判断property的StringValue是否为空或者Null(因为我们的场景为String类型并且Property无法自动识别Value值的类型,所以选择StringValue就可以),如果为空的话,那么将sceneIndex赋值为0,如果不为空的话,代表我们给其手动敲了,因此我们要判断我们敲的那个名称是否正确,正确的话,我们在给sceneIndex赋值为对应的那个场景序号,同时将bool值nameFound设置为true代表找到了并退出循环,那我们输入错误了捏,我们也将sceneIndex赋值为0就好了。
最后我们将property的内容更改为sceneIndex所表示的数组位置的内容。
这样GetSceneNameArray方法就编写完成了,我们返回OnGUI的编写:
我们初始化时如果sceneIndex为-1,那么调用GetSceneNameArray方法,然后我们要将其画成弹出式窗口,EditorGUI.Popup方法也有很多重载,我们也可以去官方查看一下(我之前也没用过),这样编写完成之后我们就会有下拉菜单,但是不能进行选择。
我们要接着做的工作就是点按切换里面的内容:我们将点击完成之后的值返回sceneIndex,并存储点击之前的sceneIndex,如果发生改变的话,就再次使用property.stringValue = sceneNames[sceneIndex].text;该赋值语句。
SceneNameDrawer脚本代码如下:
using UnityEngine;
using UnityEditor;[CustomPropertyDrawer(typeof(SceneNameAttribute))]
public class SceneNameDrawer : PropertyDrawer
{int sceneIndex = -1;GUIContent[] sceneNames;readonly string[] scenePathSplit = { "/", ".unity" };public override void OnGUI(Rect position, SerializedProperty property, GUIContent label){if (EditorBuildSettings.scenes.Length