Unity引擎2D游戏开发,场景淡入淡出效果

非强专业性文章,本文仅供学习与交流使用

淡入淡出的实现逻辑

在Persistent中,创建一个新的Canvas,命名为Fade Canvas

注意它的Sort Oder属性,该属性值越大,图层优先级越高,可以遮蔽屏幕上的任何图层

接着在Fade Canvas 中,新建一个Image,命名为Fade Image

Anchor Presets窗口中,按住alt+shift键,选中右下角,即可填充整个屏幕

那么这时候,调整Color属性中的alpha值,即可实现淡入效果

取消勾选Raycast Target。该属性会导致遮蔽的时候会将UI按钮给遮蔽,无法正常点击不该遮蔽的按钮

代码实现

从assetstore上,下载导入DOTween插件

assetstore.unity.com/packages/to...

然后将其import导入到项目当中,点击Setup DOTween

在Documentation文档当中,即将使用的就是DOBlendableColor()方法。可以通过一定的时间转换到一个指定的颜色上

现在就需要通过Scriptable跨脚本调用事件的方式来实现该功能。因为淡入淡出效果是要在SceneLoader脚本中进行代码实现,而当前Canvas调整是在Fade Canvas脚本中实现的

在FadeCanvas中,创建一个OnFadeEvent()事件,内部调用Image的DOBlendableColor()方法

c# 复制代码
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

public class FadeCanvas : MonoBehaviour
{
    public Image fadeImage;

    /// <summary>
    /// 淡入淡出事件
    /// </summary>
    /// <param name="targetColor">转换的目标颜色</param>
    /// <param name="duration">动画时间</param>
    private void OnFadeEvent(Color targetColor, float duration)
    {
        fadeImage.DOBlendableColor(targetColor, duration);
    }
}

在ScriptableObject中创建FadeEventSO脚本

创建UnityAction对象的OnEventRaised变量,然后创建RaiseEvent()方法,携带三个必要的参数在内部调用OnEventRaised事件的Invoke方法

之后,创建FadeIn和FadeOut方法,调用RaiseEvent方法,注意这时候分别传入不同的布尔值,如果为true,则启动淡入效果,反之,则淡出效果

c# 复制代码
using UnityEngine;
using UnityEngine.Events;

[CreateAssetMenu(menuName = "Event/FadeEventSO")]
public class FadeEventSO : ScriptableObject
{
    public UnityAction<Color, float, bool> OnEventRaised;

    /// <summary>
    /// 逐渐变黑
    /// </summary>
    /// <param name="duration"></param>
    public void FadeIn(float duration)
    {
        // 启动事件订阅的函数方法
        RaiseEvent(Color.black, duration, true);
    }

    /// <summary>
    /// 逐渐透明
    /// </summary>
    /// <param name="duration"></param>
    public void FadeOut(float duration) 
    {
        RaiseEvent(Color.clear, duration, false);
    }

    public void RaiseEvent(Color targetColor, float duration, bool fadeType)
    {
        OnEventRaised?.Invoke(targetColor, duration, fadeType);
    }
}

在SceneLoader脚本中,修改两处地方,分别调用FadeInFadeOut实现淡入淡出效果

c# 复制代码
public FadeEventSO fadeEventSO;

private IEnumerator UnloadPreviousScene()
{
    if (fadeScreen)
    {
        // 实现淡入
        fadeEventSO.FadeIn(fadeTime);
    }
    // 等待淡入淡出的指定时间
    yield return new WaitForSeconds(fadeTime);
    // 非空判断
    yield return currentLoadScene.assetReference.UnLoadScene();
    // 关闭人物
    playerTrans.gameObject.SetActive(false);

    LoadNewScene();
}
c# 复制代码
private void OnLoadComplete(AsyncOperationHandle<SceneInstance> handle)
{
    currentLoadScene = targetSceneToGo;

    playerTrans.position = targetPositionToGo;
    // 启动人物
    playerTrans.gameObject.SetActive(true);

    if (fadeScreen)
    {
        // 实现淡出
        fadeEventSO.FadeOut(fadeTime);
    }
    // 加载完毕,则把标识置为false
    isLoading = false;
    // 场景加载完成后的事件
    afterSceneLoadedEvent.RaiseEvent();
}

之后,在FadeCanvas脚本中,添加事件监听的变量

c# 复制代码
[Header("事件监听")]
public FadeEventSO fadeEvent;

再对其创建注册和销毁的方法

c# 复制代码
private void OnEnable()
{
    fadeEvent.OnEventRaised += OnFadeEvent;
}

private void OnDisable()
{
    fadeEvent.OnEventRaised -= OnFadeEvent;
}

注意修改下OnFadeEvent()方法的参数

c# 复制代码
/// <summary>
/// 淡入淡出事件
/// </summary>
/// <param name="targetColor">转换的目标颜色</param>
/// <param name="duration">动画时间</param>
/// <param name="fadeType">动画类型</param>
private void OnFadeEvent(Color targetColor, float duration, bool fadeType)
{
    fadeImage.DOBlendableColor(targetColor, duration);
}

在Events文件夹中,创建FadeEventSO

拖入到SceneLoad ManagerFade Cavas指定的属性中,注意FadeImage也要选择指定的实体对象

注意调整Fade Time,给一个合适的时间,即可实现淡入淡出效果

解决传送过程中仍然能操作的问题

SceneLoader脚本内,添加一个事件,携带一个布尔值参数,标志着是否正在传送

c# 复制代码
public UnityEvent<bool> playerTeleport;

OnLoadRequestEvent()启动传送的方法内,添加一行代码进行事件的广播,见13行

c# 复制代码
private void OnLoadRequestEvent(GameSceneSO sceneToGo, Vector3 positionToGo, bool fadeScreen)
{
    // 如果正在加载,则不执行加载过程中的任何操作
    if (isLoading)
    {
        return;
    }
    isLoading = true;
    targetSceneToGo = sceneToGo;
    targetPositionToGo = positionToGo;
    this.fadeScreen = fadeScreen;
    // 传送事件,传入一个是否正在加载的布尔值给PlayerControl脚本的指定方法内
    playerTeleport?.Invoke(isLoading);

    // 卸载当前场景,装载下一个场景
    if (currentLoadScene != null)
    {
        StartCoroutine(UnloadPreviousScene());
    } else
    {
        LoadNewScene();
    }
}

再在OnLoadComplete()传送完毕的方法内,添加一行代码,再一次广播事件

c# 复制代码
private void OnLoadComplete(AsyncOperationHandle<SceneInstance> handle)
{
    currentLoadScene = targetSceneToGo;

    playerTrans.position = targetPositionToGo;
    // 启动人物
    playerTrans.gameObject.SetActive(true);
    // 加载完毕,则把标识置为false
    isLoading = false;
    // 场景加载完成后的事件
    afterSceneLoadedEvent.RaiseEvent();
    if (fadeScreen)
    {
        // 实现淡出
        fadeEventSO.FadeOut(fadeTime);
    }
    // 传送完毕,再一次广播事件
    playerTeleport?.Invoke(isLoading);
}

在PlayerController脚本内,添加一个PlayerTeleporting()方法,在里面判断布尔值,是否正在传送

如果正在传送,则禁止Input操作,反之,启动操作

c# 复制代码
/// <summary>
/// 玩家正常传送中,禁止一切操作
/// </summary>
public void PlayerTeleporting(bool isLoading)
{
    if (isLoading)
    {
        playerInputControl.Gameplay.Disable();
    } else
    {
        playerInputControl.Gameplay.Enable();
    }
    
}

最后一步,在面板上,选择Player,并在旁边选择PlayerController的PlayerTeleporting()方法进行监听

相关推荐
Mapmost1 天前
【数据融合实战手册·进阶篇】模型融合总出错?先看看这些“对齐”了没!
unity3d
北桥苏3 天前
如何在 Unity3D 导入 Spine 动画
unity3d
Thomas游戏开发4 天前
Unity3D状态管理器实现指南
前端框架·unity3d·游戏开发
非衣居士7 天前
Lua程序设计笔记
lua·游戏开发
Chiyamin8 天前
VoidMatrix大佬项目提瓦特幸存者番外篇特效实现(并非完美)
c++·游戏开发
大模型铲屎官9 天前
如何用C#继承提升游戏开发效率?Enemy与Boss案例解析
开发语言·unity·c#·游戏引擎·游戏开发·boss·enemy
echeverra9 天前
号外号外!给兄弟们汇报下近期三款热门游戏万灵山海、DOF、新大话西游更新内容
游戏·游戏开发
土豆宝9 天前
Unity Visual Scripting(可视化脚本) 自定义节点 踩坑教程
unity3d
Winston-Tao9 天前
Skynet 中 snlua 服务启动整体流程分析
lua·游戏开发·c 语言·skynet·游戏服务器框架
Thomas游戏开发10 天前
Unity3D光照层级与动态切换指南
前端框架·unity3d·游戏开发