0
\$\begingroup\$

I have an object meant to represent a player that I'd like to spawn in at runtime. Because it is instantiated at runtime, I'm not sure about how to get the main camera in my scene to follow the instance of the player object.

In a camera script (which is attached to the camera), I have the following:

public Transform cameraTarget; // i.e. the player's transform component
public Transform cameraLocation;
private int offset = -10;
//...

private void TrackTarget();
{
    transform.position = new (cameraTarget.transform.position.x,
                              cameraTarget.transform.position.y,
                              cameraTarget.transform.position.z + offset);
}

In a separate game manager script, I'm instantiating the player, then attempting to "assign" the camera to it like so:

public Player player;
public Camera mainCamera;

private void Start()
{
    InstancePlayer();
    player.transform = mainCamera.cameraTarget;
}

private void Update()
{
    if (mainCamera.cameraTarget != null)
    {
        mainCamera.TrackTarget();
    }
}

private void InstancePlayer()
{
    Vector2 startLocation = Vector2.zero; // using `Vector2.zero` as a placeholder for now
    Instantiate(player, startLocation, Quaternion.identity);
}

Perhaps unsurprisingly, this is not a working solution (or if it is, I'm missing how to implement it properly), so to resummarize the question: how might I make the camera follow my instanced player object?

EDIT: Possible clarification -- the player instantiates and shows up in the Unity hierarchy as "Player(Clone)" when the game is running. I think that, if I understand what I'm doing, I'm trying to target the clone with the camera and have the camera follow after successfully obtaining a target, in this case.

EDIT 2: After consulting this StackOverflow post (https://stackoverflow.com/questions/67037208/is-there-any-way-to-assign-player-to-camera-after-the-game-started-in-unity), I attempted the first suggested method, and initially did not find success with what I had above, so I reattempted in a separate project using similar code:

public class Player : MonoBehaviour
{
    // some code to control movement
}
public class CameraController : MonoBehaviour
{
    public Transform cameraTarget;
    public Player player;
    private readonly int offset = -10;

    public void AssignTarget(Player player)
    {
        this.player = player;
        cameraTarget = player.GetComponent<Transform>();
    }

    // I initially made this function private and didn't notice...oops!
    public void TrackTarget()
    {
        transform.position = new (cameraTarget.transform.position.x,
                                  cameraTarget.transform.position.y,
                                  cameraTarget.transform.position.z + offset);
    }
}
public class GameManager : MonoBehaviour
{
    public GameObject player;
    public CameraController camController;
    
    private void Start()
    {
        InstancePlayer();
        camController.AssignTarget(camController.player);
    }
    
    private void Update()
    {
        if (camController.cameraTarget != null)
        {
            camController.TrackTarget();
        }
    }

    private void InstancePlayer()
    {
        Vector2 startPosition = Vector2.zero;
        GameObject myPlayer = Instantiate(player, startPosition, Quaternion.identity);
        camController.player = myPlayer.GetComponent<Player>();
    }
}

This solution obtains both a clone of the transform and a clone of the script component belonging to the Player prefab, although I think that only the clone of the transform is necessary to get it working. I'll be completely honest, though--I don't entirely understand why this works, and I'm not confident that it's as concise as it could be (i.e. there may be extraneous code that doesn't really get used). What I think I have figured out is that it might have been necessary to use GetComponent<>() to obtain the clone of the transform from the prefab.

In any case, here's an example of how the camera follows the instantiated Player object, along with some reference images:

a gif where a white circle sprite is followed by a main camera in a blue scene with red dots placed in it to indicate movement

a runtime capture of the main camera with Camera Controller component attached, evidencing that it obtains the Player prefab's transform clone and Player component clone, respectively

a runtime capture of the game manager object with the Game Manager component attached, showing that it accepts the Player prefab and the main camera with Camera Controller component attached

\$\endgroup\$
8
  • 2
    \$\begingroup\$ Although I was able to answer your question, when you have something that "is not a working solution", you should describe what's specifically gone wrong (e.g. specific error messages that you've encountered). \$\endgroup\$
    – Kevin
    Commented Apr 26 at 1:05
  • \$\begingroup\$ While it is certainly possible to do this using scripting, I would recommend you to look into Cinemachine. It contains a "follow" mode for cameras to automatically follow a game object (or a group of game objects as a "target group") and many more useful features to give your game really cool camera controls with almost no scripting required. \$\endgroup\$
    – Philipp
    Commented Apr 26 at 8:17
  • \$\begingroup\$ @Kevin I would have included error messages, but that's part of the issue: I'm not receiving error messages (and yes, they are turned on in the console). I'll take a look at your answer here in just a moment--I do get the feeling that it was probably something as stupid as failing to order things properly, as you suggested. \$\endgroup\$
    – NJJ_002
    Commented Apr 26 at 15:41
  • 1
    \$\begingroup\$ @NJJ_002 Your original code has multiple syntax errors which should have caused the compiler to throw error messages and prevented you from testing. If you were not getting errors, then something is wrong with your project or the way you've added your code to the project. \$\endgroup\$
    – Kevin
    Commented Apr 26 at 22:02
  • \$\begingroup\$ Or, if the code you posted is not your original code - don't do that. We can't help you if you rewrite the code for your post and your rewritten code has different mistakes than the original code. \$\endgroup\$
    – Kevin
    Commented Apr 26 at 22:07

1 Answer 1

0
\$\begingroup\$

Camera is the name of a built-in component in Unity. You should not name your component Camera, and you should refer to your component by its type.

public class FollowCamera : MonoBehaviour {
    public Transform cameraTarget // i.e. the player's transform component
    public Transform cameraLocation
    private int offset = -10;

    private void Update() {
        if (cameraTarget == null) return;
        transform.position = new Vector3(cameraTarget.transform.position.x,
                                  cameraTarget.transform.position.y,
                                  cameraTarget.transform.position.z + offset);
    }
}

You can assign the target like this:

public FollowCamera mainCamera; // Note the type.

private void Start() {
    InstancePlayer();
    mainCamera.cameraTarget = player.transform; // Note the order.
}

Also, take note that you had the original assignment statement backwards:

player.transform = mainCamera.cameraTarget;

This is trying to assign the value of mainCamera.cameraTarget to the player.transform property, which is an invalid operation since transform is a read-only property.

\$\endgroup\$
4
  • \$\begingroup\$ So here's the issue that I'm having now: it looks like all of the references are assigned properly and everything is ordered correctly, but the camera does not move with the player, and there are no generated error messages. Any idea why? \$\endgroup\$
    – NJJ_002
    Commented Apr 26 at 16:36
  • \$\begingroup\$ To clarify, I've also been using Debug.Log() to try to suss out why this is the case, and the messages are all populating in the console when they should. \$\endgroup\$
    – NJJ_002
    Commented Apr 26 at 16:48
  • \$\begingroup\$ @NJJ_002 The FollowCamera component must be attached to the same GameObject as the Unity Camera component. In FollowCamera's Update() method, add Debug.Log(cameraTarget.transform.position.ToString()). Also take note that your original code was missing the Vector3 constructor; I've added that. \$\endgroup\$
    – Kevin
    Commented Apr 26 at 22:05
  • \$\begingroup\$ The FollowCamera component was attached as you specified. As an aside, I’ve been using Visual Studio 2022, and I kept getting a message (something like “new statement can be simplified”) which seemed to indicate that the Vector3 constructor was unnecessary—I’m guessing that it’s because the structure (float, float, float) is automatically interpreted as a Vector3, but not sure if that’s why; either way, it was working as intended. \$\endgroup\$
    – NJJ_002
    Commented Apr 27 at 12:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .