Unity3d Inspector面板实现set/get访问器

     简单说一下属性和字段的区别:字段就是成员变量,而属性确实提供给外部访问内部成员变量的接口。之所以会有属性的出现,就是为了避免外部对类的成员的直接访问,通俗的说就是OOP中的封装思想。

using UnityEngine;
using System.Collections;

public class DemoTest : MonoBehaviour {


    private int _score;
    public int Score
    {
        get { return _score; }
        set
        {

            if (value > 100)
            {
                value = 100;
            }
            _score = value;
        }
    }
}

     上面的示例中_score就是字段或者叫成员变量,,而Score其实是C#语法简化的方法,提供了私有成员_score对外部的访问接口,当我们通过Score更改_score的值时就会触发set{…}代码段的代码执行,这样就完成了对_score的范围限制,这里就体现了OOP中的封装的好处啦。。。。关于属性和字段的介绍就到此为止,下面说一下这篇文章的主题。

     在Unity中可以把字段使用[SerializeField]的方式序列化到Inspector面板(至于什么是序列化,读者可以自行百度),当然public 访问权限的字段是隐式添加[SerializeField],所以可以直接被序列化的,private的字段也可以手动添加[SerializeField]来实现序列化的比如上述的例子中我简单在_score上添加[SerializeField],就可以在Inspector面板上直接对_score赋值了

using UnityEngine;
using System.Collections;

public class DemoTest : MonoBehaviour {

    [SerializeField]
    private int _score;
    public int Score
    {
        get { return _score; }
        set
        {

            if (value > 100)
            {
                value = 100;
            }
            _score = value;
        }
    }
}

此时可以在Inpector面板中看到:捕获

之所以会显示Score,而不是_score,这是unity3d在显示的时候做的一些处理,不必关注。然而此时我们如果直接修改Score的值到120,那么我们其实直接修改的_score的值,而不是通过属性Score来访问的,所以我们限定的_score<=100,就不在起作用了,那么如果在工程中有这种需求该怎么处理呢?有两种方案可供选择,先说第一种写Editor的方式实现:

using UnityEngine;
using System.Collections;

public class DemoTest : MonoBehaviour {

   // [SerializeField]
    private int _score;

    public int Score
    {
        get { return _score; }
        set
        {
           
            if (value > 100)
            {
                value = 100;
            }
            print("set _score value = " + value);
            _score = value;
        }
    }
}

自定义的Editor类源码(当然该类必须放在Editor目录下:

using UnityEngine;
using System.Collections;
using UnityEditor;
[CustomEditor(typeof(DemoTest))]    //为DemoTest添加一个自定义标签
public class EditorTest : Editor {

    public override void OnInspectorGUI()   //当DemoTest在Inspector面板上显示改动时触发
    {
        DemoTest demoTest = target as DemoTest; //target是Eiditor内部封装的当前操作的对象引用
        int score = EditorGUILayout.IntField("Score", demoTest.Score);//在Inspector面板上序列化一个对象,并关联demoTest.Score属性
        if (demoTest.Score != score)//如果该属性在改动后没有触发就手动触发
        {
            demoTest.Score = score;
        }
        base.DrawDefaultInspector();//重回Inspector面板
    }
}

这样当我们修改Socre时就可以在Console中看到相应的输出了,也就解决了set、get方法封装性问题。当然这种方式很有局限性,使用起来十分不方便,还有一种简便的方式,使用SetProperty标签,当然我个人由于unity版本过低,SetProperty还不支持,,应该要5.0以后的版本吧,这里附上链接:https://github.com/LMNRY/SetProperty

posted @ 2015-07-19 08:42  jiuguang  阅读(5042)  评论(0编辑  收藏  举报