Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

ForkRepository-JE/Unity-Attributes-Example

Open more actions menu
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Unity-Attributes-Example


项目介绍

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");
    }
}

About

Unity attribute 例子整理

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 100.0%
Morty Proxy This is a proxified and sanitized view of the page, visit original site.