0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UnityのSplineを設置するときのちょっとした便利ツールを作る

Last updated at Posted at 2024-05-18

パスに沿ってオブジェクトを動かすという動作を実装することになった。
その際にSplineを利用するということが決まったがその設定がかなりしんどい...。

例えば下の画像のように4つの座標で任意の輪っかを設定するとなった際にはそれぞれのKnotのPositionを1つずつ設定する必要がある。
image.png

これくらい簡単な図形ならまだよいが、例えば大きめの街に線路を引いて電車を走らせるみたいなことをする際にはきっと設定する座標も多く時間がかかってしまう...(超めんどくさかった!)

というわけで少し楽をできるようにスクリプトから生成するようにしたのがこちら。
image.png

何らかのTransformを配置し、その位置をもとにSplineを生成するというもので、例で上げた画像はわかりやすいようにCubeを設置して、その位置をもとにSplineを生成している。

座標を設定するという点では同じだが、こちらはオブジェクトのTransformを指定しての設定なので3Dマップを作るときなど普段の操作と同様の感覚で設定できるので楽なはず!

使い方はInspectorのSerializeFieldにパスの座標にするTransformと、SplineContainerをアタッチしてボタンを押すだけ!
デモ.gif

私は基準のSplineの外側にいくつか並走するラインを作りたかったので複数のSplineContainerを指定して設定幅分外側にもラインが引かれるような実装をしています。

(三本のラインが同心円上になるように設定してあるイメージ)
スクリーンショット 2024-05-18 20.00.11.png

以下はこの実装に利用したコードです。

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Splines;

/// <summary>
/// オブジェクトの位置を元にスプラインを生成するクラス
/// </summary>
public class CourseSplineSetter : MonoBehaviour
{
#if UNITY_EDITOR
    [SerializeField] private Transform[] _splinePoints;
    [SerializeField] private SplineContainer[] _splineContainers;
    [SerializeField] private float width = 10.0f;
    [SerializeField] private bool _isClosed = true;
    [SerializeField] private TangentMode _tangentMode = TangentMode.AutoSmooth;
    
    public void CreateSpline()
    {
        for (int i = 0; i < _splineContainers.Length; i++)
        {
            float offset = i * width; // 各パスの幅を設定
            List<Vector3> offsetPath = CalculateOffsetPath(_splinePoints, offset);
            CreateSplineFromPath(_splineContainers[i].Spline, offsetPath);
        }
    }
    
    private List<Vector3> CalculateOffsetPath(Transform[] points, float offset)
    {
        List<Vector3> offsetPath = new List<Vector3>();
        int pointCount = points.Length;

        for (int i = 0; i < pointCount; i++)
        {
            Vector3 prevPoint = points[(i - 1 + pointCount) % pointCount].transform.position;
            Vector3 currentPoint = points[i].transform.position;
            Vector3 nextPoint = points[(i + 1) % pointCount].transform.position;
            
            var toCurrent = (currentPoint - prevPoint).normalized;
            var toNext = (nextPoint - currentPoint).normalized;
            offsetPath.Add(currentPoint + (toCurrent - toNext) * offset);
        }
        return offsetPath;
    }

    void CreateSplineFromPath(Spline spline, List<Vector3> pathPoints)
    {
        spline.Clear();
        foreach (var point in pathPoints)
        {
            spline.Add(new BezierKnot(point));
        }

        spline.Closed = _isClosed;
        spline.SetTangentMode(_tangentMode);
        
        SceneView.RepaintAll();
    }
#endif
}

#if UNITY_EDITOR
[CustomEditor(typeof(CourseSplineSetter))]
public class CourseSplineSetterWindow : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        var setter = target as CourseSplineSetter;
        // Inspector上でボタンを表示
        if (!EditorApplication.isPlaying && GUILayout.Button("Create Spline"))
        {
            setter.CreateSpline();
        }
        
    }
}
#endif
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?