How I can Open a Previous Scene with button back !?
I've create a game with a menu, and 5 scenes and on the every scene I have an button that 'goes back,' however I need a script so that when I click the button 'back' it goes back to the previous scene . example : i'm in the menu and i go to scene 3 after it i go to scene 5 if i press button 'back' I want it to go back to the scene 3 and if i also press second time the button 'back' I want it to go back to the menu . & Thank u
i already googlet and try my effort but doesn't work for me this is the script one off a thons of scripts i had try it
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class SceneLoader : MonoBehaviour
{
public void back()
{
// reload the current scene
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
// load the previous scene
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex - 1);
}
}
Answer by Hellium · Mar 29, 2019 at 07:12 PM
Here are two alternatives. They have their own advantages and drawbacks. Choose the one you want. Both do the same: you can load scenes and go back to the previous scene (as "far" as you want. Even if you load 10 scenes, you will be able to roll back to the first scene, in opposition to the given answer, which allows you to load only the previous scene)
Using a ScriptableObject
using UnityEngine;
using System.Collections.Generic;
[CreateAssetMenu( fileName = "SceneManager")]
public class SceneManager : ScriptableObject
{
private Stack<int> loadedLevels;
[System.NonSerialized]
private bool initialized;
private void Init()
{
loadedLevels = new Stack<int>();
initialized = true;
}
public UnityEngine.SceneManagement.Scene GetActiveScene()
{
return UnityEngine.SceneManagement.SceneManager.GetActiveScene();
}
public void LoadScene( int buildIndex )
{
if ( !initialized ) Init();
loadedLevels.Push( GetActiveScene().buildIndex );
UnityEngine.SceneManagement.SceneManager.LoadScene( buildIndex );
}
public void LoadScene( string sceneName )
{
if ( !initialized ) Init();
loadedLevels.Push( GetActiveScene().buildIndex );
UnityEngine.SceneManagement.SceneManager.LoadScene( sceneName );
}
public void LoadPreviousScene()
{
if ( !initialized )
{
Debug.LogError( "You haven't used the LoadScene functions of the scriptable object. Use them instead of the LoadScene functions of Unity's SceneManager." );
}
if ( loadedLevels.Count > 0 )
{
UnityEngine.SceneManagement.SceneManager.LoadScene( loadedLevels.Pop() );
}
else
{
Debug.LogError( "No previous scene loaded" );
// If you want, you can call `Application.Quit()` instead
}
}
}
Copy paste the code above in a file called
SceneManager.cs
Create the scriptable object
Assets > Create > SceneManager
Drag & drop the scriptable object into the
onClick
events of your buttons, and choose the function you wantDelete the
SceneLoader
script
Drawbacks
You have to drag & drop the scriptable object on every button
Advantages
Very easy to use in the editor
Only one script
Using TWO MonoBehaviours
using UnityEngine;
public class SceneLoader : MonoBehaviour
{
public void back()
{
// reload the current scene
SceneManager.LoadPreviousScene();
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SceneManager : MonoBehaviour
{
private static bool destroyed = false;
private static object lockObject = new object();
private static SceneManager instance;
private Stack<int> loadedLevels;
public static SceneManager Instance
{
get
{
if (destroyed)
{
Debug.LogWarning("[Singleton] Instance '" + typeof(SceneManager) +
"' already destroyed. Returning null.");
return null;
}
lock (lockObject)
{
if (instance == null)
{
// Search for existing instance.
instance = (SceneManager)FindObjectOfType(typeof(SceneManager));
// Create new instance if one doesn't already exist.
if (instance == null)
{
// Need to create a new GameObject to attach the singleton to.
var singletonObject = new GameObject();
instance = singletonObject.AddComponent<SceneManager>();
singletonObject.name = typeof(SceneManager).ToString() + " (Singleton)";
// Make instance persistent.
DontDestroyOnLoad(singletonObject);
}
}
return instance;
}
}
}
public static UnityEngine.SceneManagement.Scene GetActiveScene()
{
return UnityEngine.SceneManagement.SceneManager.GetActiveScene();
}
public static void LoadScene( int buildIndex )
{
Instance.loadedLevels.Push( GetActiveScene().buildIndex );
UnityEngine.SceneManagement.SceneManager.LoadScene( buildIndex );
}
public static void LoadScene( string sceneName )
{
Instance.loadedLevels.Push( GetActiveScene().buildIndex );
UnityEngine.SceneManagement.SceneManager.LoadScene( sceneName );
}
public static void LoadPreviousScene()
{
if ( Instance.loadedLevels.Count > 0 )
{
UnityEngine.SceneManagement.SceneManager.LoadScene( Instance.loadedLevels.Pop() );
}
else
{
Debug.LogError( "No previous scene loaded" );
// If you want, you can call `Application.Quit()` instead
}
}
private void Awake()
{
loadedLevels = new Stack<int>();
}
private void OnApplicationQuit()
{
destroyed = true;
}
private void OnDestroy()
{
destroyed = true;
}
}
Copy paste the two code above in their own file :
SceneLoader.cs
andSceneManager.cs
Drag & drop the object holding the
SceneLoader
script into theonClick
event and call theback
functionDon't drag & drop the
SceneManager
component on any gameObjectRemove every occurence of
UnityEngine.SceneManagement
inSceneLoader.cs
Drawbacks
Singleton pattern
Two scripts
The
SceneLoader
script must be added to every scene where you need this feature
Advantages
Easy to use in code
Answer by Vollmondum · Mar 29, 2019 at 06:17 PM
using UnityEngine.SceneManagement; // or Unity.SceneManagement, not sure
PlayerPrefs.SetString("lastSceneName"); // to save current scene before loading next one
SceneManager.LoadScene(PlayerPrefs.GetString("lastSceneName")); // load previously saved scene
It only works for two levels, and PlayerPrefs adds storage time, I am assuming somewhere you call PlayerPrefs.Save()
Answer by luistapia2998 · Mar 02 at 04:16 AM
Here I present a functional approach, taking care of some of the drawback like having to attach every button or mantain a Singleton where is no need. Against that I found a [Stateless Pattern][1] that passes that object in functional way. I refine to load new, previous and actual scene. I make a gist btw: [Scene Loader and History][2]
using UnityEngine;
public class MySceneBehaviour: MonoBehaviour {
private static MySceneParams loadSceneRegister = null;
public MySceneParams sceneParams;
public GameObject prefabButton;
public static void loadMyScene(string nextScene, MySceneParams sceneParams, System.Action<MySceneOutcome> callback, bool previous = false) {
MySceneBehaviour.loadSceneRegister = sceneParams;
sceneParams.callback = callback;
if (!previous)
sceneParams.PreviousScenes.Add(SceneManager.GetActiveScene().name);
UnityEngine.SceneManagement.SceneManager.LoadScene(nextScene);
}
public void Awake() {
if (loadSceneRegister != null) sceneParams = loadSceneRegister;
loadSceneRegister = null; // the register has served its purpose, clear the state
}
public void endScene (MySceneOutcome outcome) {
if (sceneParams.callback != null) sceneParams.callback(outcome);
sceneParams.callback = null; // Protect against double calling;
}
//Add a button to an GameObject named "Canvas"
void Start() {
if (SceneManager.GetActiveScene().buildIndex != 0) {
GameObject backButton = (GameObject)Instantiate(prefabButton);
backButton.transform.SetParent(GameObject.Find("Canvas").GetComponent<Transform>(), false);
backButton.transform.localScale = new Vector3(1, 1, 1);
Button tempButton = backButton.GetComponent<Button>();
tempButton.onClick.AddListener(() => LoadPreviousScene());
}
}
// Previous Scene
//Call this method from your button OnClick() event system in the inspector
public void LoadPreviousScene() {
string previousScene = string.Empty;
//Check wether you're not back at your original scene (index 0)
if (sceneParams.PreviousScenes.Count > 0) {
string scenes = "";
sceneParams.PreviousScenes.ForEach(scene => scenes = scenes + " " + scene);
//Debug.Log(scenes);// Print all previous scenes
previousScene = sceneParams.PreviousScenes[sceneParams.PreviousScenes.Count - 1]; //Get the last previously loaded scene name from the list
sceneParams.previousScenes.RemoveAt(sceneParams.PreviousScenes.Count - 1); //Remove the last previously loaded scene name from the list
SceneLoader.loadScene(previousScene, sceneParams, null, true);//Load the previous scene
}
}
public void Reload() {
Scene scene = SceneManager.GetActiveScene();
SceneLoader.loadScene(scene.name, sceneParams, null, true);
}
}
[System.Serializable]
public class MySceneParams {
public System.Action<MySceneOutcome> callback;
private List<string> previousScenes;
public List<string> PreviousScenes
{
get {
if (previousScenes == null)
previousScenes = new List<string>();
return previousScenes; }
set
{
previousScenes = value;
}
}
// + inputs of the scene
}
public class MySceneOutcome {
// + outputs of the scene
}
You only have to attach the script to an object in the new scenes, add a prefab button (this can be extracted from an button) and the script creates a button whenever exist an object named Canvas and call the static function for load new scenes. It means you can decide at time to add new scenes if you want to mantain an historial and data between scenes, and the callback function you pass can handle an outcome data from that scene once ended if you call endScene before load the next.
Disanvantges: if you aren't used in functional programming.
Stateless Pattern [1]: https://gist.github.com/tomlarkworthy/11e0d99f69761ca5dd248e67fd398faf Scene Loader and History [2]: https://gist.github.com/TapiaX/5ea9e0e4f80a5e75fd273b193a5e352e