You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity:实现MoveController支持运行时添加多个实例化预制体

问题描述

我有一套基于LeanTween的Unity脚本,可将预制体沿预设路径移动且运行正常。当前MoveController仅能绑定一个挂载Moveable脚本的对象,但我需要让运行时实例化的新预制体也能加入MoveController,跟随路径运动,求实现方法。

原代码

Moveable脚本(同时负责实例化预制体)

public class Moveable : MonoBehaviour
{
    [SerializeField] private float _speedMetersPerSecond = 25f;

    private Vector3? _destination;
    private Vector3 _startPosition;
    private float _totalLerpDuration;
    private float _elapsedLerpDuration;
    private Action _onCompleteCallback;
    public GameObject Electron;

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            var NextOnPath = Instantiate(Electron, transform.position, Quaternion.identity);
            NextOnPath.AddComponent<Moveable>();
        }

        if (_destination.HasValue == false)
            return;

        if (_elapsedLerpDuration >= _totalLerpDuration && _totalLerpDuration > 0)
            return;

        _elapsedLerpDuration += Time.deltaTime;
        float percent = (_elapsedLerpDuration / _totalLerpDuration);
        Debug.Log($"{percent} = {_elapsedLerpDuration} / {_totalLerpDuration}");

        transform.position = Vector3.Lerp(_startPosition, _destination.Value, percent);
    }

    public void MoveTo(Vector3 destination, Action onComplete = null)
    {
        var distanceToNextWaypoint = Vector3.Distance(transform.position, destination);
        _totalLerpDuration = distanceToNextWaypoint / _speedMetersPerSecond;

        _startPosition = transform.position;
        _destination = destination;
        _elapsedLerpDuration = 0f;
        _onCompleteCallback = onComplete;
    }
}

MoveController脚本

using System.Linq;

public class MoverController : MonoBehaviour
{
    [SerializeField] private Moveable target;
    private List<Transform> _waypoints;
    private int _nextWaypointIndex;


    private void OnEnable()
    {
        _waypoints = GetComponentsInChildren<Transform>().ToList();
        _waypoints.RemoveAt(0);
        MoveToNextWaypoint();
    }

    private void MoveToNextWaypoint()
    {
        var targetWaypointTransform = _waypoints[_nextWaypointIndex];
        target.MoveTo(targetWaypointTransform.position, MoveToNextWaypoint);
        target.transform.LookAt(_waypoints[_nextWaypointIndex].position);
        _nextWaypointIndex++;

        if (_nextWaypointIndex >= _waypoints.Count)
            _nextWaypointIndex = 0;
    }
}

解决方案

修改后的Moveable脚本(关键部分)

public class Moveable : MonoBehaviour
{
    [SerializeField] private float _speedMetersPerSecond = 25f;
    public List<Moveable> moveables = new List<Moveable>();
    private Vector3? _destination;
    private Vector3 _startPosition;
    private float _totalLerpDuration;
    private float _elapsedLerpDuration;
    private Action _onCompleteCallback;
    public GameObject Electron;

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // 实例化并获取Moveable组件(建议预制体直接挂载Moveable,避免动态添加)
            Moveable NextOnPath = Instantiate(Electron, transform.position, Quaternion.identity).GetComponent<Moveable>();
            moveables.Add(NextOnPath);
            // 通过单例将新对象加入控制器的目标列表
            MoverController.instance.targets.Add(NextOnPath);
        }

        // 保留原Update中的移动逻辑,此处省略重复代码
    }

    // 保留原MoveTo方法,此处省略重复代码
}

修改后的MoveController脚本(关键部分)

using System.Linq;
using System.Collections.Generic;

public class MoverController : MonoBehaviour
{
    public List<Moveable> targets;
    [SerializeField] private Moveable initialTarget;
    private List<Transform> _waypoints;
    private int _nextWaypointIndex;
    public static MoverController instance;

    private void Awake()
    {
        // 实现单例模式,确保全局可访问
        instance = this;
        // 初始化目标列表,加入初始绑定的对象
        targets = new List<Moveable>();
        if(initialTarget != null)
            targets.Add(initialTarget);
    }

    private void OnEnable()
    {
        _waypoints = GetComponentsInChildren<Transform>().ToList();
        _waypoints.RemoveAt(0);
        MoveToNextWaypoint();
    }

    private void MoveToNextWaypoint()
    {
        var targetWaypointTransform = _waypoints[_nextWaypointIndex];
        // 遍历所有目标,同步发送移动指令
        foreach(var moveable in targets)
        {
            moveable.MoveTo(targetWaypointTransform.position, MoveToNextWaypoint);
            moveable.transform.LookAt(targetWaypointTransform.position);
        }
        // 所有目标完成当前点移动后,再切换到下一个路径点
        _nextWaypointIndex++;
        if (_nextWaypointIndex >= _waypoints.Count)
            _nextWaypointIndex = 0;
    }
}

核心修改说明

  • 将MoveController中单个目标改为List<Moveable> targets,用于存储所有需要跟随路径的对象
  • 给MoveController实现单例模式,让运行时实例化的对象能直接访问并加入目标列表
  • 调整MoveToNextWaypoint方法逻辑:先获取当前路径点,遍历所有目标发送移动指令后再递增路径索引,确保所有对象同步走同一个路径点(修复原方案中每个目标走不同路径点的bug)
  • 在Moveable的实例化逻辑中,将新创建的对象加入控制器的目标列表

内容的提问来源于stack exchange,提问作者SChen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 07:45:19