【迷失岛游戏框架开发个人每集总结(第四期)】

文章介绍了在Unity中如何使用ObjectManager类来管理物品状态,包括在场景卸载前保存物品的可用性和互动状态,并在场景加载后恢复这些状态。EventHandler类用于触发和响应场景切换事件,TransitionManager负责场景的无缝过渡。通过这些机制,确保了游戏状态在场景切换后的一致性。
摘要由CSDN通过智能技术生成

系列文章目录

迷失岛游戏框架开发个人每集总结(第一期)
迷失岛游戏框架开发个人每集总结(第二期)
迷失岛游戏框架开发个人每集总结(第三期)

前言

在上一期中,我们实现了通过鼠标点击带有标签“item”的物体,根据物品的名称在已设置好的,内容为物品的名称及其对应图片的列表里寻找该物品信息,该物体的图片、名称以及将对应的序号传给订阅获取这些信息事件的InventoryUI。根据这些信息对我们的ui进行更新。
这一期要实现的是保存物品在场景中的状态,以及互动的状态。这样在切换场景后就不会出现例如:刚刚在该场景拾取了钥匙,切换场景回来后钥匙依旧在该场景里显示的情况。

1

1.1

ObjectManager 用于管理物品状态

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//用于保存物品以及的状态
//场景第一次被加载进来之后,我要记录有哪些物体来构成我们的字典,并且场景里还有一些互动,在卸载这个场景之前,我要记录它们的状态
 
public class ObjectManager : MonoBehaviour
{
    //创建一个字典,储存物品的名字以及判断该物品是否可用的布尔值
    private Dictionary<ItemName, bool> itemAvailableDict = new Dictionary<ItemName, bool>();

    private Dictionary<string, bool> interactiveStateDict = new Dictionary<string, bool>();//保存互动状态


    //注册事件的方法
    private void OnEnable()
    {
        EventHandler.BeforeSceneUnloadEvent += OnBeforeSceneUnloadEvent;
        EventHandler.AfterSceneUnloadEvent += OnAfterSceneUnloadEvent;
        EventHandler.updateUIEvent += OnUpdateUIEvent;
    }
    private void OnDisable()
    {
        EventHandler.BeforeSceneUnloadEvent -= OnBeforeSceneUnloadEvent;
        EventHandler.AfterSceneUnloadEvent -= OnAfterSceneUnloadEvent;
        EventHandler.updateUIEvent -= OnUpdateUIEvent;
    }

    private void OnBeforeSceneUnloadEvent()
    {
        foreach (var item in FindObjectsOfType<Item>())
        {
            if (!itemAvailableDict.ContainsKey(item.itemName))
                itemAvailableDict.Add(item.itemName, true);//true代表在当前场景中该物体是显示状态
          
        }

        foreach (var item in FindObjectsOfType<Interactive>())
        {
            if (interactiveStateDict.ContainsKey(item.name))
                interactiveStateDict[item.name] = item.isDone;
            else
                interactiveStateDict.Add(item.name, item.isDone);
        }

    }


    private void OnAfterSceneUnloadEvent()
    {
        //如果已经在字典中则更新显示状态,不在则添加
        foreach(var item in FindObjectsOfType<Item>())
        {
            if (!itemAvailableDict.ContainsKey(item.itemName))
                itemAvailableDict.Add(item.itemName, true);
            else
                item.gameObject.SetActive(itemAvailableDict[item.itemName]);
        }

        foreach (var item in FindObjectsOfType<Interactive>())
        {
            if (interactiveStateDict.ContainsKey(item.name))
             item.isDone=interactiveStateDict[item.name] ;
            else
                interactiveStateDict.Add(item.name, item.isDone);
        }
    }

    //只在拾取物品后更新
    private void OnUpdateUIEvent(ItemDetails itemDetails ,int arg2)
    {
        if(itemDetails!=null)
        {
            itemAvailableDict[itemDetails.itemName] = false;
        }
    }
}

OnBeforeSceneUnloadEvent()
这段代码实现了一个名为 OnBeforeSceneUnloadEvent 的函数,它是在 Unity 场景销毁前执行的事件回调函数。

具体来说,该函数会获取场景中所有类型为 Item 的游戏对象,依次遍历这些游戏对象,然后将每个对象的 itemName 属性作为键值,
在 itemAvailableDict 字典中添加一个布尔型的值(如果该键值不存在)。itemAvailableDict 是一个存储 Item 对象可用性的字典
在这个场景被卸载前,我们需要将场景中所有 Item 对象的可用性信息收集起来,并保存到该字典中。

具体而言,FindObjectsOfType() 是一个函数调用,它返回当前场景中所有类型为 Item 的对象。接着,foreach 循环遍历这些对象,
对于每个对象,程序判断它的 itemName 是否已经存在于 itemAvailableDict 中,如果不存在,则将其添加到 itemAvailableDict 中,对应的布尔值为 true。

这段代码可能运行在 MonoBehavoir 的派生类中,例如 SceneManager 或某个具体的场景控制器,以实现在场景加载和卸载时进行特定的逻辑处理。

小知识
在 Unity 中,private void OnEnable() 是一个生命周期函数,它会在脚本对象被启用时自动调用。
当我们需要对脚本执行初始化操作时,可以在该函数中进行相应的操作。

具体来说,当脚本对象被创建时,默认处于禁用状态,此时 OnEnable() 函数不会被调用。
而当我们手动启用脚本对象(例如将其挂载到场景中的游戏物体上,并勾选其对应的“启用”选项),则 OnEnable() 函数会被调用。

在 OnEnable() 函数中,我们可以进行初始化、注册事件监听器、获取组件等操作,以确保脚本在启用后能够正常运行。
同时,在 OnDisable() 函数中,我们可以进行反初始化、取消事件监听器等操作,以确保脚本在禁用或销毁时不会继续运行或产生错误。

总之,OnEnable() 函数是在脚本对象被启用时自动调用的函数,在其中执行必要的初始化操作可以保证脚本能够正常运行。

1.2

EventHandler

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class EventHandler : MonoBehaviour
{  
    public static event Action<ItemDetails, int> updateUIEvent;
    public static void CallUpdateUIEvent(ItemDetails itemDetails,int index)
    {
        updateUIEvent?.Invoke(itemDetails, index);
    }

    /*
    创建两个事件来传递或者执行某些函数方法,这两个事件用于提醒订阅了这两个事件的ObjectManager 
    在场景切换前以及切换到该场景前更新字典的数据
    */
    public static event Action BeforeSceneUnloadEvent;

    public static void CallBeforeSceneUnloadEvent()
    {
        BeforeSceneUnloadEvent?.Invoke();
    }
    public static event Action AfterSceneUnloadEvent;

    public static void CallAfterSceneUnloadEvent()
    {
        AfterSceneUnloadEvent?.Invoke();
    }

  

}

1.3

TransitionManger

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;//用于场景的加载和卸载
public class TranstionManager : Singleton<TranstionManager>
    //TransitionManager用于实现场景的切换,每次点击场景切换箭头后将Teleport to H1 的两个变量传入到TransitonManager
    //将TransitionManager设置为单例模式
{

    [SceneName] public string startScene;
    private bool isFade;//判断是否切换场景
    public CanvasGroup fadeCanvasGroup;
    public float fadeDuration;//用于控制渐进渐出的速度
    private bool canTransition;

    //加载游戏一开始的场景
    public void Start()
    {
        StartCoroutine(TransitionToScene (string.Empty, startScene));
    }

    public void Transition(string from,string to)//用于场景切换
    {
        if(!isFade&&canTransition)
        //运用协程的方法卸载当前的场景,重新加载要去到的那个场景,并且将它设置为Additive
        StartCoroutine((IEnumerator)TransitionToScene(from,to));

    }

    private IEnumerator TransitionToScene(string from,string to)
    {
        yield return Fade(1);
        if(from!=string.Empty)
        {
         //在场景卸载前,呼叫订阅了该事件的代码执行方法
        EventHandler.CallBeforeSceneUnloadEvent();
        yield return SceneManager.UnloadScene(from);//卸载当前激活的场景from,并通过yield return语句返回该操作的结果
        }
        
        yield return SceneManager.LoadSceneAsync(to, LoadSceneMode.Additive);//使用SceneManager.LoadSceneAsync方法异步加载新场景to,
        //并将其添加到场景列表中

        //设置新场景为激活场景
        Scene newScene = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
        SceneManager.SetActiveScene(newScene);

        EventHandler.CallAfterSceneUnloadEvent();
        yield return Fade(0);
    }

    private IEnumerator Fade(float targetAlpha)
    {
        //传进一个数,如果是0就变成透明的,如果是1就变成黑色
        isFade = true;
        //核心方法:在场景中创建一个canvas
        fadeCanvasGroup.blocksRaycasts = true;
        float speed = Math.Abs(fadeCanvasGroup.alpha - targetAlpha)/fadeDuration;
        while (!Mathf.Approximately(fadeCanvasGroup.alpha, targetAlpha))
        {
            fadeCanvasGroup.alpha = Mathf.MoveTowards(fadeCanvasGroup.alpha, targetAlpha,speed * Time.deltaTime);
            yield return null;
        }
        fadeCanvasGroup.blocksRaycasts = false;
        isFade = false;
    }
}

2 总结

这一节比较简单。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值