【Unity C#编程】自定义数据

译林军 灰魅|2014-03-04 10:52|10589次浏览|Unity(315)移动应用(31)技术开发(16)0

在这篇Unity C#的文章中,你将会创建一个简单的数据结构,然后写下它的属性抽屉。

下面你将会学到如何创建。

  • 使用一个序列化的类
  • 创建一个自定义的属性抽屉
  • 使用序列化属性
  • 在编辑器里面使用Unity的立即窗口GUI模式

在此之前,你需要了解Unity的编辑器,以及Uinty C#的一些脚本。如果你已经学习了一些其它的课程,这将会让你更加容易上手。

这篇文章适合Unity 4.3或者以上的版本。老版本仍然可以在这里找到。

被压缩的色点

色点

Unity有很多种类的的数据类型,你可以用这些数据去制作很多自定义组件。但是有时我们需要一些小的自定义数据,它可以在很多地方使用。与其重复写同样的代码,倒不如选择一些可以重复使用,而且十分简单的封装数据类,例如一些内置的数据类型。

我们将要创建一些色点,这个数据结构是同时包括颜色和位置。

我们首先创建一个新的空项目工程,然后添加一个名为ColorPoint的新的C#脚本,同时添加所需的变量。


1

2

3

4

5

6

7

using UnityEngine;

public class ColorPoint {

    public Color color;

    public Vector3 position;

}

然后我们再创建一个叫ColorPointTester的类来测试我们刚刚创建的数据类型。我们给它一个单独的点向量和一个数组向量,同时也比较单独的点向量和数组向量。接着我们创建一个空的游戏物体,把它添加到里面。


1

2

3

4

5

6

7

8

9

10

11

12

using UnityEngine;

public class ColorPointTester : MonoBehaviour {

    

    public ColorPoint point;

    

    public ColorPoint[] points;

    

    public Vector3 vector;

    

    public Vector3[] vectors;

}

色点和空测试器。

新的数据类型不能在inspector中看到,因为他的内容还不能被保存。我们要解决这个问题就要把这个数据类型添加到系统中。被序列化后属于我们的类.在执行这步是,这个类可能要在所有公共地方的数据流可以序列化,然后才能被存储起来。


1

2

3

4

5

6

7

8

9

using UnityEngine;

using System;

[Serializable]

public class ColorPoint {

    

    public Color color;

    public Vector3 position;

}

现在我们刚自定义的数据可以再inspector中显示了,我们可以再任何地方编辑、保存。同样的,把我们的测试对象通过拖拽到项目视图的预设中,然后在场景中改变一些变量的实例。这可以证明这类数据可以在预设中正常运行。

正常的对象和一个调整的实例预设。inspector看起来很混乱。这可以有所修改,让它通过拖动变宽一些,但如果它的宽度过大,向量将会崩溃。

一个充实的inspector。

绘图属性

很可惜,即使有较宽的inspector,我们仍需要多行色点。

幸运的是,我们可以用自定义的变量在编辑中替换Unity的默认绘图属性。这可以通过扩展UnityEditor.PropertyDrawer来创建一个类,同时用 UnityEditor.CustomPropertyDrawer来匹配我们想要绘制的相关内容。然后,命名一个叫ColorPointDrawer的类,因为这是一个编辑的类,我们会把它放在一个叫Editor新的文件夹里面。


1

2

3

4

5

6

using UnityEditor;

using UnityEngine;

[CustomPropertyDrawer(typeof(ColorPoint))]

public class ColorPointDrawer : PropertyDrawer {

}

这是不做任何处理的属性抽屉。

现在inspector不再显示任何有用的东西,但是我们可以改变,通过覆盖在OnGUI上,来默认自定义版本的属性抽屉。

这个OnGUI方法有三个参数。第一个是一个巨型,它是告诉我们那些窗口的区域是应该使用什么来绘制属性。第二个是自身的属性,由一个SerializedProperty来表示。第三个是GUIContent,定义了我们应该使用的属性标签。

让我们首先用GUIEditor.PropertyField的方法找准位置,然后绘制GUIEditor.PrefixLabel。


1

2

3

4

public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {

        EditorGUI.PrefixLabel(position, label);

        EditorGUI.PropertyField(position, property.FindPropertyRelative("position"));

    }

属性抽屉的重叠标签。

当我们锁定位置后,它的标签就是重叠标签的色点。接下来,我们要通过用GUIContent.none.来重写它。


1

2

3

4

public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {

    EditorGUI.PrefixLabel(position, label);

    EditorGUI.PropertyField(position, property.FindPropertyRelative("position"), GUIContent.none);

}

一个依旧重叠的标签

向量仍然是重叠标签,因为我们使用的是同样的位置矩形,接下来,我们将用这个矩形进行替换。


1

2

3

4

public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {

    Rect contentPosition = EditorGUI.PrefixLabel(position, label);

    EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("position"), GUIContent.none);

}

即使不正确的定位,也不再重叠。

这看起来好了很多,但放置位置向量的数组元素太过于偏右。导致这个发生的原因是PropertyField方法调整当前的编辑器缩进级别。

通过静态初始化EditorGUI.indentLevel的方法,设置缩进的级别。为了暂时的消除自动缩进,我们只要将其设置为零即可。


1

2

3

4

5

public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {

    Rect contentPosition = EditorGUI.PrefixLabel(position, label);

    EditorGUI.indentLevel = 0;

    EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("position"), GUIContent.none);

}

正确定位

原文链接:http://catlikecoding.com/unity/tutorials/editor/custom-data/

修改Prefix

当prefix标签变成粗体,显示调整过的预制值时,它就无法进行任何操作。所以我们既不能立即恢复整个弹辨色点(color point),也不能轻易删除或复制prefix标签的数组元素。

我们需要在编辑器中设定属性生效的起始位置,因为目前我们仅仅展示了一部分内容。我们可以使用EditorGUI。利用BeginProperty类函数创建一个新标签,并标志着一个属性的出现,然后使用EditorGUI。利用EndProperty类函数表示属性的终止。这样我们就可以通过上下文菜单(context menu)获得拥有预期功能的标签。


1

2

3

4

5

6

7

public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {

        label = EditorGUI.BeginProperty(position, label, property);

        Rect contentPosition = EditorGUI.PrefixLabel(position, label);

        EditorGUI.indentLevel = 0;

        EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("position"), GUIContent.none);

        EditorGUI.EndProperty();

    }

恢复及数组功能支持

添加颜色

现在该设定颜色属性了。为了使其在一条线上,我们必须减少矢量所占空间。由于矢量由三部分组成而颜色作为其第四部分,我们将把向量置于前75%的水平空间,把颜色置于其余的25%空间中。我们也使用单字母命名颜色标签。


1

2

3

4

5

6

7

8

9

10

11

public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {

        label = EditorGUI.BeginProperty(position, label, property);

        Rect contentPosition = EditorGUI.PrefixLabel(position, label);

        contentPosition.width *= 0.75f;

        EditorGUI.indentLevel = 0;

        EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("position"), GUIContent.none);

        contentPosition.x += contentPosition.width;

        contentPosition.width /= 3f;

        EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("color"), new GUIContent("C"));

        EditorGUI.EndProperty();

    }

带颜色,但有误。

尽管我们的标签很短,但是它依然占据较多空间,导致颜色数据被挤到右侧。这是因为无论内容长短,标签宽度都是固定的。你可以通过调整EditorGUIUtility.labelWidth.改变标签宽度。设置14个像素的宽度效果更佳。


1

2

3

4

5

6

7

8

9

10

11

12

public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {

        label = EditorGUI.BeginProperty(position, label, property);

        Rect contentPosition = EditorGUI.PrefixLabel(position, label);

        contentPosition.width *= 0.75f;

        EditorGUI.indentLevel = 0;

        EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("position"), GUIContent.none);

        contentPosition.x += contentPosition.width;

        contentPosition.width /= 3f;

        EditorGUIUtility.labelWidth = 14f;

        EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("color"), new GUIContent("C"));

        EditorGUI.EndProperty();

    }

尺寸正好的颜色标签。

索取额外一行

默认像素可以在单行与双行之间转变,这取决于inspector的宽度。我们也可以这么做。

我们必须覆盖GetPropertyHeight method,争取更多的垂直空间。一行的默认值是16个像素。再添加一行需要另外18个像素(包括第二行自身的16个像素及两行间距的2个像素)。

当我们使用inspector面板时,屏幕宽度实际上就包含它的宽度,所以我们可以利用这一点。当宽度减小到333以下时,像素会转换至多行,因此我们也要这么做。


1

2

3

public override float GetPropertyHeight (SerializedProperty property, GUIContent label) {

        return Screen.width < 333 ? (16f + 18f) : 16f;

    }

索取更多空间。

当我们把inspector宽度调小到一定程度时,就能获得更多的垂直空间。然而,我们尚且还不能这么做。为了实现这一目标,我们必须注意以下四点内容。

第一,通过检查position长方形的高度,可以发现我们正在使用双行。第二,我们需要将高度调回到16个像素,以便颜色属性能够保留在同一行。第三,画完属性标签后,我们必须将其下移一行。第四,通过利用EditorGUI IndentedRect method,我们必须增加一级缩进级别,将其应用至position。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {

        label = EditorGUI.BeginProperty(position, label, property);

        Rect contentPosition = EditorGUI.PrefixLabel(position, label);

        if (position.height > 16f) {

            position.height = 16f;

            EditorGUI.indentLevel += 1;

            contentPosition = EditorGUI.IndentedRect(position);

            contentPosition.y += 18f;

        }

        contentPosition.width *= 0.75f;

        EditorGUI.indentLevel = 0;

        EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("position"), GUIContent.none);

        contentPosition.x += contentPosition.width;

        contentPosition.width /= 3f;

        EditorGUIUtility.labelWidth = 14f;

        EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("color"), new GUIContent("C"));

        EditorGUI.EndProperty();

    }

利用更多空间。

现在,我们对弹辨色点(color point)有了一个精彩简短的描述。它支持取消(undo),重写(redo),预制(prefabs)以及多目标编辑。如果inspector足够宽,它只占一行,否则,占两行。

接下来的editor教程涉及自定义列表(Custom List)。

已下载的数据资料

custom-data.unitypackage

已完成的项目。

【Unity C#编程】自定义数据

时间: 2024-10-09 23:38:31

【Unity C#编程】自定义数据的相关文章

Unity SurfaceShader 编程起步

Unity SurfaceShader 编程起步 在14年年初的时候,曾经给自己定下了今年要实现的三个目标,其中之一就是学会编写自己的Shader,并能够投入到实际的项目应用之中.现在,转眼间日历已经翻到了6月份,而自己关于Shader的学习,还停留在三天打鱼两天晒网的零碎学习状态,自己心里很是着急.平时的工作任务多,挤掉了自己的学习时间是一方面.但更重要的,还是因为自己没有制定一个稳步的计划,来监督自己利用一切可以利用的时间完成学习的内容,相反,自己做的太过随意了.所以,继续以博文的形式来督促

Echarts 地图(map)插件之 鼠标HOVER和tooltip自定义数据

在项目开发中,有需要用到地图的地方,百度的echarts地图插件就是个不错的选择, 这里总结一下地图自定义鼠标HOVER时的事件和自定义tooltip数据: 一.鼠标HOVER时的事件: 参照官方文档解释, 可以看出这款插件有丰富的鼠标事件可供选择: 调用鼠标HOVER事件的方法很简单,只需把以下代码放到charts()调用的函数的最底部即可 1 var ecConfig = require('echarts/config'); 2 myChart.on(ecConfig.EVENT.HOVER

Unity 编辑器扩展自定义窗体

这次看见Unity还可以自定义弹出窗体,让我很好奇.于是就去网上找文章看了看. 如果想自定义窗体需要把类放入Editor文件夹下面. 代码如下: using UnityEngine; using UnityEditor; public class MyEditor : EditorWindow { [MenuItem("GameObject/window")] static void AddWindow() { Rect wr = new Rect(0, 0, 500, 500); M

Linechart + Datagrid 互动展示数据 (Linechart自定义数据点选择线)

如上图示,在linechart中添加红色Y线,拖动该线的过程中,经过数据点时,会实时更新datagrid中对应的X.Y值数据. 实现要点: 1.linechart添加Y线 继承mx.charts.chartClasses.ChartElement,自定义Y线. package { import flash.display.Graphics; import flash.geom.Point; import flash.text.TextField; import mx.charts.chartCl

Unity与服务区交互数据

Unity与服务区交互数据 Unity可能在用的时候使用到登陆等需要与服务器交互数据.今天尝试使用了WWW类和WWWForm类来实现Get请求与Post请求. 1.WWW Unity圣典解释: WWW会返回一个新的WWW对象.当它被下载,其结果可以从返回对象中获取.这个函数创建和发送一个GET请求,流将自动开始下载响应.流创建之后,你必须等待它完成,然而可以访问已下载的数据.作为一个方面的流可以被中断,因此你可以容易的告诉Unity等待下载完成.你可以检查isDone属性来查看是否已经下载完成,

Unity加载二进制数据

[Unity加载二进制数据] The first step is to save your binary data file with the ".bytes" extension. unity will treat this file as a TextAsset. As a TextAsset the file can be included when you build your AssetBundle. Once you have downloaded the AssetBun

asp.net mvc3 数据验证(三)—自定义数据注解

原文:asp.net mvc3 数据验证(三)-自定义数据注解         前两节讲的都是asp.net mvc3预先设定的数据注解,但是系统自由的数据注解肯定不适合所有的场合,所以有时候我们需要自定义数据注解. 自定义数据注解有两种,一种是直接写在模型对象中,这样做的好处是验证时只需要关心一种模型对象的验证逻辑,缺点也是显而易见的,那就是不能重用. 还有一种是封装在自定义的数据注解中,优点是可重用,缺点是需要应对不同类型的模型. 现在我们以封装在自定义数据注解中的方法为例看下如何在asp.

Unity Shader编程(1)漫反射着色

Unity Shader编程(1)漫反射着色 在Unity中创建如下工程: 我们把Shader拖到Material上.Meterial拖到Cube上.这就完成了一个着色器的着色过程. Shader "Custom/Shader" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaq

cacti自定义数据收集脚本,创建Data Templates和Graph Templates

参考这篇文章 http://www.mamicode.com/info-detail-187799.html 还有马哥的linux视频.  cacti使用思路: cacti自定义监控脚本进行监控的具体流程如下: 自定义数据收集方法,在Collection Methods下有2项,Data Queries(xml方法)和Data Input Methods (scripts, command方法) 数据收集了如何保存呢?数据模板Data Templates.数据模板定义了:怎么通过数据收集方法获取