Udemy-Unity制作类暗黑破坏神游戏记录-P81

2024-09-18
190看过
前面我们在生命值中添加了存档系统的接口和捕获方法,通过存档系统可以报数据存储下来,将玩家的数据ID设为唯一,在Portal门户切换触发后,调用存档方法,异步加载场景之后在加载数据,这样在切换场景后,玩家的生命值也会同步一直更新,无论我们怎么切换场景后,两个场景的角色生命值都会同步,还需要在更新玩家时,先关闭寻路,等待更新完成后在开启寻路,这样防止坐标位置错乱。

设置存档数据ID


{9DAAB5EA-842D-4d1e-B72D-397592310178}.png

门户加载部分,这里有个BUG,教程中使用赋值然后查找SavingWrapper组件,SavingWrapper wrapper = FindObjectOfType<SavingWrapper>()
但是在运行游戏后,切换场景时,会导致获取SavingWrapper为空的bug。
具体原因是因为切换场景时,虽然通过赋值寻找了SavingWrapper组件,然后Save(),但是在异步加载完成之后,直接用赋值的wrapper调用Load(),
代码执行到这里时由于场景已经切换,这个时候就会出现空引用,所以这里其实还需要FindObjectOfType一次,这样就不会用问题。
{A43373D3-7451-4864-B193-7CF9727CF43F}.png

完整代码如下:
Portal

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using Unity.VisualScripting;
  4. using UnityEngine;
  5. using UnityEngine.AI;
  6. using UnityEngine.SceneManagement;
  7. namespace RPG.SceneMangement
  8. {
  9.     //// Portal触发传送 类用于在玩家进入触发器时异步加载新场景
  10.     public class Portal : MonoBehaviour
  11.     {
  12.         enum DestinationIdentifier
  13.         {
  14.             A, B, C,D,E
  15.         }
  16.         [SerializeField] int sceneToLoad = 1;// 要加载的场景索引,默认为1
  17.         [SerializeField] Transform spawnPoint;// 玩家传送后的出生点位置和旋转
  18.         [SerializeField] DestinationIdentifier destination;//给触发器设置目的地
  19.         [SerializeField] float fadeOutTime = 1f;//淡出时间
  20.         [SerializeField] float fadeInTime = 2f;//淡入时间
  21.         [SerializeField] float fadeWaitTime = 0.5f;//等待时间
  22.         
  23.         Fader fader;
  24.         
  25.         private void Start()
  26.         {
  27.              fader = FindObjectOfType<Fader>();// 查找场景中的第一个 Fader 实例
  28.             
  29.         }
  30.         // 当触发器碰撞到其他对象时调用
  31.         private void OnTriggerEnter(Collider other)
  32.         {
  33.            
  34.             // 如果碰撞的对象标签是 "Player"
  35.             if (other.tag == "Player")
  36.             {
  37.                 // 启动协程来处理场景过渡
  38.                 StartCoroutine(Transition());
  39.             }
  40.             
  41.         }
  42.         // 协程方法:处理场景的异步加载和玩家的位置更新
  43.         private IEnumerator Transition()
  44.         {
  45.             if(sceneToLoad <0)// 如果场景索引无效(小于0),则退出协程
  46.             {
  47.                 yield break;
  48.             }
  49.             
  50.             DontDestroyOnLoad(gameObject);// 确保 Portal 对象在加载新场景时不会被销毁
  51.            
  52.             yield return fader.FadeOut(fadeOutTime);// 执行淡出效果
  53.             print("开始存档");
  54.             //SavingWrapper wrapper = FindObjectOfType<SavingWrapper>();//使用赋值会导致在切换场景后出现为空的bug
  55.             FindObjectOfType<SavingWrapper>().Save();//存档文件
  56.            
  57.             yield return SceneManager.LoadSceneAsync(sceneToLoad); // 异步加载指定的场景
  58.             print("加载存档");
  59.             FindObjectOfType<SavingWrapper>().Load();//加载存档数据中的数据
  60.            
  61.             Portal otherPortal = GetOtherPortal(); // 查找另一个 Portal 对象(目标场景中的传送门)
  62.             UpdatePlayer(otherPortal);// 更新玩家位置和旋转
  63.             yield return new WaitForSeconds(fadeWaitTime);// 等待指定的时间(用于过渡或延迟)
  64.             yield return fader.FadeIn(fadeInTime);// 执行淡入效果,等待淡入完成
  65.             
  66.             Destroy(gameObject);// 场景加载完成后,销毁当前的 Portal 对象,防止两个场景的Portal重叠出现问题
  67.         }
  68.         // 更新玩家的位置和旋转,使其在目标场景中出现在正确的位置
  69.         private void UpdatePlayer(Portal otherPortal)
  70.         {
  71.             GameObject player = GameObject.FindWithTag("Player");// 查找场景中的玩家对象
  72.             // 使用 Warp 方法将玩家传送到新的出生点位置
  73.             player.GetComponent<NavMeshAgent>().enabled = false;//关闭角色的巡逻组件
  74.             player.GetComponent<NavMeshAgent>().Warp(otherPortal.spawnPoint.position);
  75.             // 设置玩家的旋转角度
  76.             player.transform.rotation = otherPortal.spawnPoint.rotation;
  77.             player.GetComponent<NavMeshAgent>().enabled = true;//启用角色的巡逻组件
  78.         }
  79.         // 查找并返回目标场景中的另一个 Portal 对象
  80.         private Portal GetOtherPortal()
  81.         {
  82.             // 遍历所有的 Portal 对象
  83.             foreach (Portal portal in FindObjectsOfType<Portal>())
  84.             {
  85.                
  86.                 if (portal == this) continue;// 跳过当前的 Portal 对象
  87.                 // 如果两个触发传送的目的地设置不一样,则跳过该对象,继续检查下一个 portal
  88.                 if (portal.destination != destination) continue;
  89.                 return portal; // 返回第一个找到的不同的 Portal 对象
  90.             }
  91.             return null;// 如果没有找到其他 Portal,则返回 null
  92.         }
  93.       
  94.     }
  95. }
复制代码




回复

举报

 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表