公司网站制作申请报告,多少钱用英语怎么说,凡客登录入口,深圳58同城招聘网最新招聘信息我的最终目标是快读建立一个关卡数据自动读入储存功能#xff1a;
1. 每个关卡有自己的编号#xff0c;如果没有自定义该关卡#xff0c;则读取默认编号的初始布局#xff0c;如果有自定义该关卡#xff0c;则读取新定义的关卡。
2.在游戏中如果对布局做出了更改#x…我的最终目标是快读建立一个关卡数据自动读入储存功能
1. 每个关卡有自己的编号如果没有自定义该关卡则读取默认编号的初始布局如果有自定义该关卡则读取新定义的关卡。
2.在游戏中如果对布局做出了更改随时储存新的修改。
3.save和load系统与玩法系统耦合度低无需管理。 小试牛刀-soundmanager
先从一个简单的soundmanager开始学习。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace BBG
{public class SaveManager : SingletonComponentSaveManager{#region Member Variablesprivate ListISaveable saveables;private JSONNode loadedSave;#endregion#region Properties/// summary/// Path to the save file on the device/// /summarypublic string SaveFilePath { get { return Application.persistentDataPath /save.json; } }/// summary/// List of registered saveables/// /summaryprivate ListISaveable Saveables{get{if (saveables null){saveables new ListISaveable();}return saveables;}}#endregion#if UNITY_EDITOR[UnityEditor.MenuItem(Tools/Bizzy Bee Games/Delete Save Data)]public static void DeleteSaveData(){if (!System.IO.File.Exists(SaveManager.Instance.SaveFilePath)){UnityEditor.EditorUtility.DisplayDialog(Delete Save File, There is no save file., Ok);return;}bool delete UnityEditor.EditorUtility.DisplayDialog(Delete Save File, Delete the save file located at SaveManager.Instance.SaveFilePath, Yes, No);if (delete){System.IO.File.Delete(SaveManager.Instance.SaveFilePath);#if BBG_MT_IAP || BBG_MT_ADSSystem.IO.Directory.Delete(BBG.MobileTools.Utils.SaveFolderPath, true);#endifUnityEditor.EditorUtility.DisplayDialog(Delete Save File, Save file has been deleted., Ok);}}#endif#region Unity Methodsprivate void Start(){Debug.Log(Save file path: SaveFilePath);}private void OnDestroy(){Save();}private void OnApplicationPause(bool pause){if (pause){Save();}}#endregion#region Public Methods/// summary/// Registers a saveable to be saved/// /summarypublic void Register(ISaveable saveable){Saveables.Add(saveable);}/// summary/// Loads the save data for the given saveable/// /summarypublic JSONNode LoadSave(ISaveable saveable){return LoadSave(saveable.SaveId);}/// summary/// Loads the save data for the given save id/// /summarypublic JSONNode LoadSave(string saveId){// Check if the save file has been loaded and if not try and load itif (loadedSave null !LoadSave(out loadedSave)){return null;}// Check if the loaded save file has the given save idif (!loadedSave.AsObject.HasKey(saveId)){return null;}// Return the JSONNode for the save idreturn loadedSave[saveId];}#endregion#region Private Methods/// summary/// Saves all registered saveables to the save file/// /summaryprivate void Save(){Dictionarystring, object saveJson new Dictionarystring, object();for (int i 0; i saveables.Count; i){saveJson.Add(saveables[i].SaveId, saveables[i].Save());}System.IO.File.WriteAllText(SaveFilePath, Utilities.ConvertToJsonString(saveJson));}/// summary/// Tries to load the save file/// /summaryprivate bool LoadSave(out JSONNode json){json null;if (!System.IO.File.Exists(SaveFilePath)){return false;}json JSON.Parse(System.IO.File.ReadAllText(SaveFilePath));return json ! null;}#endregion}
}以上代码中的Register函数很重要其他的需要储存数据的模块比如soundmanager就需要继承Isavable,并且在初始化时register自己给savemanager:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace BBG
{public class SoundManager : SingletonComponentSoundManager, ISaveable{#region Classes[System.Serializable]private class SoundInfo{public string id ;public AudioClip audioClip null;public SoundType type SoundType.SoundEffect;public bool playAndLoopOnStart false;[Range(0, 1)] public float clipVolume 1;}private class PlayingSound{public SoundInfo soundInfo null;public AudioSource audioSource null;}#endregion#region Enumspublic enum SoundType{SoundEffect,Music}#endregion#region Inspector Variables[SerializeField] private ListSoundInfo soundInfos null;#endregion#region Member Variablesprivate ListPlayingSound playingAudioSources;private ListPlayingSound loopingAudioSources;public string SaveId { get { return sound_manager; } }#endregion#region Propertiespublic bool IsMusicOn { get; private set; }public bool IsSoundEffectsOn { get; private set; }#endregion#region Unity Methodsprotected override void Awake(){base.Awake();SaveManager.Instance.Register(this);playingAudioSources new ListPlayingSound();loopingAudioSources new ListPlayingSound();if (!LoadSave()){IsMusicOn true;IsSoundEffectsOn true;}}private void Start(){for (int i 0; i soundInfos.Count; i){SoundInfo soundInfo soundInfos[i];if (soundInfo.playAndLoopOnStart){Play(soundInfo.id, true, 0);}}}private void Update(){for (int i 0; i playingAudioSources.Count; i){AudioSource audioSource playingAudioSources[i].audioSource;// If the Audio Source is no longer playing then return it to the pool so it can be re-usedif (!audioSource.isPlaying){Destroy(audioSource.gameObject);playingAudioSources.RemoveAt(i);i--;}}}#endregion#region Public Methods/// summary/// Plays the sound with the give id/// /summarypublic void Play(string id){Play(id, false, 0);}/// summary/// Plays the sound with the give id, if loop is set to true then the sound will only stop if the Stop method is called/// /summarypublic void Play(string id, bool loop, float playDelay){SoundInfo soundInfo GetSoundInfo(id);if (soundInfo null){Debug.LogError([SoundManager] There is no Sound Info with the given id: id);return;}if ((soundInfo.type SoundType.Music !IsMusicOn) ||(soundInfo.type SoundType.SoundEffect !IsSoundEffectsOn)){return;}AudioSource audioSource CreateAudioSource(id);audioSource.clip soundInfo.audioClip;audioSource.loop loop;audioSource.time 0;audioSource.volume soundInfo.clipVolume;if (playDelay 0){audioSource.PlayDelayed(playDelay);}else{audioSource.Play();}PlayingSound playingSound new PlayingSound();playingSound.soundInfo soundInfo;playingSound.audioSource audioSource;if (loop){loopingAudioSources.Add(playingSound);}else{playingAudioSources.Add(playingSound);}}/// summary/// Stops all playing sounds with the given id/// /summarypublic void Stop(string id){StopAllSounds(id, playingAudioSources);StopAllSounds(id, loopingAudioSources);}/// summary/// Stops all playing sounds with the given type/// /summarypublic void Stop(SoundType type){StopAllSounds(type, playingAudioSources);StopAllSounds(type, loopingAudioSources);}/// summary/// Sets the SoundType on/off/// /summarypublic void SetSoundTypeOnOff(SoundType type, bool isOn){switch (type){case SoundType.SoundEffect:if (isOn IsSoundEffectsOn){return;}IsSoundEffectsOn isOn;break;case SoundType.Music:if (isOn IsMusicOn){return;}IsMusicOn isOn;break;}// If it was turned off then stop all sounds that are currently playingif (!isOn){Stop(type);}// Else it was turned on so play any sounds that have playAndLoopOnStart set to trueelse{PlayAtStart(type);}}#endregion#region Private Methods/// summary/// Plays all sounds that are set to play on start and loop and are of the given type/// /summaryprivate void PlayAtStart(SoundType type){for (int i 0; i soundInfos.Count; i){SoundInfo soundInfo soundInfos[i];if (soundInfo.type type soundInfo.playAndLoopOnStart){Play(soundInfo.id, true, 0);}}}/// summary/// Stops all sounds with the given id/// /summaryprivate void StopAllSounds(string id, ListPlayingSound playingSounds){for (int i 0; i playingSounds.Count; i){PlayingSound playingSound playingSounds[i];if (id playingSound.soundInfo.id){playingSound.audioSource.Stop();Destroy(playingSound.audioSource.gameObject);playingSounds.RemoveAt(i);i--;}}}/// summary/// Stops all sounds with the given type/// /summaryprivate void StopAllSounds(SoundType type, ListPlayingSound playingSounds){for (int i 0; i playingSounds.Count; i){PlayingSound playingSound playingSounds[i];if (type playingSound.soundInfo.type){playingSound.audioSource.Stop();Destroy(playingSound.audioSource.gameObject);playingSounds.RemoveAt(i);i--;}}}private SoundInfo GetSoundInfo(string id){for (int i 0; i soundInfos.Count; i){if (id soundInfos[i].id){return soundInfos[i];}}return null;}private AudioSource CreateAudioSource(string id){GameObject obj new GameObject(sound_ id);obj.transform.SetParent(transform);return obj.AddComponentAudioSource();;}#endregion#region Save Methodspublic Dictionarystring, object Save(){Dictionarystring, object json new Dictionarystring, object();json[is_music_on] IsMusicOn;json[is_sound_effects_on] IsSoundEffectsOn;return json;}public bool LoadSave(){JSONNode json SaveManager.Instance.LoadSave(this);if (json null){return false;}IsMusicOn json[is_music_on].AsBool;IsSoundEffectsOn json[is_sound_effects_on].AsBool;return true;}#endregion}
}如上所述的soundmanager,里面有两个内容是告知savemanager如何自动储存信息的
public string SaveId { get { return sound_manager; } } public Dictionarystring, object Save(){Dictionarystring, object json new Dictionarystring, object();json[is_music_on] IsMusicOn;json[is_sound_effects_on] IsSoundEffectsOn;return json;}
另外观察soundmanager可知它在初始化时去做了一次loadsave函数也就是去找savemanager要数据如果要到了怎样设置如果没有要到怎样设置。
public bool LoadSave(){JSONNode json SaveManager.Instance.LoadSave(this);if (json null){return false;}IsMusicOn json[is_music_on].AsBool;IsSoundEffectsOn json[is_sound_effects_on].AsBool;return true;} 实战—关卡储存管理
先看一下这个gamemanager中与储存相关的代码 public Dictionarystring, object Save(){Dictionarystring, object json new Dictionarystring, object();json[num_stars_earned] SaveNumStarsEarned();json[last_completed] SaveLastCompleteLevels();json[level_statuses] SaveLevelStatuses();json[level_save_datas] SaveLevelDatas();json[star_amount] StarAmount;json[hint_amount] HintAmount;json[num_levels_till_ad] NumLevelsTillAd;return json;}private Listobject SaveNumStarsEarned(){Listobject json new Listobject();foreach (KeyValuePairstring, int pair in packNumStarsEarned){Dictionarystring, object packJson new Dictionarystring, object();packJson[pack_id] pair.Key;packJson[num_stars_earned] pair.Value;json.Add(packJson);}return json;}private Listobject SaveLastCompleteLevels(){Listobject json new Listobject();foreach (KeyValuePairstring, int pair in packLastCompletedLevel){Dictionarystring, object packJson new Dictionarystring, object();packJson[pack_id] pair.Key;packJson[last_completed_level] pair.Value;json.Add(packJson);}return json;}private Listobject SaveLevelStatuses(){Listobject json new Listobject();foreach (KeyValuePairstring, Dictionaryint, int pair in packLevelStatuses){Dictionarystring, object packJson new Dictionarystring, object();packJson[pack_id] pair.Key;string levelStr ;foreach (KeyValuePairint, int levelPair in pair.Value){if (!string.IsNullOrEmpty(levelStr)) levelStr _;levelStr levelPair.Key _ levelPair.Value;}packJson[level_statuses] levelStr;json.Add(packJson);}return json;}private Listobject SaveLevelDatas(){Listobject savedLevelDatas new Listobject();foreach (KeyValuePairstring, LevelSaveData pair in levelSaveDatas){Dictionarystring, object levelSaveDataJson pair.Value.Save();levelSaveDataJson[id] pair.Key;savedLevelDatas.Add(levelSaveDataJson);}return savedLevelDatas;}private bool LoadSave(){JSONNode json SaveManager.Instance.LoadSave(this);if (json null){return false;}LoadNumStarsEarned(json[num_stars_earned].AsArray);LoadLastCompleteLevels(json[last_completed].AsArray);LoadLevelStatuses(json[level_statuses].AsArray);LoadLevelSaveDatas(json[level_save_datas].AsArray);StarAmount json[star_amount].AsInt;HintAmount json[hint_amount].AsInt;NumLevelsTillAd json[num_levels_till_ad].AsInt;return true;}private void LoadNumStarsEarned(JSONArray json){for (int i 0; i json.Count; i){JSONNode childJson json[i];string packId childJson[pack_id].Value;int numStarsEarned childJson[num_stars_earned].AsInt;packNumStarsEarned.Add(packId, numStarsEarned);}}private void LoadLastCompleteLevels(JSONArray json){for (int i 0; i json.Count; i){JSONNode childJson json[i];string packId childJson[pack_id].Value;int lastCompletedLevel childJson[last_completed_level].AsInt;packLastCompletedLevel.Add(packId, lastCompletedLevel);}}private void LoadLevelStatuses(JSONArray json){for (int i 0; i json.Count; i){JSONNode childJson json[i];string packId childJson[pack_id].Value;string[] levelStatusStrs childJson[level_statuses].Value.Split(_);Dictionaryint, int levelStatuses new Dictionaryint, int();for (int j 0; j levelStatusStrs.Length; j 2){int levelIndex System.Convert.ToInt32(levelStatusStrs[j]);int status System.Convert.ToInt32(levelStatusStrs[j 1]);levelStatuses.Add(levelIndex, status);}packLevelStatuses.Add(packId, levelStatuses);}}/// summary/// Loads the game from the saved json file/// /summaryprivate void LoadLevelSaveDatas(JSONArray savedLevelDatasJson){// Load all the placed line segments for levels that have progressfor (int i 0; i savedLevelDatasJson.Count; i){JSONNode savedLevelDataJson savedLevelDatasJson[i];JSONArray savedPlacedLineSegments savedLevelDataJson[placed_line_segments].AsArray;JSONArray savedHints savedLevelDataJson[hints].AsArray;ListListCellPos placedLineSegments new ListListCellPos();for (int j 0; j savedPlacedLineSegments.Count; j){placedLineSegments.Add(new ListCellPos());for (int k 0; k savedPlacedLineSegments[j].Count; k 2){placedLineSegments[j].Add(new CellPos(savedPlacedLineSegments[j][k].AsInt, savedPlacedLineSegments[j][k 1].AsInt));}}Listint hintLineIndices new Listint();for (int j 0; j savedHints.Count; j){hintLineIndices.Add(savedHints[j].AsInt);}string levelId savedLevelDataJson[id].Value;int numMoves savedLevelDataJson[num_moves].AsInt;LevelSaveData levelSaveData new LevelSaveData();levelSaveData.placedLineSegments placedLineSegments;levelSaveData.numMoves numMoves;levelSaveData.hintLineIndices hintLineIndices;levelSaveDatas.Add(levelId, levelSaveData);}}#endregion
我们发现因为数据较为复杂无论是load还是save都针对不同数据有自己的辅助函数。 gamemanager中有一个startlevel,它需要一个packinfo(总关卡信息可暂时忽略)以及一个leveldata.
这里拿到的leveldata,是制作者本身就默认写好的值
如果这个leveldata的id已经存在于levelsavedata的字典中就说明这个leveldata经过了修改因此要读取的是新的levelsavedata中的配置数据。
如果这个leveldata的id没有存在于levelsavedata的字典中就说明这次是第一次打开这个level那么需要新建一个savedata:
下面的代码记录了这个功能。
/// summary/// Starts the level./// /summarypublic void StartLevel(PackInfo packInfo, LevelData levelData){ActivePackInfo packInfo;ActiveLevelData levelData;// Check if the lvel has not been started and if there is loaded save data for itif (!levelSaveDatas.ContainsKey(levelData.Id)){levelSaveDatas[levelData.Id] new LevelSaveData();}gameGrid.SetupLevel(levelData, levelSaveDatas[levelData.Id]);UpdateHintAmountText();UpdateLevelButtons();GameEventManager.Instance.SendEvent(GameEventManager.EventId_LevelStarted);ScreenManager.Instance.Show(game);// Check if its time to show an interstitial adif (NumLevelsTillAd 0){NumLevelsTillAd numLevelsBetweenAds;#if BBG_MT_ADSBBG.MobileTools.MobileAdsManager.Instance.ShowInterstitialAd();#endif}}其他的功能基本上和soundmanager一样
比如在初始化时注册自己并试图loadsave.
比如在游戏中断时进行保存 protected override void Awake(){base.Awake();GameEventManager.Instance.RegisterEventHandler(GameEventManager.EventId_ActiveLevelCompleted, OnActiveLevelComplete);SaveManager.Instance.Register(this);packNumStarsEarned new Dictionarystring, int();packLastCompletedLevel new Dictionarystring, int();packLevelStatuses new Dictionarystring, Dictionaryint, int();levelSaveDatas new Dictionarystring, LevelSaveData();if (!LoadSave()){HintAmount startingHints;NumLevelsTillAd numLevelsBetweenAds;}gameGrid.Initialize();if (startingStars 0){StarAmount startingStars;}}private void OnDestroy(){Save();}private void OnApplicationPause(bool pause){if (pause){Save();}}至此重点结束。
然后其他功能的脚本可以通过获得currentlevelsavedata的方式去修改其数据方便在关闭界面时进行数据更新。
/// summary/// Sets the numMoves and updates the Text UI/// /summaryprivate void SetNumMoves(int amount){currentLevelSaveData.numMoves amount;moveAmountText.text currentLevelSaveData.numMoves.ToString();}
围绕这个功能还可以方便设计undo/redo功能