Home > Back-end >  Assigning multiple prefabs to a script which only allows one to be added
Assigning multiple prefabs to a script which only allows one to be added

Time:12-29

I have a script where it puts an object (premade) onto a premade path using LeanTween which works fine.

The way this works is you can assign one object to the "path adder" (MoveController) that has the Moveable script attached to it.

However, I need to be able to add new prefabs made during runtime to the MoveController so they follow the path.

So how would I go about making instantiated objects attach to the MoveController during runtime.

Thank you.

Moveable script, also instantiates the prefabs

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 script

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;
        
    }
}

Premade object MoveController typically uses

Where MoveController is attached and inspector

Let me know if I need to clarify anything.

I understand this is quite a loaded question but I would greatly appreciate any help!

Solution

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 NextOnPath = Instantiate(Electron, transform.position, Quaternion.identity).GetComponent<Moveable>();
            moveables.Add(NextOnPath.GetComponent<Moveable>());
            MoverController.instance.targets.Add(NextOnPath.GetComponent<Moveable>());
        }
}
}

MoveController:

public List<Moveable> targets;
    [SerializeField] private Moveable target;
    private List<Transform> _waypoints;
    private int _nextWaypointIndex;
    public static MoverController instance;
private void MoveToNextWaypoint()
    {
        for (int i = 0; i < targets.Count; i  )
        {
            var targetWaypointTransform = _waypoints[_nextWaypointIndex];
            targets[i].MoveTo(targetWaypointTransform.position, MoveToNextWaypoint);
            targets[i].transform.LookAt(_waypoints[_nextWaypointIndex].position);
            _nextWaypointIndex  ;

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

Note: Only the changed parts are displayed in the solution

CodePudding user response:

Yes, if you use an Array then you can add as many prefabs as you want. You will still need to set the code in the script to handle multiple prefabs.

Although, it sounds like you might not understand the basics for C# and Unity and you might like to take a class, read a tutorial or watch a Youtube video.


Update

Because your question is so broad, I cannot just give you the code. That's something you should pay a coder for. But I will tell you the general ideas of what will need to be done.
  1. In the Moveable class, you need to track your var NextOnPath after instantiating them. A great way to do this (As long as you don't plan to convert anything to JSON) would be with a List<>. For example:

    List<Moveable> moveables = new List<Moveable>();
    
    void Update()
    {
        //Some code before - with instantiation
        //It is best to track items by the script that you will use since you can just use moveables[i].gameObject to access the gameObject and moveables[i].transform to access transform
        moveables.Add(NextOnPath.GetComponent<Moveable>());
        //Some code after
    }
    
  2. You might save computing power by adding the Moveable script to your Electron prefab so you use: Moveable nextOnPath = Instantiate(electron, transform.position, Quaternion.identity).GetComponent<Moveable>();

  3. Look up Singleton, you can use this to assign values to your MoverController class easily:

public static MoverController instance;
void Awake()
{
    if (instance == null)
    {
        instance = this;
    }
    else
    {
        Destroy(gameObject);
        return;
    }

    DontDestroyOnLoad(gameObject);
}

Then in the Moveable class simply add it to MoverController

//Requires changing the above code

    void Update()
    {
        //Some code before - with instantiation
        MoverController.instance.targets.Add(NextOnPath.GetComponent<Moveable>());
        //Some code after
    }
  • Related