1
1

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 - 關於簡化移動的系統 "Splines"

Posted at

注意
此處提供的資訊可能會有所變更,請以官方資訊為準。
本文針對的是 Ver.2.7(功能可能沒有太大的變化)。

image.png1


關於 Splines 的閒聊

Splines 是 Unity 官方套件中的一項功能。它於 2022 年 1 月首次發布,至本文撰寫時(2025 年 3 月),已更新至 Ver.2.8。
據說,曾經有許多要求希望將其作為標準功能進行搭載。

很多用戶早就希望這項功能能作為標準功能提供,終於現在成為官方套件了!2

開始使用 Spline

首先,安裝 Spline。打開套件管理器(Package Manager),搜尋 Splines
您應該會看到如下畫面,點擊紅框中的 Install 按鈕即可。(由於我已經導入了 Splines,因此顯示的畫面可能不同。)
Screenshot 2025-03-23 173833.png

導入後,右鍵點擊層級窗口(Hierarchy),或者從 GameObject 中選擇 Spline > New Spline,在場景中繪製 Spline,按下 Enter 鍵即可完成。
更詳細的方法請參考

沿著 Spline 移動物件

若要沿著 Spline 移動物件:

  1. 點擊想移動的物件 Inspector 標籤的 Add Component 按鈕,搜尋 Spline Animate
  2. 在 Spline 的選項中,附加剛才繪製的 Spline。

執行後,物件應該就會沿著 Spline 移動了。3

自己編寫腳本

在上一節中,我們使用的是預先編寫好的腳本來移動物件。但如何自己編寫腳本,讓物件沿著 Spline 移動呢?讓我們開始吧!

使用腳本來移動 Spline4

以下是一段基本腳本,用於讓物件沿著 Spline 移動:

SplineSystem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Splines;

public class SplineSystem : MonoBehaviour
{
    [SerializeField] private SplineContainer splineContainer;
    [SerializeField] private Transform _followTarget; // 將希望追隨 Spline 的物件(準確來說是位置資訊:transform)添加到這裡。
    [SerializeField] private float SplinesPercentage;
    [SerializeField] private Vector3 AddUpPosition; // 附加功能。

    void Update()
    {
        if (splineContainer == null || _followTarget == null)
            return;

        // 更新位置。
        Vector3 position = splineContainer.EvaluatePosition(SplinesPercentage);

        position += AddUpPosition; // 加上指定的向量(若為負值則減去)。

        _followTarget.position = position;

        // 更新旋轉。
        Vector3 tangent = ((Vector3)splineContainer.EvaluateTangent(SplinesPercentage)).normalized;
        Vector3 up = ((Vector3)splineContainer.EvaluateUpVector(SplinesPercentage));
        _followTarget.rotation = Quaternion.LookRotation(tangent, up);
    }
}

注意
當從腳本中操作 Spline 時,請務必添加以下語句:

using UnityEngine.Splines;

如果對腳本中的 [SerializeField] 感到疑惑,可參考

修改 SplinePosition 的值應該可以移動物件,並且 Spline 的旋轉效果應該也會被應用。
至於具體機制,請參考

擴展上一個腳本

這裡將介紹:
1️⃣ 輸入從 Spline 起點開始的距離後,將物件移動到該位置的腳本。
2️⃣ 指定速度(km/h),讓物件以該速度在 Spline 上移動的腳本。

擴展腳本:Part 1️⃣

上一個腳本是以比例計算位置的。
這意味著,如果能知道 Spline 的總長度,是否能計算從起點開始的距離呢?

計算 Spline 長度的函數是:

CalculateLength();

以下是範例腳本:

SplineSystem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Splines;

public class SplineSystem : MonoBehaviour
{
    [SerializeField] private SplineContainer splineContainer;
    [SerializeField] private Transform _followTarget;
    private float SplinesPercentage; // 更改:完全私有化。
    [SerializeField] private float SplineLength_Position; // 添加:輸入從 Spline 起點開始的距離。
    /*[SerializeField]*/ private float SplineLength; // 添加:獲取指定 Spline 長度的變數。
    [SerializeField] private Vector3 AddUpPosition;
    [SerializeField] private float AddLength; // 附加功能。
    public TrainSystem trainSystem;

    void Start()
    {
        SplineLength = splineContainer.CalculateLength(); // 添加:獲取指定 Spline 的長度。
    }

    void Update()
    {
        if (splineContainer == null || _followTarget == null)
            return;
        
        SplinesPercentage = (SplineLength_Position + AddLength) / SplineLength; // 添加:將距離轉換為比例,並分配給位置變數。

        // 更新位置。
        Vector3 position = splineContainer.EvaluatePosition(SplinesPercentage);

        position += AddUpPosition; // 加上指定的向量(若為負值則減去)。

        _followTarget.position = position;

        // 更新旋轉。
        Vector3 tangent = ((Vector3)splineContainer.EvaluateTangent(SplinesPercentage)).normalized;
        Vector3 up = ((Vector3)splineContainer.EvaluateUpVector(SplinesPercentage));
        _followTarget.rotation = Quaternion.LookRotation(tangent, up);
    }
}

以下是 Part 2️⃣ 的續篇翻譯:


擴展腳本:Part 2️⃣ (續)

SplineSystem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Splines;

public class SplineSystem : MonoBehaviour
{
    [SerializeField] private SplineContainer splineContainer;
    [SerializeField] private Transform _followTarget;
    private float SplinesPercentage;
    [SerializeField] private float SplineLength_Position;
    /*[SerializeField]*/ private float SplineLength;
    [SerializeField] private Vector3 AddUpPosition;
    [SerializeField] private float AddLength;
    [SerializeField] private float ObjectSpeed; // 添加:輸入速度(km/h)。

    void Start()
    {
        SplineLength = splineContainer.CalculateLength();
    }

    void Update()
    {
        if (splineContainer == null || _followTarget == null)
            return;

        SplineLength_Position += (ObjectSpeed * (1000f / 3600f)) * Time.deltaTime; // 添加:將 km/h 換算為 m/s 並計算。

        SplinesPercentage = (SplineLength_Position + AddLength) / SplineLength;

        // 更新位置。
        Vector3 position = splineContainer.EvaluatePosition(SplinesPercentage);

        position += AddUpPosition; // 加上指定的向量(若為負值則減去)。

        _followTarget.position = position;

        // 更新旋轉。
        Vector3 tangent = ((Vector3)splineContainer.EvaluateTangent(SplinesPercentage)).normalized;
        Vector3 up = ((Vector3)splineContainer.EvaluateUpVector(SplinesPercentage));
        _followTarget.rotation = Quaternion.LookRotation(tangent, up);
    }
}

以上腳本中,// 添加 的部分是新增的代碼,用於支持以 km/h 計算移動速度並更新位置。
這樣,您可以根據自己的需求輕鬆控制物件的移動速度。


再次閒聊

感謝各位讀到這裡!我個人的近況是剛剛完成學校的畢業典禮,寫這篇文章時正悠閒地放鬆著。
接下來要準備考試了,感覺有點崩潰,但還是要努力。
不管是小學生、初中生還是高中生,要考試的朋友們,一起加油吧!

完結!
translated with Bing AI

  1. 画像・參考網站:Unity 2022.2 の Splines を使って、フロー狀態でより美しいパスを描き出そう

  2. 引用:Unity 2022 新機能!スプラインを使ってみよう! - YouTube

  3. 詳細方法請參考:【Unity2022】スプラインツールの導入方法と使い方|ねこじゃらシティ

  4. 參考網站:【Unity2022】スプラインをスクリプトから扱う方法|ねこじゃらシティ

1
1
3

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?