Unity3D多场景管理框架设计

前言

我将设计一个Unity3D游戏客户端框架的多场景管理系统,包含场景加载、进度显示和过渡动画等功能。

设计思路

  1. 场景管理核心:单例管理器处理场景加载/卸载
  2. 加载界面:显示进度条、提示信息和加载动画
  3. 场景切换过渡:平滑的淡入淡出效果
  4. 多场景支持:支持叠加加载和单独加载
  5. 错误处理:场景加载失败提示

对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀!

完整实现代码

using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;

public class SceneTransitionManager : MonoBehaviour
{
    public static SceneTransitionManager Instance { get; private set; }

    [Header("UI References")]
    public CanvasGroup loadingScreen;
    public Slider progressBar;
    public Text progressText;
    public Text tipText;
    public Image loadingIcon;

    [Header("Settings")]
    public float fadeDuration = 0.5f;
    public float minLoadTime = 1.5f;
    public List<string> loadingTips = new List<string>
    {
        "小提示:探索场景可以找到隐藏道具",
        "小提示:按ESC键可以打开设置菜单",
        "小提示:完成每日任务可获得额外奖励"
    };

    private AsyncOperation currentAsyncOperation;
    private bool isLoading;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    // 加载单个场景(替换当前场景)
    public void LoadScene(string sceneName)
    {
        if (isLoading) return;
        StartCoroutine(LoadSceneCoroutine(sceneName, LoadSceneMode.Single));
    }

    // 叠加加载场景(不卸载当前场景)
    public void LoadSceneAdditive(string sceneName)
    {
        if (isLoading) return;
        StartCoroutine(LoadSceneCoroutine(sceneName, LoadSceneMode.Additive));
    }

    // 卸载指定场景
    public void UnloadScene(string sceneName)
    {
        StartCoroutine(UnloadSceneCoroutine(sceneName));
    }

    private IEnumerator LoadSceneCoroutine(string sceneName, LoadSceneMode mode)
    {
        isLoading = true;
        
        // 显示随机提示
        tipText.text = loadingTips[Random.Range(0, loadingTips.Count)];
        
        // 淡入加载界面
        yield return StartCoroutine(FadeLoadingScreen(0, 1, fadeDuration));
        
        float timer = 0f;
        progressBar.value = 0;
        progressText.text = "0%";
        
        // 开始异步加载场景
        currentAsyncOperation = SceneManager.LoadSceneAsync(sceneName, mode);
        currentAsyncOperation.allowSceneActivation = false;
        
        // 旋转加载图标
        StartCoroutine(RotateLoadingIcon());
        
        while (!currentAsyncOperation.isDone)
        {
            timer += Time.deltaTime;
            
            // 计算加载进度(0-0.9)
            float loadProgress = Mathf.Clamp01(currentAsyncOperation.progress / 0.9f);
            float percent = Mathf.Clamp01((timer / minLoadTime) * loadProgress);
            
            progressBar.value = percent;
            progressText.text = Mathf.Round(percent * 100) + "%";
            
            // 加载完成但等待最小加载时间
            if (currentAsyncOperation.progress >= 0.9f && timer >= minLoadTime)
            {
                progressBar.value = 1;
                progressText.text = "100%";
                currentAsyncOperation.allowSceneActivation = true;
            }
            
            yield return null;
        }
        
        // 淡出加载界面
        yield return StartCoroutine(FadeLoadingScreen(1, 0, fadeDuration));
        
        isLoading = false;
    }

    private IEnumerator UnloadSceneCoroutine(string sceneName)
    {
        AsyncOperation unloadOperation = SceneManager.UnloadSceneAsync(sceneName);
        while (!unloadOperation.isDone)
        {
            yield return null;
        }
    }

    private IEnumerator FadeLoadingScreen(float startAlpha, float endAlpha, float duration)
    {
        float time = 0;
        loadingScreen.blocksRaycasts = true;
        loadingScreen.interactable = true;
        
        while (time < duration)
        {
            loadingScreen.alpha = Mathf.Lerp(startAlpha, endAlpha, time / duration);
            time += Time.deltaTime;
            yield return null;
        }
        
        loadingScreen.alpha = endAlpha;
        
        if (endAlpha == 0)
        {
            loadingScreen.blocksRaycasts = false;
            loadingScreen.interactable = false;
        }
    }

    private IEnumerator RotateLoadingIcon()
    {
        while (isLoading)
        {
            loadingIcon.transform.Rotate(0, 0, -180 * Time.deltaTime);
            yield return null;
        }
    }
}

使用说明

场景切换方法

  1. 加载单个场景

SceneTransitionManager.Instance.LoadScene("MainScene");

叠加加载场景

SceneTransitionManager.Instance.LoadSceneAdditive("InventoryScene");

卸载场景

SceneTransitionManager.Instance.UnloadScene("InventoryScene");

编辑器设置

  1. 创建UI Canvas用于加载界面
  2. 添加以下元素:
  • 半透明背景Panel
  • 进度条Slider
  • 进度百分比Text
  • 提示信息Text
  • 旋转加载图标Image
  • 将组件拖拽到SceneTransitionManager脚本的对应字段

功能特点

  1. 平滑过渡:使用CanvasGroup实现淡入淡出效果
  2. 最小加载时间:确保玩家能看到加载提示和进度
  3. 随机提示:每次加载显示不同的游戏提示
  4. 进度可视化:实时显示加载进度百分比
  5. 动画效果:旋转图标增强视觉效果
  6. 错误保护:防止重复加载场景

最佳实践建议

  1. 场景组织
  • 将核心系统放在常驻场景
  • 按功能模块划分场景(如UI、关卡、角色等)
  • 资源管理
  • 使用Addressables或AssetBundle管理资源
  • 在加载场景前预加载必要资源
  • 场景通信
  • 使用事件系统解耦场景间通信
  • 通过GameObject.FindGameObjectWithTag查找关键对象
  • 性能优化
  • 对大型场景使用分区域加载
  • 异步加载资源避免卡顿
  • 使用对象池管理频繁创建销毁的对象

这个多场景管理系统提供了游戏开发中常见的场景管理功能,可以作为游戏框架的核心组件之一。您可以根据项目需求扩展错误处理、场景依赖管理等功能。

更多教学视频

Unity3D​www.bycwedu.com/promotion_channels/2146264125

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值