Unity Attribute 例子整理
添加组件菜单
引擎会把该程序集下的全部类视为编辑器类
设置Application.onBeforeRender回调函数的执行顺序
DHR拾色器界面
为脚本添加快捷菜单
为脚本字段添加快捷菜单
添加ScriptableObject的创建菜单
自定义Tilemap笔刷
延迟更新字段的值
不允许多次挂载同一个脚本到同一个物体上
添加[ExcludeFromObjectFactory]后,调用ObjectFactory.AddComponent<对应组件>时,会失败并报错
添加[ExcludeFromPreset]后,即便用代码生成Preset,Preset的参数也不支持设置
添加[ExcludeFromPreset]后,不能选择和保存为Preset
using UnityEngine;
[ExecuteAlways]
public class ExampleClass : MonoBehaviour
{
void Start()
{
if (Application.IsPlaying(gameObject))
{
// Play logic
}
else
{
// Editor logic
}
}
}
/// <summary>
/// https://docs.unity3d.com/ScriptReference/ExecuteInEditMode.html
/// </summary>
// The PrintAwake script is placed on a GameObject.
// The Awake function is usually
// called when the GameObject is started at runtime.
// Due to the ExecuteInEditMode
// attribute, the script is also called by the Editor.
// The Awake() function will be called,
// for example, when the Scene is changed to a
// different Scene in the Project window.
// The Update() function is called,
// for example, when the GameObject transform
// position is changed in the Editor.
[ExecuteInEditMode]
public class PrintAwake : MonoBehaviour {
void Awake() {
Debug.Log("Editor causes this Awake");
}
void Update() {
Debug.Log("Editor causes this Update");
}
}
颜色渐变界面
// 控制OnGUI函数调用,在哪些显示设备上有效
// GUITarget attribute allows to control for which display the OnGUI is called.
[GUITarget(1, 2)]
void OnGUI() {
var color = GUI.color;
GUI.color = Color.red;
GUILayout.Space(30f);
GUILayout.Label(" This information is visible on 'Display 2' and 'Display 3' only.");
GUI.color = color;
}
[Header("Health Settings")]
public int health = 0;
public int maxHealth = 100;
[Header("Shield Settings")]
public int shield = 0;
public int maxShield = 0;
点击组件上的问号按钮,会打开指定的网站
// 隐藏字段
[HideInInspector]
public int p = 5;
// 指定字符串能显示的行数(我也不知道为什么只显示了7行)
[Multiline(8)]
public string value;
还有,需要按回车才能换行
(继承ScriptableObject的类)添加[PreferBinarySerialization]后,
对应的asset文件的存储格式,会变成二进制格式
滑条样式
1. 自动添加依赖的组件
2. 不能手动移除依赖的组件(必须先移除该组件,才能移除依赖的组件)
运行时初始化,触发调用(全都只触发一次)
class RuntimeInitializeOnLoadMethodExample {
// Callback used for registration of subsystems
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void OnSubsystemRegistration() {
Debug.Log("0.OnSubsystemRegistration");
}
// Callback when all assemblies are loaded and preloaded assets are initialized.
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
static void OnAfterAssembliesLoaded() {
Debug.Log("1.OnAfterAssembliesLoaded");
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
static void OnBeforeSplashScreen() {
Debug.Log("2.Before the splash screen is shown.");
}
// 加载第一个场景时会被调用
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void OnBeforeSceneLoad() {
Debug.Log("3.Before first Scene loaded");
}
// 等价于[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
[RuntimeInitializeOnLoadMethod]
static void OnAfterSceneLoad1() {
Debug.Log("4-1.After first Scene loaded");
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void OnAfterSceneLoad2() {
Debug.Log("4-2.After first Scene loaded");
}
[RuntimeInitializeOnLoadMethod]
static void OnAfterSceneLoad3() {
Debug.Log("4-3.After first Scene loaded");
}
}
在Scene窗口,
点击没带[SelectionBase]的组件的物体时,
自动选择父级里,带[SelectionBase]的组件的物体
//This field gets serialized because it is public.
public string firstName = "John";
//This field does not get serialized because it is private.
private int age = 40;
//This field gets serialized even though it is private
//because it has the SerializeField attribute applied.
[SerializeField]
private bool hasHealthPotion = true;
void Start()
{
if (hasHealthPotion)
Debug.Log("Person's first name: " + firstName + " Person's age: " + age);
}
添加后,能在不同Animator间共享同一个StateMachineBehaviour
// 测试例子
// SharedBetweenAnimatorsExampleCounter.cs
public List<SharedBetweenAnimatorsExample> StateMachineBehaviours;
public List<Animator> Animators;
// SharedBetweenAnimatorsExample.cs
[SharedBetweenAnimators]
public class SharedBetweenAnimatorsExample : StateMachineBehaviour {
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
var Animators = SharedBetweenAnimatorsExampleCounter.Instance.Animators;
if (!Animators.Contains(animator)) {
Animators.Add(animator);
}
var StateMachineBehaviours = SharedBetweenAnimatorsExampleCounter.Instance.StateMachineBehaviours;
if (!StateMachineBehaviours.Contains(this)) {
StateMachineBehaviours.Add(this);
}
}
}
运行结果:
StateMachineBehaviours长度为1,Animators长度为2,
两个动画共享同一个SharedBetweenAnimatorsExample
在字段间加一段间隔
可自动换行的字符串界面样式
光标停留在字段名字上一段时间后,显示提示
指定旧字段的名字,防止字段改名后造成的数据丢失
// FormerlySerializedAsExample.cs
public class FormerlySerializedAsExample : MonoBehaviour {
public string myValue;
}
====>
public class FormerlySerializedAsExample : MonoBehaviour {
[FormerlySerializedAs("myValue")]
[SerializeField]
string m_MyValue;
public string myValue {
get { return m_MyValue; }
set { m_MyValue = value; }
}
}
允许同时编辑多个
自定义预览界面
[CustomPreview(typeof(MyObject))]
public class MyPreview : ObjectPreview {
public override bool HasPreviewGUI() {
return true;
}
public override void OnPreviewGUI(Rect r, GUIStyle background) {
GUI.Label(r, target.name + " is being previewed");
}
}
自定义属性界面
自定义Scene窗口的Gizmo
public class MyScriptGizmoDrawer {
[DrawGizmo(GizmoType.Selected | GizmoType.Active)]
static void DrawGizmoForMyScript(MyScript scr, GizmoType gizmoType) {
Vector3 position = scr.transform.position;
if (Vector3.Distance(position, Camera.current.transform.position) > 10f)
Gizmos.DrawIcon(position, "MyScript Gizmo.png", true);
}
}
// 打开项目后,生成该类,并调用该类的构造函数
/// <summary>
/// https://docs.unity3d.com/ScriptReference/InitializeOnLoadAttribute.html
///
/// Allows you to initialize an Editor class when Unity loads,
/// and when your scripts are recompiled.
/// Static constructors with this attribute are called
/// when scripts in the project are recompiled (also known as a Domain Reload).
/// when Unity first loads your project,
/// but also when Unity detects modifications to scripts
/// (depending on your Auto Refresh preferences),
/// and when you enter Play Mode (depending on your Play Mode configuration).
/// </summary>
// Running Editor Script Code on Launch
[InitializeOnLoad]
public class InitializeOnLoadExample {
static InitializeOnLoadExample() {
/// https://docs.unity3d.com/Manual/RunningEditorCodeOnLaunch.html
//Debug.Log("Up and running");
// editor frame update
//EditorApplication.update += Update;
}
//static void Update() {
// Debug.Log("Updating");
//}
}
// 打开Unity引擎后触发调用
[InitializeOnLoadMethod]
static void OnProjectLoadedInEditor() {
/// https://docs.unity3d.com/ScriptReference/InitializeOnLoadMethodAttribute.html
//Debug.Log("Project loaded in Unity Editor");
}
打开资源时(在Project窗口双击文件后)触发调用
发布程序后触发调用(每次)
// PostProcessBuildExample.cs
[PostProcessBuild(1)]
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) {
// after build
Debug.Log(target + ":" + pathToBuiltProject);
}
每次进入场景前触发调用
// PostProcessSceneExample.cs
[PostProcessScene(2)]
static void OnPostprocessScene() {
OnBeforeSceneLoaded();
}
static void OnBeforeSceneLoaded() {
var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
Debug.LogWarning("OnBeforeSceneLoaded ======> " + scene.name + ".unity");
}
GridPaintSorting(the sorting of Active Targets in the Active Tilemap list of the Tile Palette window)
自定义脚本的图标
自定义枚举显示的名字
public enum MyEnum {
A,
[InspectorName("B评分")]
B,
[InspectorName("C评分")]
C,
}
限定最小值
不可排序列表
// NonReorderableExample.cs
/// <summary>
/// 不可排序
/// </summary>
[NonReorderable]
public List<int> nonReorderableList = new List<int> { 1, 4, 2, 99 };
/// <summary>
/// 可排序
/// </summary>
public List<string> reorderableList = new List<string> { "哈哈", "哈", "哈哈哈哈" };
打开搜索窗口,可以通过关键字和query text来搜索资源,
但这个query text的具体语法,我暂时没能在官方文档里找到相关的链接或教程
编辑器里点播放按钮后触发调用
[InitializeOnEnterPlayMode]
static void OnEnterPlaymodeInEditor(EnterPlayModeOptions options) {
Debug.Log("Entering PlayMode");
}
配合ScriptableSingleton<T>使用,指定数据的保存位置
指定Editor对应的组件
// CustomEditorExampleEditor.cs
[CustomEditor(typeof(CustomEditorExample), true)]
public class CustomEditorExampleEditor : Editor { ... }
CustomEditorExample2继承与CustomEditorExample,
组件面板上都带有名为A button的按钮
脚本编译结束后触发调用
public class DidReloadScriptsExample {
[DidReloadScripts]
static void AfterReloadedScripts() {
Debug.LogWarning("AfterReloadedScripts");
}
}