Bearded Multi-Headed Instantiation Dragoon Question

If I wanted to: (sorry for the complicated question)

  1. instantiate a sphere prefab with a name, a random position, and a random size
  2. instantiate a button for it on a scroll view
  3. on click of set button, make my only camera look at the sphere prefab I just instantiated
  4. while also on click, travel to the instantiated sphere prefab
  5. and end up at the same transform of the previous object,relative to the new one

I have conquered instantiating the sphere prefab with its random specifications.
I can currently add a button prefab with the same sphere prefab name to an existing scroll view by the use of a list, a sphere prefab class, and a button prefab class.
I would like to add a generic function to satisfy requirement 3, 4, and 5 in my button prefab onClick so it is linked to the new sphere prefab I have just instantiated. To make this all the more complicated I am instantiating 1000 of these sphere prefabs in a 3D environment at run time.

public GameObject mainCamera;
public float transitionSpeed;
public float startTime = 1.0f;

//the newSphere is the instantiated sphere prefab
public void SphereButtonClick(GameObject newSphere)
    {
        Transform newSphereTrans = newSphere.transform;
        Vector3 sphereToZoomToPos = newSphereTrans.position;
        float sphereToZoomToX = sphereToZoomToPos.x;
        float sphereToZoomToY = sphereToZoomToPos.y;
        float sphereoZoomToZ = sphereToZoomToPos.z;

        Transform mainCameraTrans = mainCamera.transform;
        mainCameraTrans.SetParent(newSphereTrans);
        mainCameraTrans.LookAt(newSphereTrans);
        float lerpXValue = Mathf.Lerp(0, sphereToZoomToX, (Time.time - startTime) * transitionSpeed);
        float lerpYValue = Mathf.Lerp(0, sphereToZoomToY, (Time.time - startTime) * transitionSpeed);
        float lerpZValue = Mathf.Lerp(0, sphereToZoomToZ, (Time.time - startTime) * transitionSpeed);
        mainCameraTrans.position = new Vector3(lerpXValue, lerpYValue, lerpZValue);
    }

This is my camera movement function but I can’t get it to work. I have attempted to slide it into the onClick of the button prefab as both a separate class and as a part of another but when I bring up the class the function does not exist. Is my function for onClick not allowed to take in a GameObject? If not, how would I take my instantiated sphere prefab game object (which has its own sphere prefab class) (and is also in a list that displays on the aforementioned scroll view) and link it to the main camera through an also instantiated button onClick?

My Sphere Prefab Class:

public class SpherePrefab : MonoBehaviour
{
    public GameObject sphereInScene;
    public Text SphereName;
}

And my Button prefab Class:

public class ButtonPrefab : MonoBehaviour {

    public Button button;
    public Text sphereName;

}

First of all we can start with SphereFactory (singleton):
public void SphereFactory: MonoBehaviour
{
public event Action SphereCreatedListeners;

	public void CreateNew()
	{
		//Create Vector3 random position
		//Create Vector3 random size
		var newObject = Instantiate(prefab, position);
		newObject.transform.localScale = randomScale;
		
		SphereCreatedListeners?.Invoke(newObject); //Assuming you are using C# 6.0
	}
}

Next, we can create ButtonFactory (singleton):

public void ButtonFactory: MonoBehaviour
{
	public event Action<GameObject> SphereClickedListeners;
	
	void Start()
	{
		SphereFactory.Instance.SphereCreatedListeners += OnSphereCreated;
	}
	
	private void OnSphereCreated(GameObject sphere)
	{
		var newButton = Instantiate(prefab, gridLayout);
		newButton.onClick.AddListener(() => SphereAction(sphere));
	}
	
	private void SphereAction(GameObject sphere)
	{
		SphereClickedListeners?.Invoke(sphere); //C# 6.0
	}
	
	void OnDestroy()
	{
		SphereFactory.Instance.SphereCreatedListeners -= OnSphereCreated;
	}
}

Finally CameraController basend on your code:

public void CameraController: MonoBehaviour
{
	private Transform target;
	
	void Start()
	{
		ButtonFactory.Instance.SphereClickedListeners += OnSphereClicked;
	}
	
	private void OnSphereClicked(GameObject sphere)
	{
		target = sphere.transform;
	}
	
	private void NavigateTo(GameObject target)
	{
		Vector3 sphereToZoomToPos = target.position;
		float sphereToZoomToX = sphereToZoomToPos.x;
		float sphereToZoomToY = sphereToZoomToPos.y;
		float sphereoZoomToZ = sphereToZoomToPos.z;

		Transform mainCameraTrans = mainCamera.transform;
		mainCameraTrans.SetParent(newSphereTrans);
		mainCameraTrans.LookAt(newSphereTrans);
		float lerpXValue = Mathf.Lerp(0, sphereToZoomToX, (Time.time - startTime) * transitionSpeed * time.deltaTime);
		float lerpYValue = Mathf.Lerp(0, sphereToZoomToY, (Time.time - startTime) * transitionSpeed * time.deltaTime);
		float lerpZValue = Mathf.Lerp(0, sphereToZoomToZ, (Time.time - startTime) * transitionSpeed * time.deltaTime);
		mainCameraTrans.position = new Vector3(lerpXValue, lerpYValue, lerpZValue);
	}
	
	void Update()
	{
		if(target == null) return;
		
		NavigateTo(target);
	
		if(HasArrived())
		{
			target = null;
		}
	}
	
	private bool HasArrived()
	{
		return target != null && (target.position - mainCamera.position).magnitude <= 0.1f;
	}
	
	void OnDestroy()
	{
		ButtonFactory.Instance.SphereClickedListeners -= OnSphereClicked;
	}
}

I have missed some fields, methods and basic singleton pattern, but I hope you get the point :slight_smile: I don’t like idea of having sphere action in button factory (it should be defined in sphere script, like OnButtonClickAction).