Browse Source

Simplified save system to not use slots. A full history of save points is stored, and user can rewind to previous save points.

master
Christopher 8 years ago
parent
commit
6e860053f5
  1. 36
      Assets/Fungus/Scripts/Commands/LoadGame.cs
  2. 17
      Assets/Fungus/Scripts/Commands/SavePoint.cs
  3. 31
      Assets/Fungus/Scripts/Components/GameSaver.cs
  4. 61
      Assets/Fungus/Scripts/Components/SaveGameHelper.cs
  5. 0
      Assets/Fungus/Scripts/Components/SaveGameHelper.cs.meta
  6. 102
      Assets/Fungus/Scripts/Components/SaveManager.cs
  7. 17
      Assets/Fungus/Scripts/SavePoints/SaveGameObjects.cs
  8. 4
      Assets/Fungus/Scripts/SavePoints/SaveGameObjects.cs.meta
  9. 58
      Assets/Fungus/Scripts/SavePoints/SaveHistory.cs
  10. 4
      Assets/Fungus/Scripts/SavePoints/SaveHistory.cs.meta
  11. 47
      Assets/Fungus/Scripts/SavePoints/SavePointData.cs
  12. 23
      Assets/Fungus/Scripts/Signals/SaveSignals.cs
  13. 12
      Assets/Fungus/Scripts/Signals/SaveSignals.cs.meta
  14. 31
      Assets/FungusExamples/SaveGame/Menu.unity
  15. 2441
      Assets/FungusExamples/SaveGame/SaveExample.unity
  16. 8
      Assets/FungusExamples/SaveGame/SaveExample.unity.meta
  17. 34
      Assets/FungusExamples/SaveGame/SavePicker.cs
  18. 5
      Assets/FungusExamples/SaveGame/SceneA.unity
  19. 3
      ProjectSettings/ProjectSettings.asset

36
Assets/Fungus/Scripts/Commands/LoadGame.cs

@ -1,36 +0,0 @@
// This code is part of the Fungus library (http://fungusgames.com) maintained by Chris Gregan (http://twitter.com/gofungus).
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine;
namespace Fungus
{
[CommandInfo("Variable",
"Load Game",
"Loads a previously saved game. The original scene is loaded and the resume block is executed.")]
public class LoadGame : Command
{
[SerializeField] protected IntegerData saveSlot = new IntegerData(0);
#region Public members
public override void OnEnter()
{
var saveManager = FungusManager.Instance.SaveManager;
saveManager.Load(saveSlot.Value);
}
public override string GetSummary()
{
return saveSlot.Value.ToString();
}
public override Color GetButtonColor()
{
return new Color32(235, 191, 217, 255);
}
#endregion
}
}

17
Assets/Fungus/Scripts/Commands/SavePoint.cs

@ -14,29 +14,28 @@ namespace Fungus
{
[SerializeField] protected string saveKey;
[SerializeField] protected string description;
[SerializeField] protected string saveDescription;
[SerializeField] protected bool saveNow;
[SerializeField] protected bool resumeFromHere = true;
#region Public members
public string SaveKey { get { return saveKey; } }
public bool ResumeFromHere { get { return resumeFromHere; } }
public override void OnEnter()
{
var saveManager = FungusManager.Instance.SaveManager;
saveManager.PopulateSaveBuffer(saveKey, description);
if (saveNow)
{
saveManager.Save();
}
saveManager.AddSavePoint(saveKey, saveDescription);
Continue();
}
public override string GetSummary()
{
return saveKey;
return saveKey + " : " + saveDescription;
}
public override Color GetButtonColor()

31
Assets/Fungus/Scripts/Components/GameSaver.cs

@ -1,31 +0,0 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
namespace Fungus
{
public class GameSaver : MonoBehaviour
{
[SerializeField] protected string startScene = "";
[SerializeField] protected List<Flowchart> flowcharts = new List<Flowchart>();
#region Public methods
public List<Flowchart> Flowcharts { get { return flowcharts; } }
public virtual void Save()
{
var saveManager = FungusManager.Instance.SaveManager;
saveManager.Save();
}
public virtual void LoadScene(string sceneName)
{
SceneManager.LoadScene(sceneName);
}
#endregion
}
}

61
Assets/Fungus/Scripts/Components/SaveGameHelper.cs

@ -0,0 +1,61 @@
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
namespace Fungus
{
public class SaveGameHelper : MonoBehaviour
{
[SerializeField] protected string startScene = "";
[SerializeField] protected SaveGameObjects saveGameObjects = new SaveGameObjects();
protected virtual void OnEnable()
{
SaveSignals.OnGameSave += OnGameSave;
}
protected virtual void OnDisable()
{
SaveSignals.OnGameSave -= OnGameSave;
}
protected virtual void OnGameSave(string saveKey, string saveDescription)
{
// TODO: Play sound effect
}
#region Public methods
public SaveGameObjects SaveGameObjects { get { return saveGameObjects; } }
public virtual void Save()
{
var saveManager = FungusManager.Instance.SaveManager;
saveManager.Save();
}
public virtual void Load()
{
var saveManager = FungusManager.Instance.SaveManager;
saveManager.Load();
}
public virtual void Rewind()
{
var saveManager = FungusManager.Instance.SaveManager;
saveManager.Rewind();
}
public virtual void Restart()
{
var saveManager = FungusManager.Instance.SaveManager;
saveManager.Clear();
SceneManager.LoadScene(startScene);
}
#endregion
}
}

0
Assets/Fungus/Scripts/Components/GameSaver.cs.meta → Assets/Fungus/Scripts/Components/SaveGameHelper.cs.meta

102
Assets/Fungus/Scripts/Components/SaveManager.cs

@ -5,112 +5,66 @@ namespace Fungus
{
public class SaveManager : MonoBehaviour
{
const string ActiveSlotKey = "active_slot";
const string DefaultSaveDataKey = "save_data";
const string SlotKeyFormat = "slot{0}";
protected static SaveHistory saveHistory = new SaveHistory();
protected string saveBuffer = "";
protected virtual string FormatSaveKey(int slot)
protected virtual void ReadSaveHistory(string saveDataKey)
{
return string.Format(SlotKeyFormat, slot);
}
protected virtual void StoreJSONData(string key, string jsonData)
var historyData = PlayerPrefs.GetString(saveDataKey);
if (!string.IsNullOrEmpty(historyData))
{
if (key.Length > 0)
var tempSaveHistory = JsonUtility.FromJson<SaveHistory>(historyData);
if (tempSaveHistory != null)
{
PlayerPrefs.SetString(key, jsonData);
saveHistory = tempSaveHistory;
}
}
}
protected virtual string LoadJSONData(string key)
protected virtual void WriteSaveHistory(string saveDataKey)
{
if (key.Length > 0)
var historyData = JsonUtility.ToJson(saveHistory, true);
if (!string.IsNullOrEmpty(historyData))
{
return PlayerPrefs.GetString(key);
PlayerPrefs.SetString(saveDataKey, historyData);
PlayerPrefs.Save();
}
return "";
}
#region Public members
public virtual int ActiveSlot
{
get
{
return PlayerPrefs.GetInt(ActiveSlotKey);
}
set
public virtual void Save(string saveDataKey = DefaultSaveDataKey)
{
PlayerPrefs.SetInt(ActiveSlotKey, value);
}
WriteSaveHistory(saveDataKey);
}
public virtual void Save()
public void Load(string saveDataKey = DefaultSaveDataKey)
{
if (saveBuffer == "")
ReadSaveHistory(saveDataKey);
if (saveHistory != null)
{
// Nothing to save
return;
saveHistory.LoadLatestSavePoint();
}
var key = FormatSaveKey(ActiveSlot);
PlayerPrefs.SetString(key, saveBuffer);
saveBuffer = "";
}
public virtual bool SlotExists(int slot)
{
var key = FormatSaveKey(slot);
if (PlayerPrefs.HasKey(key) &&
PlayerPrefs.GetString(key) != "")
public virtual void AddSavePoint(string saveKey, string saveDescription)
{
return false;
saveHistory.AddSavePoint(saveKey, saveDescription);
}
return true;
}
public virtual void Load(int slot)
public virtual void Rewind()
{
ActiveSlot = slot;
var key = FormatSaveKey(slot);
var saveDataJSON = LoadJSONData(key);
if (saveDataJSON != "")
if (saveHistory.NumSavePoints > 0)
{
SavePointData.Decode(saveDataJSON);
saveHistory.RemoveSavePoint();
saveHistory.LoadLatestSavePoint();
}
}
public virtual void LoadNewGame(int slot, string saveDescription)
{
var key = FormatSaveKey(slot);
var saveDataJSON = SavePointData.EncodeNewGame(saveDescription, SceneManager.GetActiveScene().name);
// Create a new save entry
PlayerPrefs.SetString(key, saveDataJSON);
SavePointLoaded.NotifyEventHandlers("new_game");
}
public virtual void Delete(int slot)
{
var key = FormatSaveKey(slot);
PlayerPrefs.DeleteKey(key);
}
public virtual void PopulateSaveBuffer(string saveKey, string description)
public virtual void Clear()
{
saveBuffer = SavePointData.Encode(saveKey, description, SceneManager.GetActiveScene().name);
Debug.Log(saveBuffer);
saveHistory.Clear();
}
#endregion

17
Assets/Fungus/Scripts/SavePoints/SaveGameObjects.cs

@ -0,0 +1,17 @@
using UnityEngine;
using System.Collections.Generic;
namespace Fungus
{
[System.Serializable]
public class SaveGameObjects
{
[SerializeField] protected List<Flowchart> flowcharts = new List<Flowchart>();
#region Public methods
public List<Flowchart> Flowcharts { get { return flowcharts; } }
#endregion
}
}

4
Assets/FungusExamples/SaveGame/SavePicker.cs.meta → Assets/Fungus/Scripts/SavePoints/SaveGameObjects.cs.meta

@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: 60a19f3f0e9b84b14b2b310a296de1b1
timeCreated: 1479485750
guid: f9c00b58b03474e37b54a4b39ed6c8ee
timeCreated: 1480503989
licenseType: Free
MonoImporter:
serializedVersion: 2

58
Assets/Fungus/Scripts/SavePoints/SaveHistory.cs

@ -0,0 +1,58 @@
using UnityEngine;
using System.Collections.Generic;
using Fungus;
using UnityEngine.SceneManagement;
namespace Fungus
{
[System.Serializable]
public class SaveHistory
{
/// <summary>
/// Version number of current save data format.
/// </summary>
protected const int SaveDataVersion = 1;
[SerializeField] protected int version = SaveDataVersion;
[SerializeField] protected List<string> savePoints = new List<string>();
#region Public methods
public int NumSavePoints { get { return savePoints.Count; } }
public void AddSavePoint(string saveKey, string saveDescription)
{
string sceneName = SceneManager.GetActiveScene().name;
var savePointData = SavePointData.Encode(saveKey, saveDescription, sceneName);
savePoints.Add(savePointData);
}
/// <summary>
/// Removes the latest save point.
/// </summary>
public void RemoveSavePoint()
{
if (savePoints.Count > 0)
{
savePoints.RemoveAt(savePoints.Count - 1);
}
}
public void LoadLatestSavePoint()
{
if (savePoints.Count > 0)
{
var savePointData = savePoints[savePoints.Count - 1];
SavePointData.Decode(savePointData);
}
}
public void Clear()
{
savePoints.Clear();
}
#endregion
}
}

4
Assets/Fungus/Scripts/Commands/LoadGame.cs.meta → Assets/Fungus/Scripts/SavePoints/SaveHistory.cs.meta

@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: 4bd5b7f5cc3944217aa05a6fa8552baf
timeCreated: 1478530280
guid: fd859426b9f7445b5a1d7281f4943bb8
timeCreated: 1480422606
licenseType: Free
MonoImporter:
serializedVersion: 2

47
Assets/Fungus/Scripts/SavePoints/SavePointData.cs

@ -7,12 +7,6 @@ namespace Fungus
[System.Serializable]
public class SavePointData
{
/// <summary>
/// Version number of current save data format.
/// </summary>
protected const int SavePointDataVersion = 0;
[SerializeField] protected int version;
[SerializeField] protected string saveKey;
[SerializeField] protected string description;
[SerializeField] protected string sceneName;
@ -36,19 +30,37 @@ namespace Fungus
FlowchartData.Decode(flowchartData);
}
SavePointLoaded.NotifyEventHandlers(savePointData.saveKey);
ExecuteBlocks(savePointData);
ExecuteBlocks(savePointData.saveKey);
}
protected static void ExecuteBlocks(SavePointData savePointData)
protected static void ExecuteBlocks(string saveKey)
{
SavePointLoaded.NotifyEventHandlers(saveKey);
// Execute any block containing a SavePoint command matching the save key, with Resume From Here enabled
var savePoints = Object.FindObjectsOfType<SavePoint>();
for (int i = 0; i < savePoints.Length; i++)
{
var savePoint = savePoints[i];
if (savePoint.ResumeFromHere &&
string.Compare(savePoint.SaveKey, saveKey, true) == 0)
{
int index = savePoint.CommandIndex;
var block = savePoint.ParentBlock;
var flowchart = savePoint.GetFlowchart();
flowchart.ExecuteBlock(block, index + 1);
// Assume there's only one SavePoint using this key
break;
}
}
// Execute any block containing a Label matching the save key
var labels = Object.FindObjectsOfType<Label>();
for (int i = 0; i < labels.Length; i++)
{
var label = labels[i];
if (string.Compare(label.Key, savePointData.SaveKey, true) == 0)
if (string.Compare(label.Key, saveKey, true) == 0)
{
int index = label.CommandIndex;
var block = label.ParentBlock;
@ -62,7 +74,6 @@ namespace Fungus
{
var savePointData = new SavePointData();
savePointData.version = 1;
savePointData.saveKey = _saveKey;
savePointData.description = _description;
savePointData.sceneName = _sceneName;
@ -79,7 +90,7 @@ namespace Fungus
public static string EncodeNewGame(string _description, string _sceneName)
{
var savePointData = Create("new_game", _description, _sceneName);
var savePointData = Create("start_game", _description, _sceneName);
return JsonUtility.ToJson(savePointData, true);
}
@ -88,16 +99,16 @@ namespace Fungus
{
var savePointData = Create(_saveKey, _description, _sceneName);
var gameSaver = GameObject.FindObjectOfType<GameSaver>();
if (gameSaver == null)
var saveGameHelper = GameObject.FindObjectOfType<SaveGameHelper>();
if (saveGameHelper == null)
{
Debug.LogError("Failed to find SaveHelper object in scene");
Debug.LogError("Failed to find SaveGameHelper object in scene");
return null;
}
for (int i = 0; i < gameSaver.Flowcharts.Count; i++)
for (int i = 0; i < saveGameHelper.SaveGameObjects.Flowcharts.Count; i++)
{
var flowchart = gameSaver.Flowcharts[i];
var flowchart = saveGameHelper.SaveGameObjects.Flowcharts[i];
var flowchartData = FlowchartData.Encode(flowchart);
savePointData.FlowchartDatas.Add(flowchartData);
}

23
Assets/Fungus/Scripts/Signals/SaveSignals.cs

@ -0,0 +1,23 @@
// This code is part of the Fungus library (http://fungusgames.com) maintained by Chris Gregan (http://twitter.com/gofungus).
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
namespace Fungus
{
/// <summary>
/// Save manager signalling system.
/// You can use this to be notified about various events in the save game system.
/// </summary>
public static class SaveSignals
{
#region Public members
/// <summary>
/// GameSave signal. Sent when the game is saved.
/// </summary>
public static event GameSaveHandler OnGameSave;
public delegate void GameSaveHandler(string saveKey, string saveDescription);
public static void DoGameSave(string saveKey, string saveDescription) { if (OnGameSave != null) OnGameSave(saveKey, saveDescription); }
#endregion
}
}

12
Assets/Fungus/Scripts/Signals/SaveSignals.cs.meta

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a47447a63010d4230884d0978a26f097
timeCreated: 1474988491
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

31
Assets/FungusExamples/SaveGame/Menu.unity

@ -335,7 +335,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: New Game
m_Text: Save Slot
--- !u!222 &274184161
CanvasRenderer:
m_ObjectHideFlags: 0
@ -409,9 +409,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 'New Game
'
m_Text: Save Slot
--- !u!222 &342006600
CanvasRenderer:
m_ObjectHideFlags: 0
@ -485,7 +483,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: New Game
m_Text: Save Slot
--- !u!222 &554677439
CanvasRenderer:
m_ObjectHideFlags: 0
@ -600,6 +598,13 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 60a19f3f0e9b84b14b2b310a296de1b1, type: 3}
m_Name:
m_EditorClassIdentifier:
quickSaveSlotDesc: Quick Save Slot
emptySlotDesc: Empty Slot
newSlotDesc: New Game
slotTexts:
- {fileID: 342006599}
- {fileID: 274184160}
- {fileID: 554677438}
--- !u!1 &829939242
GameObject:
m_ObjectHideFlags: 1
@ -1500,7 +1505,7 @@ GameObject:
- 114: {fileID: 1744305197}
- 114: {fileID: 1744305196}
m_Layer: 5
m_Name: Slot3
m_Name: Slot2
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -1643,21 +1648,19 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
version: 1
scrollPos: {x: 0, y: 0}
scrollPos: {x: 3.5126438, y: 1.8458961}
variablesScrollPos: {x: 0, y: 0}
variablesExpanded: 1
blockViewHeight: 400
zoom: 1
zoom: 0.9922716
scrollViewRect:
serializedVersion: 2
x: -343
y: -340
width: 1114
height: 859
selectedBlocks:
- {fileID: 1902192250}
selectedCommands:
- {fileID: 1902192253}
selectedBlocks: []
selectedCommands: []
variables: []
description:
stepPause: 0
@ -1697,7 +1700,7 @@ MonoBehaviour:
- {fileID: 1902192253}
--- !u!114 &1902192251
MonoBehaviour:
m_ObjectHideFlags: 0
m_ObjectHideFlags: 2
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1902192248}
@ -1723,7 +1726,7 @@ Transform:
m_RootOrder: 1
--- !u!114 &1902192253
MonoBehaviour:
m_ObjectHideFlags: 0
m_ObjectHideFlags: 2
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1902192248}

2441
Assets/FungusExamples/SaveGame/SaveExample.unity

File diff suppressed because it is too large Load Diff

8
Assets/FungusExamples/SaveGame/SaveExample.unity.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a440424aaf73a4ff3bf88e9d1eb3a43c
timeCreated: 1480421523
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

34
Assets/FungusExamples/SaveGame/SavePicker.cs

@ -1,34 +0,0 @@
using UnityEngine;
using System.Collections;
namespace Fungus
{
public class SavePicker : MonoBehaviour
{
[SerializeField] protected string newGameDescription = "Playing";
#region Public methods
public virtual void Select(int slot)
{
var saveManager = FungusManager.Instance.SaveManager;
if (saveManager.SlotExists(slot))
{
saveManager.Load(slot);
}
else
{
saveManager.LoadNewGame(slot, newGameDescription);
}
}
public virtual void Delete(int slot)
{
var saveManager = FungusManager.Instance.SaveManager;
saveManager.Delete(slot);
}
#endregion
}
}

5
Assets/FungusExamples/SaveGame/SceneA.unity

@ -371,8 +371,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
parentBlock: {fileID: 27697880}
saveKeys:
- save_1
saveKey:
--- !u!114 &27697880
MonoBehaviour:
m_ObjectHideFlags: 2
@ -444,7 +443,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
nodeRect:
serializedVersion: 2
x: 419
x: 420
y: 66
width: 120
height: 40

3
ProjectSettings/ProjectSettings.asset

@ -29,6 +29,7 @@ PlayerSettings:
m_StackTraceTypes: 010000000100000001000000010000000100000001000000
iosShowActivityIndicatorOnLoading: -1
androidShowActivityIndicatorOnLoading: -1
tizenShowActivityIndicatorOnLoading: -1
iosAppInBackgroundBehavior: 0
displayResolutionDialog: 1
iosAllowHTTPDownload: 1
@ -44,6 +45,7 @@ PlayerSettings:
runInBackground: 0
captureSingleScreen: 0
Override IPod Music: 0
muteOtherAudioSources: 0
Prepare IOS For Recording: 0
submitAnalytics: 1
usePlayerLog: 1
@ -144,6 +146,7 @@ PlayerSettings:
tvOSSmallIconLayers: []
tvOSLargeIconLayers: []
tvOSTopShelfImageLayers: []
tvOSTopShelfImageWideLayers: []
iOSLaunchScreenType: 0
iOSLaunchScreenPortrait: {fileID: 0}
iOSLaunchScreenLandscape: {fileID: 0}

Loading…
Cancel
Save