Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Character prefab loosing references when spawned. (I know this is normal behavior)

Discussion in 'Scripting' started by brettnorton64, Nov 24, 2022.

  1. brettnorton64

    brettnorton64

    Joined:
    Sep 28, 2021
    Posts:
    6
    Hi, I'm creating a 2d runner game where the camera follows the player, i have 3 prefab characters which you choose at the main menu, but when the game starts the camera loses the reference to the player and won't follow. I know this is normal, but I can't figure out how to implement this. any help would be greatly appreciated.



    //THIS SCRIPT IS ATTACHED TO MAIN MENU SCENE - CANVAS - CHARACTER SELECTION GRID THAT I CREATED.
    ----------------------------------------------------------------------------------------------------------

    Code (CSharp):
    1. public class CharacterSelectionUI : MonoBehaviour
    2. {
    3.     public GameObject optionPrefab;
    4.  
    5.     public Transform prevCharacter;
    6.     public Transform selectedCharacter;
    7.  
    8.  
    9.  
    10.  
    11.     private void Start()
    12.     {
    13.  
    14.  
    15.         foreach (Character c in MenuManager.instance.characters)
    16.         {
    17.  
    18.             GameObject option = Instantiate(optionPrefab, transform);
    19.             Button button = option.GetComponent<Button>();
    20.  
    21.  
    22.             button.onClick.AddListener(() =>
    23.             {
    24.                 MenuManager.instance.SetCharacter(c);
    25.                 if (selectedCharacter != null)
    26.                 {
    27.                     prevCharacter = selectedCharacter;
    28.                 }
    29.  
    30.                 selectedCharacter = option.transform;
    31.  
    32.          
    33.             });
    34.  
    35.      
    36.  
    37.  
    38.             Text text = option.GetComponentInChildren<Text>();
    39.             text.text = c.name;
    40.  
    41.             Image image = option.GetComponentInChildren<Image>();
    42.             image.sprite = c.icon;
    43.  
    44.         }
    45.  
    46.     }
    47.  
    48.  
    49.  
    50.     private void Update()
    51.     {
    52.         if(selectedCharacter != null)
    53.         {
    54.             selectedCharacter.localScale = Vector3.Lerp(selectedCharacter.localScale, new
    55.                 Vector3(1.2f, 1.2f, 1.2f), Time.deltaTime * 10);
    56.         }
    57.  
    58.         if (prevCharacter != null)
    59.         {
    60.             prevCharacter.localScale = Vector3.Lerp(prevCharacter.localScale, new
    61.                 Vector3(1f, 1f, 1f), Time.deltaTime * 10);
    62.         }
    63.  
    64.     }
    65.  
    66. }
    67.  









    //THIS SCRIPT IS ATTACHED TO A EMPTY GAME OBJECT IN PLAY MODE.
    --------------------------------------------------------------------------------------------

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3.  
    4.  
    5.  
    6. public class PlayerSpawnScript : MonoBehaviour
    7. {
    8.  
    9.     void Start()
    10.     {
    11.         Instantiate(MenuManager.instance.currentCharacter.prefab, transform.position, Quaternion.identity);
    12.      
    13.     }
    14.  
    15. }









    //THIS SCRIPT IS ATTACHED TO THE MAIN CAMERA IN PLAY MODE.
    ----------------------------------------------------------------------------------------------------------------

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CameraScript : MonoBehaviour
    6. {
    7.  
    8. public PlayerController thePlayer;
    9.  
    10. public Vector3 lastPlayerPosition;
    11.  
    12.  
    13. public float distanceToMove;
    14.  
    15.  
    16.  
    17.  
    18. void Start()
    19. {
    20. thePlayer = FindObjectOfType<PlayerController>();
    21. lastPlayerPosition = thePlayer.transform.position;
    22. }
    23.  
    24.  
    25. void Update()
    26. {
    27.  
    28. distanceToMove = thePlayer.transform.position.x - lastPlayerPosition.x;
    29.  
    30. transform.position = new Vector3(transform.position.x + distanceToMove, transform.position.y, transform.position.z);
    31.  
    32. lastPlayerPosition = thePlayer.transform.position;
    33.  
    34. }
    35. }
     
    Last edited: Nov 25, 2022
  2. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,850
    Use code formatting from the toolbar. I would have helped you but am not wading thru that looking for breaks and open->close brackets.
     
  3. brettnorton64

    brettnorton64

    Joined:
    Sep 28, 2021
    Posts:
    6
    Hi, I'm new to this, it's my first time posting for help, I have edited the post I hope this is what you meant.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,515
    Camera stuff is pretty tricky... you may wish to consider using Cinemachine from the Unity Package Manager.

    There's even a dedicated forum: https://forum.unity.com/forums/cinemachine.136/

    Otherwise, make sure you give the camera the reference to the player. I don't see you doing that above. For instance, your PlayerSpawnScript simply Instantiates the player, does nothing with the value Instantiate() returns.
     
  5. brettnorton64

    brettnorton64

    Joined:
    Sep 28, 2021
    Posts:
    6
    Yes, sorry your right i believe that PlayerSpawnScript can be removed this does nothing, what I'm trying to achieve in a simple question is how do i make the camera follow the selected prefab character. as the drag and drop references disappear.

    This one feels like the answer is really simple but i can't get my head around. I will see if cinemachine has a feature i can use.

    appreciate your input.

    [INVALID SCRIPT NOW REMOVED FROM ORIGINAL POST]
     
    Last edited: Nov 24, 2022
  6. oceanofsoftwares3

    oceanofsoftwares3

    Joined:
    Nov 17, 2021
    Posts:
    3
    Alright So I haven't actually seen your code but after reading out your problem, I would like to say that the prefabs that you have. Like the Player Prefabs. You should make a script named player prefab. I think you would already have one. If not, then make one. And after doing that, go to the camera script and where you've put the reference of the character, Just use this line of code:


    void Start()
    {
    selectedCharacter = GameObject.FindObjectOfType<Your Player Script Name>().transform;
    }



    And that should do all of your work by itself. I hope this works. Let me know your feedback.

    Thank You
    Mudassar Ali :)
     
  7. brettnorton64

    brettnorton64

    Joined:
    Sep 28, 2021
    Posts:
    6
    Hi, all of the suggestions so far are already done in the scripts, if i were to insert the player prefab into the scene and drag the player into the camera reference. the game plays fine and all works well.

    but if i start the game from the main menu and have no player already in the scene and instantiate the selected character from the main menu, then the camera loses its reference. and the camera won't follow the player prefab. even with this line of code in the camera.

    thePlayer = FindObjectOfType<PlayerController>();

    I'm assuming this is caused because all 3 of the playable characters share the same player script, and the cameras reference to the player script is not using the active one in the scene. I don't know.
     
  8. brettnorton64

    brettnorton64

    Joined:
    Sep 28, 2021
    Posts:
    6
    This is the error code - NullReferenceException: Object reference not set to an instance of an object

    CameraScript.Start () (at Assets/Scripts/CameraScript.cs:25)
     
  9. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    Give your prefab spawner a reference to your camera script.
    After instantiating the prefab use the camera script reference to call a method on it that takes the spawned prefab as an argument.
    Use this method to initialize the camera script.
     
  10. brettnorton64

    brettnorton64

    Joined:
    Sep 28, 2021
    Posts:
    6
    Hi thanks for the reply, i see what you're saying but im not sure how that would look in code.

    i need the camera to have the spawned prefabs script & position.
    the camera is looking for these two lines.

    public PlayerController thePlayer;
    public Vector3 lastPlayerPosition;




    Code (CSharp):
    1. public class PlayerSpawnScript : MonoBehaviour
    2. {
    3.  
    4.  
    5.     public CameraScript theCameraScript;
    6.  
    7.  
    8.  
    9.     void Start()
    10.     {
    11.         theCameraScript = FindObjectOfType<CameraScript>();
    12.  
    13.  
    14.         Instantiate(MenuManager.instance.currentCharacter.prefab, transform.position, Quaternion.identity);
    15.        
    16.  
    17.         theCameraScript.thePlayer = "how do i give the camera the new spawned player game object"
    18.         theCameraScript.lastPlayerPosition = "how do i give the camera script the new spawned player postition here"
    19.  
    20.  
    21.     }
    22.  
    23. }
     
  11. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    Is PlayerSpawnScript and CameraScript not in the same scene? Can you not drag the reference between those in the inspector?

    Instantiate returns a reference to the thing that was spawned. You can pass this along to your camera script, example below(not complete, no copyPaste, you will need to create SetPlayer yourself)


    Code (csharp):
    1. GameObject spawnedPlayer =  Instantiate(MenuManager.instance.currentCharacter.prefab, transform.position, Quaternion.identity);
    2.  
    3. theCameraScript.SetPlayer(spawnedPlayer);
     
  12. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,850
    For following a player with the camera. Simply put a camera positioner inside the character prefab at the position you would prefer it. Place another target object inside the player prefab as the cameraTarget. Now Lerp the camera from it's current position to the cameraPositioner at each frame. It will never quite catch up until you stop moving but should smoothly lerp from current to next position.

    Code (CSharp):
    1. public Transform camTarget;
    2. public Transform camPositioner;
    3. public Transform camT;
    4. public float lerpSpeed = 10.0f;
    5.  
    6. void Update () {
    7.      camT.position = Vector3.Lerp(camT.position, camPositioner.position,  lerpSpeed * Time.deltaTime);
    8.      camT.LookAt(camTarget);
    9.  
    10. }