Search Unity

Keeping the player's position when loading a previous scene

Discussion in 'Scripting' started by DustyShinigami, May 10, 2019.

  1. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    I've managed to achieve this with dying and respawning back to a checkpoint, and even then it was because of following a tutorial and copying some code, but I can't figure out how I can get the same result just from exiting one scene and (re)loading another. Obviously, using SceneManager.LoadScene destroys everything and resets the level from the start. Is there an alternative I can use where it doesn't destroy the previous scene, or specifically the character's location? Or maybe some code? I've tried experimenting with a couple of older scripts involving a HealthManager and a Checkpoints script, as they include parts to do with respawnPoints, but I can't get them to work when loading from one scene to another. These are all the scripts I have so far, just to give an idea of what I have:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class HealthManager : MonoBehaviour
    7. {
    8.     //The counters will count down and will keep counting down based on the length variables
    9.     public int maxHealth;
    10.     public int currentHealth;
    11.     public float invincibilityLength;
    12.     public Renderer playerRenderer;
    13.     public float flashLength;
    14.     public float respawnLength;
    15.     public GameObject deathEffect;
    16.     public Image blackScreen;
    17.     public float fadeSpeed;
    18.     public float waitForFade;
    19.  
    20.     private float invincibilityCounter;
    21.     private float flashCounter;
    22.     private bool isRespawning;
    23.     private Vector3 respawnPoint;
    24.     private bool isFadetoBlack;
    25.     private bool isFadefromBlack;
    26.     public PlayerController thePlayer;
    27.  
    28.     void Start()
    29.     {
    30.         thePlayer = FindObjectOfType<PlayerController>();
    31.         currentHealth += maxHealth;
    32.         respawnPoint = thePlayer.transform.position;
    33.     }
    34.  
    35.     void Update()
    36.     {
    37.         //These functions are checked every frame until the player takes damage
    38.         if(invincibilityCounter > 0)
    39.         {
    40.             invincibilityCounter -= Time.deltaTime;
    41.             flashCounter -= Time.deltaTime;
    42.             if(flashCounter <= 0)
    43.             //The Flash Counter is currently set at 0.1 and will be within the 0 region as it counts down. During this period, the playerRenderer will alternate between on and off
    44.             {
    45.                 playerRenderer.enabled = !playerRenderer.enabled;
    46.                 //The Flash Counter will keep counting down and reloop depending on the Flash Length time
    47.                 flashCounter = flashLength;
    48.             }
    49.             //This makes sure after the flashing and invincibility has worn off that the player renderer is always turned back on so you can see the player
    50.             if(invincibilityCounter <= 0)
    51.             {
    52.                 playerRenderer.enabled = true;
    53.             }
    54.         }
    55.         if (isFadetoBlack)
    56.         {
    57.             blackScreen.color = new Color(blackScreen.color.r, blackScreen.color.g, blackScreen.color.b, Mathf.MoveTowards(blackScreen.color.a, 1f, fadeSpeed * Time.deltaTime));
    58.             if (blackScreen.color.a == 1f)
    59.             {
    60.                 isFadetoBlack = false;
    61.             }
    62.         }
    63.         if (isFadefromBlack)
    64.         {
    65.             blackScreen.color = new Color(blackScreen.color.r, blackScreen.color.g, blackScreen.color.b, Mathf.MoveTowards(blackScreen.color.a, 0f, fadeSpeed * Time.deltaTime));
    66.             if (blackScreen.color.a == 0f)
    67.             {
    68.                 isFadefromBlack = true;
    69.             }
    70.         }
    71.     }
    72.  
    73.     public void HurtPlayer(int damage, Vector3 direction)
    74.     {
    75.         //If the invincibility countdown reaches zero it stops, making you no longer invincible and prone to taking damage again
    76.         if (invincibilityCounter <= 0)
    77.         {
    78.             currentHealth -= damage;
    79.             if (currentHealth <= 0)
    80.             {
    81.                 Respawn();
    82.             }
    83.             else
    84.             {
    85.                 thePlayer.Knockback(direction);
    86.                 invincibilityCounter = invincibilityLength;
    87.                 playerRenderer.enabled = false;
    88.                 flashCounter = flashLength;
    89.             }
    90.         }
    91.     }
    92.  
    93.     public void Respawn()
    94.     {
    95.         //A StartCoroutine must be set up before the IEnumerator can begin
    96.         if (!isRespawning)
    97.         {
    98.  
    99.             StartCoroutine("RespawnCo");
    100.         }
    101.     }
    102.  
    103.     //IEnumerators or Coroutines will execute the code separately at specified times while the rest of the code in a codeblock will carry on executing as normal
    104.     public IEnumerator RespawnCo()
    105.     {
    106.         isRespawning = true;
    107.         thePlayer.gameObject.SetActive(false);
    108.         Instantiate(deathEffect, thePlayer.transform.position, thePlayer.transform.rotation);
    109.         yield return new WaitForSeconds(respawnLength);
    110.         isFadetoBlack = true;
    111.         yield return new WaitForSeconds(waitForFade);
    112.         isFadefromBlack = true;
    113.         isRespawning = false;
    114.         thePlayer.gameObject.SetActive(true);
    115.         thePlayer.transform.position = respawnPoint;
    116.         currentHealth = maxHealth;
    117.         invincibilityCounter = invincibilityLength;
    118.         playerRenderer.enabled = false;
    119.         flashCounter = flashLength;
    120.     }
    121.  
    122.     public void HealPlayer(int healAmount)
    123.     {
    124.         currentHealth += healAmount;
    125.         if(currentHealth > maxHealth)
    126.         {
    127.             currentHealth = maxHealth;
    128.         }
    129.     }
    130.  
    131.     public void SetSpawnPoint(Vector3 newPosition)
    132.     {
    133.         respawnPoint = newPosition;
    134.     }
    135. }
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class Checkpoint : MonoBehaviour
    7. {
    8.     public HealthManager theHealthManager;
    9.     public Renderer cpRenderer;
    10.     public Renderer postRenderer;
    11.     public SpriteRenderer pcRenderer;
    12.     public Material cpOff;
    13.     public Material cpOn;
    14.     public Material postOff;
    15.     public Material postOn;
    16.     public bool checkpoint1On;
    17.     public GameObject[] infoPanels;
    18.  
    19.     //Make sure to assign a value to a bool with '=' and in an 'if' statement somewhere in the code to prevent warnings.
    20.     //private bool checkpoint1IsActivated;
    21.     private bool infoPanel1Activated;
    22.  
    23.     void Start()
    24.     {
    25.         theHealthManager = FindObjectOfType<HealthManager>();
    26.     }
    27.  
    28.     void Update()
    29.     //Key presses are better handled in the Update function and will recognise keys being pressed once every frame.
    30.     {
    31.         if (checkpoint1On == true)
    32.         {
    33.             if (infoPanel1Activated == false)
    34.             {
    35.                 if (Input.GetKeyDown(KeyCode.Space))
    36.                 {
    37.                     infoPanels[0].SetActive(true);
    38.                     infoPanel1Activated = true;
    39.                 }
    40.             }
    41.             else
    42.             {
    43.                 if (infoPanel1Activated == true)
    44.                 {
    45.                     if (Input.GetKeyDown(KeyCode.Space))
    46.                     {
    47.                         infoPanels[0].SetActive(false);
    48.                         infoPanel1Activated = false;
    49.                     }
    50.                 }
    51.             }
    52.         }
    53.     }
    54.  
    55.     public void Checkpoint1On()
    56.     {
    57.         cpRenderer.material = cpOn;
    58.         postRenderer.material = postOn;
    59.         pcRenderer.color = new Color(1f, 1f, 1f, 1f);
    60.         checkpoint1On = true;
    61.     }
    62.  
    63.     //[] makes a variable an Array (a list). The 'foreach' loop will check through all the Checkpoint objects
    64.  
    65.     //Checkpoint[] checkpoints = FindObjectsOfType<Checkpoint>();
    66.  
    67.     //For each Checkpoint Array called 'checkpoints', look for 'cp' and turn the others in the list off
    68.  
    69.     /*foreach (Checkpoint cp in checkpoints)
    70.     {
    71.         cp.CheckpointOff();
    72.     }
    73.     theRenderer.material = cpOn;*/
    74.  
    75.     public void Checkpoint1Off()
    76.     {
    77.         cpRenderer.material = cpOff;
    78.         postRenderer.material = postOff;
    79.         pcRenderer.color = new Color(1f, 1f, 1f, 5f);
    80.         checkpoint1On = false;
    81.     }
    82.  
    83.     public void OnTriggerStay(Collider other)
    84.     {
    85.         if (other.gameObject.CompareTag("Player"))
    86.         {
    87.             if (GameManager.currentGold >= 5)
    88.             {
    89.                 if (Input.GetKeyDown(KeyCode.Return))
    90.                 {
    91.                     theHealthManager.SetSpawnPoint(transform.position);
    92.                     Checkpoint1On();
    93.                     checkpoint1On = true;
    94.                 }
    95.             }
    96.             else if (GameManager.currentGold <= 5)
    97.             {
    98.                 checkpoint1On = false;
    99.             }
    100.         }
    101.     }
    102. }
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.SceneManagement;
    5. using UnityEngine.UI;
    6.  
    7. public class EntranceTrigger : MonoBehaviour
    8. {
    9.     public GameObject[] buttonPrompts;
    10.     public HealthManager theHealthManager;
    11.     public bool entranceVicinity;
    12.     //public bool exitVicinity;
    13.     //public bool allowInteraction = false;
    14.  
    15.     private int xbox360Controller = 0;
    16.     private int ps4Controller = 0;
    17.     private bool outsideHut;
    18.     private PlayerController thePlayer;
    19.  
    20.     void Start()
    21.     {
    22.         thePlayer = FindObjectOfType<PlayerController>();
    23.         theHealthManager = FindObjectOfType<HealthManager>();
    24.         if(SceneManager.GetActiveScene() == SceneManager.GetSceneByName("start_area"))
    25.         {
    26.             outsideHut = true;
    27.         }
    28.         /*else if(SceneManager.GetActiveScene() == SceneManager.GetSceneByName("hut_interior"))
    29.         {
    30.             insideHut = true;
    31.             outsideHut = false;
    32.         }*/
    33.     }
    34.  
    35.     public void OnTriggerEnter(Collider other)
    36.     {
    37.         if (outsideHut)
    38.         {
    39.             if (other.gameObject.CompareTag("Player"))
    40.             {
    41.                 entranceVicinity = true;
    42.                 //exitVicinity = false;
    43.                 ControllerDetection();
    44.                 if (entranceVicinity && ps4Controller == 1)
    45.                 {
    46.                     PS4Prompts();
    47.                 }
    48.                 else if (entranceVicinity && xbox360Controller == 1)
    49.                 {
    50.                     Xbox360Prompts();
    51.                 }
    52.                 else
    53.                 {
    54.                     PCPrompts();
    55.                 }
    56.             }
    57.         }
    58.     }
    59.  
    60.     public void OnTriggerExit(Collider other)
    61.     {
    62.         entranceVicinity = false;
    63.         //exitVicinity = false;
    64.     }
    65.  
    66.     public void Update()
    67.     {
    68.         if (entranceVicinity)
    69.         {
    70.             if (xbox360Controller == 1)
    71.             {
    72.                 if (Input.GetKeyDown("joystick button 2"))
    73.                 {
    74.                     SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 2);
    75.                 }
    76.             }
    77.             else if (ps4Controller == 1)
    78.             {
    79.                 if (Input.GetKeyDown("joystick button 0"))
    80.                 {
    81.                     SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 2);
    82.                 }
    83.             }
    84.             else
    85.             {
    86.                 if (Input.GetKeyDown(KeyCode.Return))
    87.                 {
    88.                     SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 2);
    89.                 }
    90.             }
    91.         }
    92.     }
    93.  
    94.     public void Hide()
    95.     {
    96.         buttonPrompts[0].SetActive(false);
    97.         buttonPrompts[1].SetActive(false);
    98.         buttonPrompts[2].SetActive(false);
    99.     }
    100.  
    101.     public void Xbox360Prompts()
    102.     {
    103.         buttonPrompts[1].SetActive(true);
    104.         Invoke("Hide", 3f);
    105.     }
    106.  
    107.     public void PS4Prompts()
    108.     {
    109.         buttonPrompts[2].SetActive(true);
    110.         Invoke("Hide", 3f);
    111.     }
    112.  
    113.     public void PCPrompts()
    114.     {
    115.         buttonPrompts[0].SetActive(true);
    116.         Invoke("Hide", 3f);
    117.     }
    118.  
    119.     public void ControllerDetection()
    120.     {
    121.         string[] names = Input.GetJoystickNames();
    122.         for (int x = 0; x < names.Length; x++)
    123.         {
    124.             //print(names[x].Length);
    125.             if (names[x].Length == 19)
    126.             {
    127.                 //print("PS4 CONTROLLER IS CONNECTED");
    128.                 ps4Controller = 1;
    129.                 xbox360Controller = 0;
    130.                 if (ps4Controller == 1)
    131.                 {
    132.                     Debug.Log("PS4 controller detected");
    133.                 }
    134.             }
    135.             else if (names[x].Length == 33)
    136.             {
    137.                 //print("XBOX 360 CONTROLLER IS CONNECTED");
    138.                 ps4Controller = 0;
    139.                 xbox360Controller = 1;
    140.                 if (xbox360Controller == 1)
    141.                 {
    142.                     Debug.Log("Xbox 360 controller detected");
    143.                 }
    144.             }
    145.             else
    146.             {
    147.                 ps4Controller = 0;
    148.                 xbox360Controller = 0;
    149.             }
    150.  
    151.             if(xbox360Controller == 0 && ps4Controller == 0)
    152.             {
    153.                 Debug.Log("No controllers detected");
    154.             }
    155.  
    156.             /*if (!string.IsNullOrEmpty(names[x]))
    157.             {
    158.                 xbox360Controller = 1;
    159.                 ps4Controller = 1;
    160.             }
    161.  
    162.             else if(string.IsNullOrEmpty(names[x]))
    163.             {
    164.                 xbox360Controller = 0;
    165.                 ps4Controller = 0;
    166.                 Debug.Log("Controllers not detected");
    167.             }*/
    168.         }
    169.     }
    170. }
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.SceneManagement;
    5.  
    6. public class ExitTrigger : MonoBehaviour
    7. {
    8.     public GameObject[] buttonPrompts;
    9.     public bool exitVicinity;
    10.     public GameObject thePlayer;
    11.  
    12.     private int xbox360Controller = 0;
    13.     private int ps4Controller = 0;
    14.     private bool insideHut;
    15.     private HealthManager theHealthManager;
    16.  
    17.     void Start()
    18.     {
    19.         theHealthManager = FindObjectOfType<HealthManager>();
    20.         if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("hut_interior"))
    21.         {
    22.             insideHut = true;
    23.             exitVicinity = true;
    24.         }
    25.     }
    26.  
    27.     public void OnTriggerEnter(Collider other)
    28.     {
    29.         if (insideHut)
    30.         {
    31.             if (other.gameObject.CompareTag("Player"))
    32.             {
    33.                 exitVicinity = true;
    34.                 ControllerDetection();
    35.                 if (exitVicinity && ps4Controller == 1)
    36.                 {
    37.                     PS4Prompts();
    38.                 }
    39.                 else if (exitVicinity && xbox360Controller == 1)
    40.                 {
    41.                     Xbox360Prompts();
    42.                 }
    43.                 else
    44.                 {
    45.                     PCPrompts();
    46.                 }
    47.             }
    48.         }
    49.     }
    50.  
    51.     public void OnTriggerExit(Collider other)
    52.     {
    53.         exitVicinity = false;
    54.     }
    55.  
    56.     public void Update()
    57.     {
    58.         if (exitVicinity)
    59.         {
    60.             if (xbox360Controller == 1)
    61.             {
    62.                 if (Input.GetKeyDown("joystick button 2"))
    63.                 {
    64.                     SceneManager.LoadScene("start_area");
    65.                 }
    66.             }
    67.             else if (ps4Controller == 1)
    68.             {
    69.                 if (Input.GetKeyDown("joystick button 0"))
    70.                 {
    71.                     SceneManager.LoadScene("start_area");
    72.                 }
    73.             }
    74.             else
    75.             {
    76.                 if (Input.GetKeyDown(KeyCode.Return))
    77.                 {
    78.                     SceneManager.LoadScene("start_area");
    79.                 }
    80.             }
    81.         }
    82.     }
    83.  
    84.     public void Hide()
    85.     {
    86.         buttonPrompts[0].SetActive(false);
    87.         buttonPrompts[1].SetActive(false);
    88.         buttonPrompts[2].SetActive(false);
    89.     }
    90.  
    91.     public void Xbox360Prompts()
    92.     {
    93.         buttonPrompts[1].SetActive(true);
    94.         Invoke("Hide", 3f);
    95.     }
    96.  
    97.     public void PS4Prompts()
    98.     {
    99.         buttonPrompts[2].SetActive(true);
    100.         Invoke("Hide", 3f);
    101.     }
    102.  
    103.     public void PCPrompts()
    104.     {
    105.         buttonPrompts[0].SetActive(true);
    106.         Invoke("Hide", 3f);
    107.     }
    108.  
    109.     public void ControllerDetection()
    110.     {
    111.         string[] names = Input.GetJoystickNames();
    112.         for (int x = 0; x < names.Length; x++)
    113.         {
    114.             //print(names[x].Length);
    115.             if (names[x].Length == 19)
    116.             {
    117.                 //print("PS4 CONTROLLER IS CONNECTED");
    118.                 ps4Controller = 1;
    119.                 xbox360Controller = 0;
    120.                 if (ps4Controller == 1)
    121.                 {
    122.                     Debug.Log("PS4 controller detected");
    123.                 }
    124.             }
    125.             else if (names[x].Length == 33)
    126.             {
    127.                 //print("XBOX 360 CONTROLLER IS CONNECTED");
    128.                 ps4Controller = 0;
    129.                 xbox360Controller = 1;
    130.                 if (xbox360Controller == 1)
    131.                 {
    132.                     Debug.Log("Xbox 360 controller detected");
    133.                 }
    134.             }
    135.             else
    136.             {
    137.                 ps4Controller = 0;
    138.                 xbox360Controller = 0;
    139.             }
    140.  
    141.             if (xbox360Controller == 0 && ps4Controller == 0)
    142.             {
    143.                 Debug.Log("No controllers detected");
    144.             }
    145.  
    146.             /*if (!string.IsNullOrEmpty(names[x]))
    147.             {
    148.                 xbox360Controller = 1;
    149.                 ps4Controller = 1;
    150.             }
    151.  
    152.             else if(string.IsNullOrEmpty(names[x]))
    153.             {
    154.                 xbox360Controller = 0;
    155.                 ps4Controller = 0;
    156.                 Debug.Log("Controllers not detected");
    157.             }*/
    158.         }
    159.     }
    160. }
    161.  
    The idea was to get the position where the player interacts with the entrance trigger that loads up the next scene. Once leaving the building/scene, I want the player to be in the same spot as when they entered.
     
    athgen113 likes this.
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    This is a total hack, but one approach is to leave a spare GameObject named a particular way and marked as DontDestroyOnLoad(), and then anytime you spawn the player in the outdoors scene, you check for a GameObject of that name, and if it exists, use its position and rotation to spawn the player, then destroy the GameObject.

    This obviously falls over if you have more than one layer of "being outside/being inside" but it is a perfectly viable and lightweight way of doing this, and you can even wrap it all up in a class. You could even make it a Monobehavior and that would let you stick it on the GameObject and put other information into it too.

    To extend it you could make a factory for these things (let's call them BreadCrumbs?) and the factory would make one and return its unique name to you, which later you would use to say "hey do you have a BreadCrumb called 'MainLevelOutdoorPlayerMarker'?" and that would scale to any number of depths, but not necessarily any number of topologies.
     
  3. astracat111

    astracat111

    Joined:
    Sep 21, 2016
    Posts:
    725
    The way I did it was to create a custom scene manager game object set to DontDestroyOnLoad() that has a database that stores the positions and rotations of each NPCs and all the scene's Cameras.

    The scene manager game object would be like your overlord game object that manages all the settings, handles your main game database and shifting from one scene to the next.

    For my game's SDK I have it in where you do "manager.SceneGoto(string startingCameraName, string playerStartPositionGameObjectName)". I also have my manager have lists for the gameObjects in the scene and the available cameras in the scene so like:

    Code (CSharp):
    1. public class Manager {
    2.  
    3.      public Database mgDatabase; < --- something like this to store scene data
    4.      public List<Camera> Scene_Cameras;
    5.      public List<NPC> Scene_NPCs;
    6.  
    7. }
    Like that sort of setup.
     
  4. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    Thanks for the suggestions, guys. Though I’m still at a loss on where to begin; I’ve been at it for hours, it’s late here and I’m tired. :(

    One problem is, is that the character in my second scene is actually bigger due to the scene’s model being at a bigger and up-close scale. Both player versions share the same script and causes this bigger version to appear in the first scene if it’s not destroyed on load.
     
  5. astracat111

    astracat111

    Joined:
    Sep 21, 2016
    Posts:
    725
    I would highly recommend taking some tutorials on Youtube to assist you, take your time have patience and watch them through one step at a time.

    For size of characters, well...You want to use a prefab that you can use universally called "NPC" or "Person" or "Character" or "Entity" or something like that, and then have that NPC or whatever you want to call it have a property that's like isControlled. If isControlled == true when it Start()s it sets you up for controlling it. The player object should ideally be an instantiated version of this Entity prefab.

    You really will want something like a Player class like this (when the scene starts, remember this would be like an overlord class in that it stays present from scene to scene):

    Code (CSharp):
    1. public class NPC {
    2.     private bool isControlled;
    3.     private GameObject gameObject;
    4.  
    5.     public void SetControl(bool value) {
    6.         isControlled = value;
    7.     }
    8.  
    9.     public void SetPosition(Vector3 position) {
    10.         gameObject.transform.position = position;
    11.     }
    12.  
    13.     public void SetRotation(Vector3 eulerAngles) {
    14.         gameObject.transform.eulerAngles = eulerAngles;
    15.     }
    16. }
    17.  
    18. public class Player : NPC {
    19.  
    20. }
    You would with a kind of manager script create the player like this:

    Code (CSharp):
    1. Player player = new Player();
    2. player.SetPosition(new Vector3(0,0,0));
    3. player.SetRotation(new Vector3(0,0,0));
    4. player.SetControl(true);
    At the start of your scene.

    Your scene then needs a default player starting game object. Your player will ideally when the scene starts take over the position of this default player starting game object every time UNLESS you have it overridden, and THAT'S when you have the player start at the position of a custom game object instead of the default.
     
    Last edited: May 10, 2019
  6. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    Hmm... Wouldn't I be better putting the NPC code into my PlayerController script? Also, would setting up the player's position like that work if I use SceneManager.LoadScene, as that resets the whole scene/level. Apart from positioning the player manually where they'll eventually be in the scene, and getting the exact position/rotation, is there a better way of getting their position?

    I don't get the public class Player : NPC part either. Does that need to be done in a new script or the one where all the SetControl/Position/Rotation code is?
     
    Last edited: May 10, 2019
  7. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    I'm sorry, but this is just causing more and more confusion. I've tried that code and I can't get it working properly. :(
     
  8. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    I feel about ready to give up on this problem; I just can't work out how I could fix it. Nothing I've tried works. :(
     
  9. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    If I release a build of my project, could someone take a look at it? Maybe implement something that works and break it down for me...? Or see, based on how it's set up, what the best course of action is?
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Sorry to hear you're having trouble getting this going but I want you to succeed.

    Here's what I can give you: I whipped up the simple breadcrumb link thing I mentioned in my first post and I have attached it here as a .unitypackage.

    It has three scenes (scene1, scene2, scene3) that you must add to your EditorBuildSettings in order for it to function.

    Open scene1 and you can walk around. See this map for how the three scenes are laid out:

    rough_map.png

    When you hit one of the edges that have an active link, you will load the next scene over.

    When you come back, it will put you back exactly where you left the level. This "breadcrumbing" is specified in the exit link for each scene.

    When the player spawns, the PlayerXZController (simple cheese movement) looks for a breadcrumb first, if it can't find that, it looks for a GameObject with a "SpawnPlayerHere" script on it. If it can't find either it just leaves you where it finds you and begins the level.

    The PlayerLinkSensor is what detects you entering a trigger and does the linking, leaving a breadcrumb if you asked for it.

    Let me know if you have any questions. It's somewhat commented and very straightforward, took about 10-15 minutes to whip up.

    Note also that the breadcrumbs contain the name of the scene they are from, to allow multiple ones to coexist in the Unity hierarchy. I think if you went from scene 1 to 2 to 3 and then back to 1, you'd probably be in the same spot you were when you left for 2... try it out. The combinations get complicated really quickly, but this should get you started.
     

    Attached Files:

    ivolusion and DustyShinigami like this.
  11. newjerseyrunner

    newjerseyrunner

    Joined:
    Jul 20, 2017
    Posts:
    966
    I have several scenes that have different ways of dropping in and preserving a list of positions was one of them. I recorded the positions I needed in the playerprefs, then reassigned everything to my new anchors onlevelload where I grabbed them. This doubles as a permanent storage device, so in case the game crashes or something, it still has the last relevant positions.
     
    Kurt-Dekker likes this.
  12. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    Thanks for taking the time out to set this up. I’ll look into it when I can. This ‘breadcrumb’ system... Is it similar to how this guy has done it?





    I’m in the process of following those tutorials to solve my issue; they seem pretty straightforward. :)
     
  13. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    Okay, so, as usual, nothing is ever straightforward. :( I'm so close to fixing the problem, but something isn't working right. Big surprise... So, following those two videos above, and this one -
    - I have things set up more-or-less the same, however, for some annoying reason, if I have...

    Code (CSharp):
    1. if (thePlayer.startPoint == pointName)
    2.         {
    3.             thePlayer.transform.position = transform.position;
    4.         }
    ...in my PlayerStartPoints script, once I hit Return to enter the next scene, the player doesn't move to the Start Point I've assigned. He stays in the same position as he was in in the previous scene and just endlessly falls. If I remove the 'if' statement so it's just thePlayer.transform.position = transform.position, the player will enter the next scene in the right place, but only if I change the names of the Point Names instead of keeping them the same, like in the video. However, in the first scene, he doesn't appear at the start of the level, but at the Start Point outside the building/hut.
     
    Last edited: May 11, 2019
  14. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    Okay, after some investigating, it seems to be an issue with the camera. Because I hadn't been preventing the camera from being destroyed in the new scene, I think the position of the default camera was knocking the player away somehow...? Preventing the camera from being destroyed in each new scene though, the player appears in the right place in the second scene, but the camera doesn't. It also doesn't carry over my Bound Box either, which is used to lock the camera on the player so you can't see the Sky Box. I've tried messing with some of the code from those tutorials for the camera, but I can't get it to work and stay in the right place.

    This is what I have for my CameraController and PlayerStartPoints:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CameraController : MonoBehaviour
    6. {
    7.     [SerializeField] GameObject player = null;
    8.  
    9.     public BoxCollider boundBox;
    10.  
    11.     private Vector3 minBounds;
    12.     private Vector3 maxBounds;
    13.     private Camera theCamera;
    14.     private float halfHeight;
    15.     private float halfWidth;
    16.     private static bool cameraExists;
    17.  
    18.     const float m_minY = 2f;
    19.     Vector3 targetPosition;
    20.     Vector3 cameraOffset;
    21.  
    22.     void Start()
    23.     {
    24.         theCamera = GetComponent<Camera>();
    25.         cameraOffset = transform.position - player.transform.position;
    26.         minBounds = boundBox.bounds.min;
    27.         maxBounds = boundBox.bounds.max;
    28.         halfHeight = theCamera.orthographicSize;
    29.         halfWidth = halfHeight * Screen.width / Screen.height;
    30.         if (!cameraExists)
    31.         {
    32.             cameraExists = true;
    33.             DontDestroyOnLoad(transform.gameObject);
    34.         }
    35.         else
    36.         {
    37.             Destroy(gameObject);
    38.         }
    39.     }
    40.  
    41.     void Update()
    42.     {
    43.         transform.position = player.transform.position + cameraOffset;
    44.         targetPosition.y = Mathf.Min(targetPosition.y, m_minY);
    45.         float clampedX = Mathf.Clamp(transform.position.x, minBounds.x + halfWidth, maxBounds.x - halfWidth);
    46.         float clampedY = Mathf.Clamp(transform.position.y, minBounds.y + halfHeight, maxBounds.y - halfHeight);
    47.         transform.position = new Vector3(clampedX, clampedY, transform.position.z);
    48.     }
    49. }
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerStartPoints : MonoBehaviour
    6. {
    7.     //public Vector3 startDirection;
    8.     public string pointName;
    9.  
    10.     private PlayerController thePlayer;
    11.     private CameraController theCamera;
    12.  
    13.     void Start()
    14.     {
    15.         thePlayer = FindObjectOfType<PlayerController>();
    16.  
    17.         //The player(controller's) startPoint, which has been accessed and the variable found on Start, checks to see if it's equal to or matches the pointName, which is found on each Start Point object through this script. If it does match, the player's transform/position will match the Start Point's. If it doesn't match, the player will be placed in the default location, such as at the beginning of the start_area scene. The pointName for a building's entrance/exit in one scene must match those in another scene for this to work! Think of them as teleporter links.
    18.         if (thePlayer.startPoint == pointName)
    19.         {
    20.             thePlayer.transform.position = transform.position;
    21.         }
    22.  
    23.         theCamera = FindObjectOfType<CameraController>();
    24.         theCamera.transform.position = new Vector3(theCamera.transform.position.x, theCamera.transform.position.y, transform.transform.position.z);
    25.     }
    26. }
    27.  
     
  15. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Just take this one step at a time with the editor in front of you. Run it and try to go through your link.

    The moment you do, pause the editor and study what condition things in your scene are in. Is there two cameras? Two players? Where is the player? Did he get moved properly? Did something else move him? Take notes of what you try so you can back up and try other things.

    As you get further into this you may find you have to disable certain scripts to isolate the problem, such as disabling the part that sets the new position, etc. What you are doing is the basics of debugging, bisecting the big problem until you can identify exactly the part that isn't doing what you expect in your scene context.
     
  16. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    It’s definitely my camera from the first scene. The second scene is in a different position, and the camera is locked to the player in the first scene by using a bounds box. This bounds box doesn’t make it into the second scene and the GameObject box in the Inspector is empty once the second scene has loaded. I’m not sure how to fix that.
    Although surely the player should still go to the new start point and the camera should follow...? In the camera script, the camera’s transform is equal to the player’s, so I don’t understand what’s going on there.
    If I make it so the camera doesn’t get destroyed on load, but set up another camera in scene 2, that’s in the right place, everything’s fine. Of course, that first camera from scene 1 is still there; it just can’t be seen. Exiting scene 2 and going back to 1, the new camera is destroyed, but the original camera and player are in the right place outside the hut and carry on as normal. It’s a temporary fix at least. :)

    Would still like to know how to get the original camera to go to the right position in scene 2 though.
     
  17. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    S**t. My temporary solution looks to be temperamental. It looks like it's a case of it'll work one minute and not the next. I'll press Return to enter the next scene, and the player may appear in the right spot, or he won't and will fall forever. :(
     
  18. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
    I’m really going to have to upload my latest build for people to access and look at; I’ve pretty much given up at this stage. It’s doing my head in. I can’t work it out or process it. Scripting is not my forte at all.

    @Kurt-Dekker I did take a look at your project you whipped up, but looking through the code, I can’t break it down or get my head around it. My brain just won’t process it. I have a hard time understanding what each thing is and why it does what it does.
    :( I’ll have another look at it this evening, but I’m not expecting to ‘get it’.
    :-/
     
  19. DustyShinigami

    DustyShinigami

    Joined:
    Jan 5, 2018
    Posts:
    529
  20. ivolusion

    ivolusion

    Joined:
    Apr 16, 2020
    Posts:
    1
    Thanks a whole bunch Kurt! I finally got to understand your script and made it work for me. Cheers!
     
    Kurt-Dekker likes this.