iT邦幫忙

2024 iThome 鐵人賽

DAY 4
0
Software Development

Unity Trick 30 - 提升遊戲開發效率和質感的30個技巧系列 第 4

Unity Trick 4 - 使用Attribute語法糖加速開發效率

  • 分享至 

  • xImage
  •  

什麼是Attribute?

Attribute(屬性)是C#獨有的語法特性。
可以在一個Function上面戴帽子[ 🎩 ]
提供額外的訊息和觸發特定的行為。

常見的Unity屬性:

Inspector 相關:

  1. [SerializeField]

    • 使Private變量在Inspector中可見並可編輯。
    [SerializeField]
    private int myPrivateField;
    
  2. [HideInInspector]

    • 隱藏Public的變量,使其在編輯器中不可見。
    [HideInInspector]
    public int myPublicField;
    
  3. [Range(min, max)]

    • 為int設置範圍,並在編輯器中顯示Slider。
    [Range(0, 100)]
    public int myRangeField;
    
  4. [Tooltip("Description")]

    • 為變量增加提示,當鼠標Hover時顯示。
    [Tooltip("This is a tooltip")]
    public int myField;
    
  5. [Header("Header Title")]

    • 在編輯器中增加標題。
    [Header("My Header")]
    public int myField;
    
  6. [Space(height)]

    • 在編輯器中增加換行間距。
    [Space(10)]
    public int myField;
    
  7. [Multiline]

    • 顯示多行輸入框。
    [Multiline]
    public string myString;
    
  8. [TextArea(minLines, maxLines)]

    • 顯示TextArea。
    [TextArea(3, 10)]
    public string myString;
    

Component相關:

  1. [RequireComponent(typeof(Component))]

    • 確保依賴的組件存在,不存在的話會自動添加
    [RequireComponent(typeof(Rigidbody))]
    public class MyComponent : MonoBehaviour
    {
        // ...
    }
    
  2. [AddComponentMenu("Menu Name")]

    • 將組件添加到指定的組件菜單中。
    [AddComponentMenu("Custom/MyComponent")]
    public class MyComponent : MonoBehaviour
    {
        // ...
    }
    
  3. [ExecuteInEditMode]

    • 允許代碼在編輯模式下執行。
    [ExecuteInEditMode]
    public class MyComponent : MonoBehaviour
    {
        // ...
    }
    
  4. [DisallowMultipleComponent]

    • 防止在同一個遊戲對象上添加多個相同的組件。
    [DisallowMultipleComponent]
    public class MyComponent : MonoBehaviour
    {
        // ...
    }
    
  5. [SelectionBase]

    • 使組件成為選擇基礎,當選擇其子物體時會自動選擇此組件。
    [SelectionBase]
    public class MyComponent : MonoBehaviour
    {
        // ...
    }
    

Runtime相關:

  1. [RuntimeInitializeOnLoadMethod]

    • 標記一個static方法,在遊戲啟動時執行。
    • 也可以指定執行時機,如 RuntimeInitializeLoadType.AfterSceneLoadRuntimeInitializeLoadType.BeforeSceneLoad
    using UnityEngine;
    
    public class MyClass
    {
        [RuntimeInitializeOnLoadMethod]
        static void OnRuntimeMethodLoad()
        {
            Debug.Log("This runs when the game starts.");
        }
    
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        static void BeforeSceneLoad()
        {
            Debug.Log("This runs before any scene is loaded.");
        }
    }
    
  2. [InitializeOnLoadMethod]

    • 用於標記一個static方法,使其在編輯器加載或重新編譯腳本時執行:
    using UnityEditor;
    using UnityEngine;
    
    public class MyEditorClass
    {
        [InitializeOnLoadMethod]
        static void OnEditorLoad()
        {
            Debug.Log("This runs when the editor loads.");
        }
    }
    

Editor 相關:

  1. [MenuItem]

    • 用於將Function添加到 Unity 的Menu中。
    using UnityEditor;
    using UnityEngine;
    
    public class MyMenuItems
    {
        [MenuItem("MyMenu/Do Something")]
        static void DoSomething()
        {
            Debug.Log("Doing something...");
        }
    
        [MenuItem("MyMenu/Do Something with Shortcut %g")]
        static void DoSomethingWithShortcut()
        {
            Debug.Log("Doing something with shortcut...");
        }
    }
    
  2. [CustomEditor]
    創建自定義編輯器,讓你自定義Inspector的顯示效果

    using UnityEditor;
    using UnityEngine;
    
    [CustomEditor(typeof(MyComponent))]
    public class MyComponentEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            DrawDefaultInspector();
    
            MyComponent myComponent = (MyComponent)target;
            if (GUILayout.Button("Do Something"))
            {
                myComponent.DoSomething();
            }
        }
    }
    

Unit Test 相關:

  1. [Test]
    -標記Unit Test方法。

    using NUnit.Framework;
    
    public class MyTests
    {
        [Test]
        public void MyTest()
        {
            Assert.AreEqual(1, 1);
        }
    }
    
  2. [UnityTest]
    標記一個協程測試方法。

    using UnityEngine.TestTools;
    using NUnit.Framework;
    using System.Collections;
    
    public class MyUnityTests
    {
        [UnityTest]
        public IEnumerator MyUnityTest()
        {
            yield return null;
            Assert.AreEqual(1, 1);
        }
    }
    

如果你有使用第三方的插件
如Odin Inspector,
裡面會提供更多的Inspector擴展Attribute可以快速使用。
https://ithelp.ithome.com.tw/upload/images/20240816/201194701haMHYHePO.png


自定義屬性

你可以創建自己的屬性來添加特定的元數據或行為。創建自定義屬性需要繼承 System.Attribute 並使用 [AttributeUsage] 指定屬性可以應用到哪些目標。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyCustomAttribute : Attribute
{
    public string Description { get; }

    public MyCustomAttribute(string description)
    {
        Description = description;
    }
}

如何自製作自己的 Attribute:

  1. 宣告需要用到的Header
using System;
using System.Reflection;
using UnityEngine;
  1. 自義一個新的Attribute
public class DataNameAttribute : Attribute
{
public string PropName;
}
  1. 宣告一個 Model Class

在需要更換名字的變數上加入DataName的Attribute,
複寫ToString的函式

public class Character
{
    [DataName(PropName = "LifePoint")]
    public int Hp { get; set; }

    [DataName]
    public int Mp { get; set; }

    public override string ToString()
    {

        string str = "";

        foreach (PropertyInfo info in GetType().GetProperties())
        {
            foreach (Attribute attr in Attribute.GetCustomAttributes(info))
            {
                if (attr.GetType() == typeof(DataNameAttribute))
                {
                    var propName = ((DataNameAttribute)attr).PropName;
                    if (propName != null)
                        str += ((DataNameAttribute)attr).PropName + ":" + info.GetValue(this) + " ";
                    else
                        str += info.Name + ":" + info.GetValue(this) + " ";
                }
            }
        }
        return str;
    }
}
  1. 使用方法
public class CharacterData : MonoBehaviour
{
    private void Start()
    {
        Character character = new Character();
        character.Hp = 100;
        character.Mp = 200;

        Debug.Log(character);

    }
}

5.顯示結果:
https://ithelp.ithome.com.tw/upload/images/20240817/20119470iQwLO5DqWC.png



上一篇
Unity Trick 3 - 了解Unity代碼的生命週期
下一篇
Unity Trick 5 - 如何寫一份通用的串接API代碼?
系列文
Unity Trick 30 - 提升遊戲開發效率和質感的30個技巧9
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言