Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)

前言

在部分场景搭建中需要整齐摆放一些物品(如仓库中的货堆、货架等),因为有交互的操作在单个模型上,每次总是手动拖动模型操作起来也是繁琐和劳累。
在这背景下,我编写了一个在运行或者编辑状态下都可以进行一键排序模型的脚步。方便在场景搭建时,可以快速搭建这种有规律的模型;在运行时有模型排序功能需求时,能调用接口一键排序。

效果

X轴居中排序:
Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)_第1张图片

X轴左对齐排序:
Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)_第2张图片

XY轴左排序:
Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)_第3张图片

XY轴居中排序:
Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)_第4张图片

xyz轴居中排序:
Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)_第5张图片

多重嵌套排序:
Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)_第6张图片

多重嵌套YZ轴排序:

Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)_第7张图片

实现

功能的设计是在脚步的Inspector上进行排序相关的参数设置,并提供一键排序的按钮。点击后子节点按配置要求进行位置修改。

配置内容

首先是排序的对齐方式(alignment),这里提供如下枚举:

public enum RankAlign {
   Center =1,
   Left =2,
   Right = 3
}

Center为居中的方式,Left是以父节点的位置为左侧(这里不是严格意义上的左,而是从坐标轴的0–正轴方向排序),Right与Left相反。

其它配置,主要就是三个轴系中的配置内容:

    [Header("x轴对齐方式")]
    public RankAlign rankXAlign = RankAlign.Center;
    [Header("y轴对齐方式")]
    public RankAlign rankYAlign = RankAlign.Center;
    [Header("z轴对齐方式")]
    public RankAlign rankZAlign = RankAlign.Center;

    [Header("启用x轴排序)")]
    public bool isXAxis;

    [Header("启用y轴排序)")]
    public bool isYAxis;

    [Header("启用z轴排序)")]
    public bool isZAxis;

    [Header("x轴间距)")]
    public float XDis;

    [Header("y轴间距)")]
    public float YDis;

    [Header("z轴间距)")]
    public float ZDis;


    [Header("x轴默认值)")]
    public float XDef;

    [Header("y轴默认值)")]
    public float YDef;

    [Header("z轴默认值)")]
    public float ZDef;

其中 isXAxis、isYAxis和isZAxis是启用对应轴上排序的开关。

完整的配置如图:
Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)_第8张图片

排序逻辑

再者就是排序处理:

    public void RankingChildren() {
        int total = transform.childCount;
        if (isXAxis)
            XMidIdx = GetMiddleIndex(total, rankXAlign);
        if (isYAxis)
            YMidIdx = GetMiddleIndex(total, rankYAlign);
        if (isZAxis)
            ZMidIdx = GetMiddleIndex(total, rankZAlign);
        for (int i = 0; i < total; i++)
            SetRankPos(transform.GetChild(i), i, total);
     }

这里的处理就是根据各个轴排序对齐方式找到中间点,根据这个轴向上的中间点和节点间距计算出对应轴上的位置,如果不启用排序的则使用对应轴的默认值。

编辑器拓展

因为要使用编辑器的类Editor,所以要新建一个Editor文件夹放入编辑器拓展的脚本,或者在脚步中判断是否为编辑器环境。否则无法打包。这里在Editor文件夹下新建一个ModelRankingEditor脚本:

[CustomEditor(typeof(ModelRanking))]
public class ModelRankingEditor : Editor
{
    // Start is called before the first frame update
    void Start()
    {
        
    }
    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        ModelRanking modelRanking = (ModelRanking)target;

        if (GUILayout.Button("排序节点", new GUILayoutOption[] { GUILayout.ExpandWidth(false) }))
        {
            modelRanking.RankingChildren();
        }
}
}

其处理方式就是重写OnInspectorGUI函数,绘制一个排序节点的按钮,按钮事件绑定RankingChildren() 函数。 还有一点要在编辑器未运行下可执行排序,脚本上需要加上
[ExecuteInEditMode]。

测试场景

测试场景可以随意搭建一下,基于SampleScene新建一个空节点,新增几个Cube节点作为子节点:

Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)_第9张图片

在排序节点上添加上排序脚本,进行简单的配置后,点击排序节点按钮即可:
Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)_第10张图片

如果需要,在程序运行中进行排序,可以使用AddComponent()来添加组件,
添加后对其配置属性进行简单设置,以上步骤也可以预先添加设置好;然后调用==modelRanking.RankingChildren();==函数进行排序即可。

你可能感兴趣的:(Unity3D,c#,Unity拓展,Unity3d源码,Unity一键排序,Unity自定义编辑器)