目录
(一)玩家数据保存
(二)制作主菜单
(三)制作NewGame场景转换
(四)制作场景渐入渐出
(五)玩家死亡返回Menu
(一)玩家数据保存
创建新的脚本SaveManager专门负责保存数据。为了能够随时调用并保存数据,所以使用泛型单例与设置DontDestroyOnLoad。玩家数据的保存则使用JsonUtility+PlayerPrefs的形式存储,PlayerPrefs提供给玩家int,float,string三个类型进行储存与修改,以键值对的形式存储;而JsonUtility可以对ScriptableObject等类进行存储。存储时先将数据转为json格式,再使用PlayerPrefs进行存储,读取同理。
保存的数据需要在转换场景时仍然保存,在SceneController的传送协程中,切换场景之前和之后分别进行Save和Load。(顺便把其他场景的UI补上)
SaveManager:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SaveManager : Singleton<SaveManager> { protected override void Awake() { base.Awake(); DontDestroyOnLoad(this);//防止Manager被销毁 } private void Update() { if(Input.GetKeyDown(KeyCode.S)) { SavePlayerData(); } if (Input.GetKeyDown(KeyCode.L)) { LoadPlayerData(); } } public void SavePlayerData()//存储玩家数据 { Save(GameManager.Instance.playerStats.characterData, GameManager.Instance.playerStats.characterData.name); } public void LoadPlayerData() { Load(GameManager.Instance.playerStats.characterData, GameManager.Instance.playerStats.characterData.name); } public void Save(object data, string key) { var jsonData = JsonUtility.ToJson(data,true);//数据格式转换为json PlayerPrefs.SetString(key, jsonData);//构造键值对与存储 PlayerPrefs.Save(); } public void Load(object data, string key) { if(PlayerPrefs.HasKey(key))//找到key则读取 { JsonUtility.FromJsonOverwrite(PlayerPrefs.GetString(key), data); } } }
讯享网
(二)制作主菜单
首先进行主菜单场景的布置,注意当利用player等prefab进行布置时,最好解包并关闭一些组件。
创建菜单Canvas,调整比例并添加配件。当UI字体模糊时,尝试提高字号的同时将Scale调小会使字体清晰。将Canvas的RenderMode调整为Camera,这样UI界面就在所设定的摄像机的视野中进行布局,再改成WorldSpace模式就可以以合适的初始位置来调整UI的空间视觉效果(自己的作业本来不想改,但是后面做转换效果更好所以改了。)。
下面编写主菜单的脚本并挂载到主菜单Canvas上。主菜单的功能按钮在脚本中以事件的形式产生作用,可以采用button.onClick.AddListener(xxx)来为按钮事件添加xxx方法。新游戏和继续游戏都需要转换到对应场景并加载Player,这需要在SceneController中再写一个新的协程,在GameManager中完成获得场景入口的方法:
讯享网public Transform GetEntrance() { foreach(var i in FindObjectsOfType<TransitionDestination>()) { if(i.destinationTag== TransitionDestination.DestinationTag.Enter) { return i.transform; } } return null; }
这样在协程中调用此方法来作为player生成的位置。完成场景加载和玩家生成后,保存数据并结束协程。协程在方法中调用,而方法与事件绑定。(泛型单例在重复时会删除到只剩一个,所以不用担心Manager重复)。传送方法:
//给NewGame使用跳转到第一个场景 public void TransitionToFirstScene() { StartCoroutine(LoadLevel("Level1")); } IEnumerator LoadLevel(string sceneName) { if(sceneName!="")//找到场景,跳转并生成player { yield return SceneManager.LoadSceneAsync(sceneName); yield return player = Instantiate(PlayerPrefab, GameManager.Instance.GetEntrance().position, GameManager.Instance.GetEntrance().rotation); //保存数据以便下次继续游戏 SaveManager.Instance.SavePlayerData(); yield break; } }
最后在按钮处调用即可。
读档需要让玩家也能回到原本的场景,因此需要在Save同时保存所在场景到PlayerPrefs中,并在SceneController实现读取游戏的传送方法:
讯享网public void TransitionToLoadScene() { StartCoroutine(LoadLevel(SaveManager.Instance.SceneName)); }
玩家数据的读取则应当在player开始时获取,所以写在PlayerController的start中,且玩家注册到游戏中的步骤则应该调整到OnEnable中。可以在Manager的Update中判断按下Input.GetKeyDown(KeyCode.Escape),是则跳转回主界面,跳转本身的实现则需要像上面一样在SceneController中再写一次方法和协程:
public void TransitionToMainScene() { StartCoroutine(LoadMain()); } IEnumerator LoadMain() { yield return SceneManager.LoadSceneAsync("Main"); yield break; }
这样主菜单的基本功能就完成了,此时的存档会在按下对应按键(Update中设置)、开始与加载游戏以及跨场景传送时触发。
(三)制作NewGame场景转换
单纯的卡顿不利于场景转换的表现,下面需要制作场景的转换效果。Timeline是一种针对多对象的动画制作功能,一般用于过场动画的制作,其实际操作类似于PR,将需要控制的物体拖入左侧可以创建track,然后通过录制关键帧来控制动画的播放。比如在相机的Transform position上右键添加Key,就可以在相机的track上添加一个关键帧,两个关键帧之间则会自动产生动画效果。录制希望添加效果的对象的track。对于可以使用Animation的对象,Timeline可以直接将动画拖到时间轴上来播放。对于播放动画时的位置偏移,可以选择Add override track,在一条附属轨道上录制正确的位置动画。
制作的动画希望在点击New Game时播放,所以要取消director的Awake时播放,在MainMenuUI脚本中控制director,director的stopped是动画结束时的事件,所以可以将NewGame注册到这一事件中来,修改一下参数即可。
对于动画播放中仍然可以用键盘控制按钮的问题,可以在Timeline中创建EventSystem的Activation track,删掉active段。

(四)制作场景渐入渐出
使用Canvas Group制作SceneFader效果。创建Canvas并令其image覆盖屏幕,然后添加组件Canvas Group,通过调整其Alpha值来实现渐入渐出的视觉效果,使用脚本SceneFader 控制。
由于透明度的调整与场景加载同步进行,所以采用协程的形式实现,协程的嵌套则可以在yield return中进行:
讯享网using System.Collections; using System.Collections.Generic; using UnityEngine; public class SceneFader : MonoBehaviour { CanvasGroup canvasGroup; public float fadeInDuration;//渐入时间 public float fadeoutDuration;//渐出时间 private void Awake() { canvasGroup = GetComponent<CanvasGroup>(); DontDestroyOnLoad(this); } public IEnumerator FadeOutToIn()//完整渐入渐出 { yield return FadeOut(fadeoutDuration); yield return FadeIn(fadeInDuration); } public IEnumerator FadeOut(float time)//alpha 0-1,渐出 { while (canvasGroup.alpha < 1) { canvasGroup.alpha += Time.deltaTime / time;//??? yield return null; } } public IEnumerator FadeIn(float time)//alpha 1-0,渐入 { while (canvasGroup.alpha !=0) { canvasGroup.alpha -= Time.deltaTime / time;//??? yield return null; } } }
剩下只需要在转换场景前后调用协程即可。
(五)玩家死亡返回Menu
玩家死亡时GameManager发出广播,可让SceneController也监听并执行返回菜单操作。加入监听操作见敌人制作部分(继承与注册)。收到广播方法后启动返回主菜单协程即可。
为了防止GameManager持续广播导致SceneController执行过多游戏崩溃,要在SceneController设置bool flag进行判断,并在每次新游戏开始时重置flag保证其功能正常
(六)打包与运行
将初步完成的项目打包,从而能够脱离unity编辑器来运行。
打包前需要调整Build Settings,需要把涉及到的场景都添加上,并设置运行的平台环境。名字和图标等设置则在左下角的PlayerSettings中。需要多平台支持的话,可以事先在UnityHub中为编辑器添加模块,就可以在PlayerSettings中设置了。更改打包方式为IL2CPP可以比Mono减少游戏大小,且更难反编译。
打包前要在Edit菜单中清除所有PlayerPrefs,防止将测试存档带入打包文件。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/28835.html