diff --git a/Assets/Fungus/Scripts/Commands/SavePoint.cs b/Assets/Fungus/Scripts/Commands/SavePoint.cs index c7793e65..c30ebbac 100644 --- a/Assets/Fungus/Scripts/Commands/SavePoint.cs +++ b/Assets/Fungus/Scripts/Commands/SavePoint.cs @@ -2,6 +2,7 @@ // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) using UnityEngine; +using System.Collections; namespace Fungus { @@ -10,18 +11,31 @@ namespace Fungus "Creates a Save Point and adds it to the Save History. The player can save the Save History to peristent storage and load it again later.")] public class SavePoint : Command { - [Tooltip("A string key which uniquely identifies this save point. If empty then the parent Block's name will be used.")] + [Tooltip("A string key which uniquely identifies this save point. If you leave this empty then the parent Block's name will be used.")] [SerializeField] protected string savePointKey = ""; - [Tooltip("A short description of this save point. If empty then the current time and date will be used.")] + [Tooltip("A short description of this save point. If you leave this empty then the current time and date will be used.")] [SerializeField] protected string savePointDescription; - [Tooltip("Fire an event that will be handled by any Save Point Loaded event handler with matching key.")] + [Tooltip("Fire a Save Point Loaded event when this command executes.")] [SerializeField] protected bool fireEvent = true; - [Tooltip("Resume execution from this command after loading a save point.")] + [Tooltip("Resume execution from here after loading this Save Point.")] [SerializeField] protected bool resumeFromHere = true; + protected virtual void Start() + { + // Each scene should have one Save Point with the 'Start' key. + // We automatically start execution from this command whenever the scene starts 'normally' (i.e. first play, restart or scene load via the Load Scene command or SceneManager.LoadScene). + // If on the other hand, the scene was loaded by loading a Save Point then the Save Manager handles resuming execution at the appropriate point, so we don't need to do anything here. + + if (string.Compare(SavePointKey, "Start", true) == 0 && + !FungusManager.Instance.SaveManager.HasLoadedSavePoint) + { + GetFlowchart().ExecuteBlock(ParentBlock, CommandIndex); + } + } + #region Public members /// @@ -69,7 +83,7 @@ namespace Fungus if (fireEvent) { - SavePointLoaded.NotifyEventHandlers(savePointKey); + SavePointLoaded.NotifyEventHandlers(SavePointKey); } Continue(); diff --git a/Assets/Fungus/Scripts/Components/SaveManager.cs b/Assets/Fungus/Scripts/Components/SaveManager.cs index bc8b627c..8284861f 100644 --- a/Assets/Fungus/Scripts/Components/SaveManager.cs +++ b/Assets/Fungus/Scripts/Components/SaveManager.cs @@ -1,4 +1,5 @@ using UnityEngine; +using System.Collections; namespace Fungus { @@ -38,8 +39,37 @@ namespace Fungus return false; } + protected virtual void OnEnable() + { + SaveManagerSignals.OnSavePointLoaded += OnSavePointLoaded; + } + + protected virtual void OnDisable() + { + SaveManagerSignals.OnSavePointLoaded -= OnSavePointLoaded; + } + + protected virtual void OnSavePointLoaded(string savePointKey) + { + // Flag that a save point was loaded. + // The flag remains set for 1 frame to give other components enough time to poll it in their Start method. + HasLoadedSavePoint = true; + StartCoroutine(ResetHasLoadedSavePoint()); + } + + protected virtual IEnumerator ResetHasLoadedSavePoint() + { + yield return new WaitForEndOfFrame(); + HasLoadedSavePoint = false; + } + #region Public members + /// + /// The default key used for storing save game data in PlayerPrefs. + /// + public const string DefaultSaveDataKey = "save_data"; + /// /// Returns the number of Save Points in the Save History. /// @@ -50,34 +80,32 @@ namespace Fungus /// public virtual int NumRewoundSavePoints { get { return saveHistory.NumRewoundSavePoints; } } + public virtual bool HasLoadedSavePoint { get; private set; } + /// /// Writes the Save History to persistent storage. /// - public virtual void Save(string saveDataKey) + public virtual void Save(string saveDataKey = DefaultSaveDataKey) { WriteSaveHistory(saveDataKey); - - SaveManagerSignals.DoGameSaved(saveDataKey); } /// /// Loads the Save History from persistent storage. /// - public void Load(string saveDataKey) + public void Load(string saveDataKey = DefaultSaveDataKey) { if (ReadSaveHistory(saveDataKey)) { saveHistory.ClearRewoundSavePoints(); saveHistory.LoadLatestSavePoint(); - - SaveManagerSignals.DoGameLoaded(saveDataKey); } } /// /// Deletes a previously stored Save History from persistent storage. /// - public void Delete(string saveDataKey) + public void Delete(string saveDataKey = DefaultSaveDataKey) { PlayerPrefs.DeleteKey(saveDataKey); PlayerPrefs.Save(); @@ -86,7 +114,7 @@ namespace Fungus /// /// Returns true if save data has previously been stored using this key. /// - public bool SaveDataExists(string saveDataKey) + public bool SaveDataExists(string saveDataKey = DefaultSaveDataKey) { return PlayerPrefs.HasKey(saveDataKey); } @@ -108,7 +136,7 @@ namespace Fungus { if (saveHistory.NumSavePoints > 0) { - // Can't rewind the first save point (new_game) + // Rewinding the first save point is not permitted if (saveHistory.NumSavePoints > 1) { saveHistory.Rewind(); @@ -142,8 +170,8 @@ namespace Fungus /// Starts Block execution based on a Save Point Key /// The execution order is: /// 1. Save Point Loaded event handlers with a matching key. - /// 2. First Save Point command (in any Block) with matching key. Execution starts at following command. - /// 3. Any label in any block with name matching the key. Execution starts at following command. + /// 2. First Save Point command (in any Block) with matching key. Execution starts at the following command. + /// 3. Any label in any block with name matching the key. Execution starts at the following command. /// public static void ExecuteBlocks(string savePointKey) { diff --git a/Assets/Fungus/Scripts/Components/SaveMenu.cs b/Assets/Fungus/Scripts/Components/SaveMenu.cs index 1f015364..3dedb8dd 100644 --- a/Assets/Fungus/Scripts/Components/SaveMenu.cs +++ b/Assets/Fungus/Scripts/Components/SaveMenu.cs @@ -10,12 +10,8 @@ namespace Fungus /// public class SaveMenu : MonoBehaviour { - const string SaveDataKey = "save_data"; - - const string NewGameSavePointKey = "new_game"; - - [Tooltip("On scene start, execute any Save Point Loaded event handlers which have the 'new_game' key")] - [SerializeField] protected bool autoStartGame = true; + [Tooltip("Automatically load the most recently saved game on startup")] + [SerializeField] protected bool loadOnStart = true; [Tooltip("Delete the save game data from disk when player restarts the game. Useful for testing, but best switched off for release builds.")] [SerializeField] protected bool restartDeletesSave = false; @@ -72,32 +68,19 @@ namespace Fungus // Assume that the first scene that contains the SaveMenu is also the scene to load on restart. startScene = SceneManager.GetActiveScene().name; - if (!saveMenuActive) { saveMenuGroup.alpha = 0f; } - var saveManager = FungusManager.Instance.SaveManager; - - if (autoStartGame && - saveManager.NumSavePoints == 0) + if (loadOnStart) { - StartNewGame(); + var saveManager = FungusManager.Instance.SaveManager; + if (saveManager.SaveDataExists()) + { + saveManager.Load(); + } } - - CheckSavePointKeys(); - } - - protected virtual void StartNewGame() - { - var saveManager = FungusManager.Instance.SaveManager; - - // Create an initial save point - saveManager.AddSavePoint(NewGameSavePointKey, ""); - - // Start game execution - SaveManager.ExecuteBlocks(NewGameSavePointKey); } protected virtual void Update() @@ -112,7 +95,7 @@ namespace Fungus } if (loadButton != null) { - loadButton.interactable = saveManager.SaveDataExists(SaveDataKey); + loadButton.interactable = saveManager.SaveDataExists(); } if (rewindButton != null) { @@ -124,33 +107,6 @@ namespace Fungus } } - /// - /// Warns if duplicate SavePointKeys are found. - /// - protected void CheckSavePointKeys() - { - List keys = new List(); - - var savePoints = GameObject.FindObjectsOfType(); - - foreach (var savePoint in savePoints) - { - if (string.IsNullOrEmpty(savePoint.SavePointKey)) - { - continue; - } - - if (keys.Contains(savePoint.SavePointKey)) - { - Debug.LogError("Save Point Key " + savePoint.SavePointKey + " is defined multiple times."); - } - else - { - keys.Add(savePoint.SavePointKey); - } - } - } - protected void PlayClickSound() { if (clickAudioSource != null) @@ -159,21 +115,6 @@ namespace Fungus } } - /// - /// Callback for the restart scene load - /// - protected void OnSceneLoaded(Scene scene, LoadSceneMode mode) - { - if (scene.name != startScene) - { - return; - } - - SceneManager.sceneLoaded -= OnSceneLoaded; - - StartNewGame(); - } - #region Public methods /// @@ -220,7 +161,7 @@ namespace Fungus if (saveManager.NumSavePoints > 0) { PlayClickSound(); - saveManager.Save(SaveDataKey); + saveManager.Save(); } } @@ -231,10 +172,10 @@ namespace Fungus { var saveManager = FungusManager.Instance.SaveManager; - if (saveManager.SaveDataExists(SaveDataKey)) + if (saveManager.SaveDataExists()) { PlayClickSound(); - saveManager.Load(SaveDataKey); + saveManager.Load(); } } @@ -277,17 +218,16 @@ namespace Fungus return; } - var saveManager = FungusManager.Instance.SaveManager; - PlayClickSound(); + // Reset the Save History for a new game + var saveManager = FungusManager.Instance.SaveManager; saveManager.ClearHistory(); if (restartDeletesSave) { - saveManager.Delete(SaveDataKey); + saveManager.Delete(); } - SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.LoadScene(startScene); } diff --git a/Assets/Fungus/Scripts/Signals/SaveManagerSignals.cs b/Assets/Fungus/Scripts/Signals/SaveManagerSignals.cs index 56878ade..385d80eb 100644 --- a/Assets/Fungus/Scripts/Signals/SaveManagerSignals.cs +++ b/Assets/Fungus/Scripts/Signals/SaveManagerSignals.cs @@ -12,18 +12,11 @@ namespace Fungus #region Public members /// - /// GameSaved signal. Sent just after the game is saved. + /// SavePointLoaded signal. Sent just after a SavePoint is loaded. /// - public static event GameSavedHandler OnGameSaved; - public delegate void GameSavedHandler(string saveDataKey); - public static void DoGameSaved(string saveDataKey) { if (OnGameSaved != null) OnGameSaved(saveDataKey); } - - /// - /// GameLoaded signal. Sent just after the game is loaded. - /// - public static event GameLoadedHandler OnGameLoaded; - public delegate void GameLoadedHandler(string saveDataKey); - public static void DoGameLoaded(string saveDataKey) { if (OnGameLoaded != null) OnGameLoaded(saveDataKey); } + public static event SavePointLoadedHandler OnSavePointLoaded; + public delegate void SavePointLoadedHandler(string savePointKey); + public static void DoSavePointLoaded(string savePointKey) { if (OnSavePointLoaded != null) OnSavePointLoaded(savePointKey); } /// /// SavePointAdded signal. Sent when a new save point is added to the save history (typically via the Save Point command). diff --git a/Assets/Fungus/Scripts/Utils/FungusConstants.cs b/Assets/Fungus/Scripts/Utils/FungusConstants.cs index 9edc868d..f7276c9d 100644 --- a/Assets/Fungus/Scripts/Utils/FungusConstants.cs +++ b/Assets/Fungus/Scripts/Utils/FungusConstants.cs @@ -27,8 +27,19 @@ namespace Fungus /// public const string DefaultBlockName = "New Block"; + /// + /// The default choice block color. + /// public static Color DefaultChoiceBlockTint = new Color(1.0f, 0.627f, 0.313f, 1.0f); + + /// + /// The default event block color. + /// public static Color DefaultEventBlockTint = new Color(0.784f, 0.882f, 1.0f, 1.0f); + + /// + /// The default process block color. + /// public static Color DefaultProcessBlockTint = new Color(1.0f, 0.882f, 0.0f, 1.0f); #endregion diff --git a/Assets/Fungus/Scripts/Utils/SavePointData.cs b/Assets/Fungus/Scripts/Utils/SavePointData.cs index 78cc8b54..991f44e3 100644 --- a/Assets/Fungus/Scripts/Utils/SavePointData.cs +++ b/Assets/Fungus/Scripts/Utils/SavePointData.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; +using System.Collections; namespace Fungus { @@ -34,6 +35,8 @@ namespace Fungus } SaveManager.ExecuteBlocks(savePointData.savePointKey); + + SaveManagerSignals.DoSavePointLoaded(savePointData.savePointKey); } protected static SavePointData Create(string _savePointKey, string _savePointDescription, string _sceneName) diff --git a/Assets/FungusExamples/SaveGame/SaveExample.unity b/Assets/FungusExamples/SaveGame/SaveExample.unity index 7d38358f..a08d47f7 100644 --- a/Assets/FungusExamples/SaveGame/SaveExample.unity +++ b/Assets/FungusExamples/SaveGame/SaveExample.unity @@ -1287,12 +1287,12 @@ GameObject: - component: {fileID: 1889213511} - component: {fileID: 1889213509} - component: {fileID: 1889213470} - - component: {fileID: 1889213471} - component: {fileID: 1889213473} - component: {fileID: 1889213481} - component: {fileID: 1889213480} - - component: {fileID: 1889213479} + - component: {fileID: 1889213478} - component: {fileID: 1889213475} + - component: {fileID: 1889213471} m_Layer: 0 m_Name: Flowchart m_TagString: Untagged @@ -1302,7 +1302,7 @@ GameObject: m_IsActive: 1 --- !u!114 &1889213470 MonoBehaviour: - m_ObjectHideFlags: 0 + m_ObjectHideFlags: 2 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 1889213469} @@ -1322,7 +1322,7 @@ MonoBehaviour: itemId: 52 blockName: Play Music 1 description: - eventHandler: {fileID: 1889213471} + eventHandler: {fileID: 1889213475} commandList: - {fileID: 1889213473} --- !u!114 &1889213471 @@ -1336,13 +1336,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 9ca33a026786245d4b10323b87e84d5f, type: 3} m_Name: m_EditorClassIdentifier: - parentBlock: {fileID: 1889213470} + parentBlock: {fileID: 1889213481} savePointKeys: - - new_game - - Queens Chamber + - Use Umbrella + - Duck Down + - The Queen --- !u!114 &1889213473 MonoBehaviour: - m_ObjectHideFlags: 0 + m_ObjectHideFlags: 2 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 1889213469} @@ -1394,9 +1395,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 9ca33a026786245d4b10323b87e84d5f, type: 3} m_Name: m_EditorClassIdentifier: - parentBlock: {fileID: 1889213482} + parentBlock: {fileID: 1889213470} savePointKeys: - - new_game + - Start + - Queens Chamber --- !u!114 &1889213476 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1410,7 +1412,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: version: 1 - scrollPos: {x: -57.30224, y: -63.688995} + scrollPos: {x: -103.9434, y: -49.980755} variablesScrollPos: {x: 0, y: 0} variablesExpanded: 1 blockViewHeight: 400 @@ -1422,7 +1424,7 @@ MonoBehaviour: width: 1502.7736 height: 1138.5048 selectedBlocks: - - {fileID: 1889213481} + - {fileID: 1889213500} selectedCommands: [] variables: - {fileID: 1889213489} @@ -1450,25 +1452,26 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 7 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1889213479 +--- !u!114 &1889213478 MonoBehaviour: - m_ObjectHideFlags: 0 + m_ObjectHideFlags: 2 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 1889213469} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9ca33a026786245d4b10323b87e84d5f, type: 3} + m_Script: {fileID: 11500000, guid: 0b115619cb83b4d6ab8047d0e9407403, type: 3} m_Name: m_EditorClassIdentifier: - parentBlock: {fileID: 1889213481} - savePointKeys: - - Use Umbrella - - Duck Down - - The Queen + itemId: 61 + indentLevel: 0 + savePointKey: + savePointDescription: + fireEvent: 1 + resumeFromHere: 1 --- !u!114 &1889213480 MonoBehaviour: - m_ObjectHideFlags: 0 + m_ObjectHideFlags: 2 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 1889213469} @@ -1485,7 +1488,7 @@ MonoBehaviour: fadeDuration: 1 --- !u!114 &1889213481 MonoBehaviour: - m_ObjectHideFlags: 0 + m_ObjectHideFlags: 2 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 1889213469} @@ -1496,8 +1499,8 @@ MonoBehaviour: m_EditorClassIdentifier: nodeRect: serializedVersion: 2 - x: 81.28943 - y: 288.5421 + x: 78.28943 + y: 294.5421 width: 120 height: 40 tint: {r: 1, g: 1, b: 1, a: 1} @@ -1505,7 +1508,7 @@ MonoBehaviour: itemId: 59 blockName: Play Music 2 description: - eventHandler: {fileID: 1889213479} + eventHandler: {fileID: 1889213471} commandList: - {fileID: 1889213480} --- !u!114 &1889213482 @@ -1528,10 +1531,11 @@ MonoBehaviour: tint: {r: 1, g: 1, b: 1, a: 1} useCustomTint: 0 itemId: 16 - blockName: new_game + blockName: Start description: - eventHandler: {fileID: 1889213475} + eventHandler: {fileID: 0} commandList: + - {fileID: 1889213478} - {fileID: 1889213474} - {fileID: 1889213507} - {fileID: 1889213504} @@ -1631,9 +1635,7 @@ MonoBehaviour: itemId: 21 indentLevel: 0 savePointKey: - savePointDescription: - stringRef: {fileID: 0} - stringVal: + savePointDescription: fireEvent: 1 resumeFromHere: 1 --- !u!114 &1889213488 @@ -1923,13 +1925,13 @@ MonoBehaviour: nodeRect: serializedVersion: 2 x: 542.1676 - y: 144.44673 + y: 143.44673 width: 120 height: 40 tint: {r: 1, g: 1, b: 1, a: 1} useCustomTint: 0 itemId: 31 - blockName: TheQueen + blockName: The Queen description: eventHandler: {fileID: 0} commandList: @@ -1953,9 +1955,7 @@ MonoBehaviour: itemId: 35 indentLevel: 0 savePointKey: - savePointDescription: - stringRef: {fileID: 0} - stringVal: + savePointDescription: fireEvent: 1 resumeFromHere: 1 --- !u!114 &1889213502 @@ -1972,9 +1972,7 @@ MonoBehaviour: itemId: 34 indentLevel: 0 savePointKey: - savePointDescription: - stringRef: {fileID: 0} - stringVal: + savePointDescription: fireEvent: 1 resumeFromHere: 1 --- !u!114 &1889213503 @@ -2239,9 +2237,7 @@ MonoBehaviour: itemId: 43 indentLevel: 0 savePointKey: - savePointDescription: - stringRef: {fileID: 0} - stringVal: + savePointDescription: fireEvent: 1 resumeFromHere: 1 --- !u!1 &2025975869