【Unity实战】切换场景加载进度和如何在后台异步加载具有庞大世界的游戏场景,实现无缝衔接(附项目源码)

文章目录

  • 最终效果
  • 前言
  • 一、绘制不同的场景
  • 二、切换场景加载进度
    • 1. 简单实现
    • 2. 优化
  • 三、角色移动和跳跃控制
  • 四、添加虚拟摄像机
  • 五、触发器动态加载场景
  • 六、最终效果
  • 参考
  • 源码
  • 完结

最终效果

在这里插入图片描述

前言

观看本文后,我的希望你对unity场景管理有更好的理解,并且能够制作具有巨大世界的游戏并无缝加载游戏的各个部分在后台运行而不中断游戏玩法,这种方法非常灵活,而且很容易实现,因此无论您是制作小型平台游戏还是大型开放世界游戏,它应该都适用于两者,准备好让我们开始吧!

一、绘制不同的场景

创建不同场景
在这里插入图片描述

开始菜单界面场景Menu
在这里插入图片描述
主场景 Main,就简单放置个主角人物
在这里插入图片描述
房间1场景Room1,简单放置个平台,记得去除摄像机
在这里插入图片描述

二、切换场景加载进度

1. 简单实现

新增MainMenuManager 代码,实现加载进度,场景切换和加载

public class MainMenuManager : MonoBehaviour
{[SerializeField, Header("加载进度条的父对象")] private GameObject _loadingBarObject;[SerializeField, Header("加载进度条的图像")] private Image _loadingBar;[SerializeField, Header("需要隐藏的对象")] private GameObject[] _objectsToHide;[Space][SerializeField, Header("主要持久化场景的名称")] private string _persistentGameplay = "Main";[SerializeField, Header("游戏关卡场景的名称")] private string _levelScene = "Room1";private List<AsyncOperation> _scenesToLoad = new List<AsyncOperation>(); // 存储待加载场景的列表private void Awake(){_loadingBarObject.SetActive(false); // 禁用加载进度条}//开始游戏public void StartGame(){HideMenu(); _loadingBarObject.SetActive(true); // 启用加载进度条// 加载持久化场景和游戏关卡场景,并将它们添加到待加载场景列表中_scenesToLoad.Add(SceneManager.LoadSceneAsync(_persistentGameplay));_scenesToLoad.Add(SceneManager.LoadSceneAsync(_levelScene, LoadSceneMode.Additive));StartCoroutine(ProgressLoadingBar()); // 启动异步加载进度条的协程}// 隐藏界面private void HideMenu(){for (int i = 0; i < _objectsToHide.Length; i++){_objectsToHide[i].SetActive(false); // 隐藏需要隐藏的对象}}//异步加载进度条的协程private IEnumerator ProgressLoadingBar(){float loadProgress = 0f; // 总的加载进度for (int i = 0; i < _scenesToLoad.Count; i++){while (!_scenesToLoad[i].isDone){loadProgress += _scenesToLoad[i].progress; // 累加加载进度_loadingBar.fillAmount = loadProgress / _scenesToLoad.Count; // 更新加载进度条的显示yield return null; // 等待下一帧}           }}
}

挂载脚本,配置参数

在这里插入图片描述
配置开始游戏点击事件
在这里插入图片描述
被忘记在项目设置加入新的场景
在这里插入图片描述
效果
在这里插入图片描述

2. 优化

正常我们都是按场景名称或者索引去跟踪我们的场景吗,这里其实有一个更好的方法,之后在所有的项目中我们都可以去使用它

灵感来源于一篇Unity论坛的SceneField代码:
https://discussions.unity.com/t/inspector-field-for-scene-asset/40763
在这里插入图片描述
解释:这是代码通过使用SceneField类和SceneFieldPropertyDrawer属性绘制器,开发者可以在自定义的脚本中方便地引用和管理场景对象,并在Inspector面板中进行编辑和选择操作。这对于需要频繁切换场景或者处理多个场景的情况非常有用。

我已经复制代码下来,并加入了一些注释,如下

using UnityEngine;#if UNITY_EDITOR
using UnityEditor;
#endif[System.Serializable]
public class SceneField
{[SerializeField]private Object m_SceneAsset;[SerializeField]private string m_SceneName = "";public string SceneName{get { return m_SceneName; }}// 使其与现有的Unity方法(LoadLevel / LoadScene)兼容public static implicit operator string(SceneField sceneField){return sceneField.SceneName;}
}#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(SceneField))]
public class SceneFieldPropertyDrawer : PropertyDrawer
{public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label){EditorGUI.BeginProperty(_position, GUIContent.none, _property);SerializedProperty sceneAsset = _property.FindPropertyRelative("m_SceneAsset");SerializedProperty sceneName = _property.FindPropertyRelative("m_SceneName");_position = EditorGUI.PrefixLabel(_position, GUIUtility.GetControlID(FocusType.Passive), _label);if (sceneAsset != null){// 显示场景选择器,让用户选择一个场景sceneAsset.objectReferenceValue = EditorGUI.ObjectField(_position, sceneAsset.objectReferenceValue, typeof(SceneAsset), false);// 如果已经选择了场景,则将场景名称保存在场景名称变量中if (sceneAsset.objectReferenceValue != null){sceneName.stringValue = (sceneAsset.objectReferenceValue as SceneAsset).name;}}EditorGUI.EndProperty();}
}
#endif

修改MainMenuManager

[SerializeField, Header("主要持久化场景")] private SceneField _persistentGameplay;
[SerializeField, Header("游戏关卡场景")] private SceneField _levelScene;

配置,场景可以通过拖入绑定了
在这里插入图片描述
效果,还是和前面一样,没什么问题
在这里插入图片描述

三、角色移动和跳跃控制

简单实现一下角色的控制

public class PlayerController : MonoBehaviour
{private Rigidbody2D rb; // 刚体组件public float speed, jumpForce; // 移动速度和跳跃力度public Transform groundCheck; // 地面检测点public LayerMask ground; // 地面图层public bool isGround; // 是否在地面上bool jumpPressed; // 是否按下跳跃键//检测范围public float checkRadius;void Start(){rb = GetComponent<Rigidbody2D>(); // 获取刚体组件}void Update(){if (Input.GetButtonDown("Jump")){jumpPressed = true;}}private void FixedUpdate(){isGround = Physics2D.OverlapCircle(groundCheck.position, checkRadius, ground); // 检测是否在地面上GroundMovement(); // 地面移动Jump(); // 跳跃}//画出的射线可以看见private void OnDrawGizmosSelected(){if (groundCheck != null){Gizmos.color = Color.red;Gizmos.DrawWireSphere(groundCheck.position, checkRadius);}}void GroundMovement(){float horizontal = Input.GetAxisRaw("Horizontal"); // 获取水平方向输入rb.velocity = new Vector2(horizontal * speed, rb.velocity.y); // 设置刚体速度if (horizontal != 0){transform.localScale = new Vector3(horizontal, 1, 1); // 翻转角色}}void Jump(){if (jumpPressed && isGround){rb.velocity = new Vector2(rb.velocity.x, jumpForce); // 设置刚体速度jumpPressed = true;}}
}

挂载脚本,记得配置地面图层为Ground
在这里插入图片描述

效果
在这里插入图片描述

四、添加虚拟摄像机

在这里插入图片描述
效果
在这里插入图片描述

五、触发器动态加载场景

新增其他房间场景
在这里插入图片描述
新增SceneLoadTrigger ,定义触发器检测异步加载和卸载不同场景

public class SceneLoadTrigger : MonoBehaviour
{[SerializeField, Header("需要加载的场景数组")] private SceneField[] _scenesToLoad;[SerializeField, Header("需要卸载的场景数组")] private SceneField[] _scenesToUnload;private GameObject _player; // 玩家对象private void Awake(){_player = GameObject.FindGameObjectWithTag("Player"); // 查找并赋值玩家对象}private void OnTriggerEnter2D(Collider2D collision){if (collision.gameObject == _player) // 碰撞体为玩家时{LoadScenes(); UnloadScenes(); }}// 加载场景private void LoadScenes(){for (int i = 0; i < _scenesToLoad.Length; i++){bool isSceneLoaded = false;for (int j = 0; j < SceneManager.sceneCount; j++){Scene loadedScene = SceneManager.GetSceneAt(j);if (loadedScene.name == _scenesToLoad[i].SceneName){isSceneLoaded = true;break;}}if (!isSceneLoaded){SceneManager.LoadSceneAsync(_scenesToLoad[i].SceneName, LoadSceneMode.Additive); // 异步加载需要加载的场景}}}// 卸载场景private void UnloadScenes(){for (int i = 0; i < _scenesToUnload.Length; i++){for (int j = 0; j < SceneManager.sceneCount; j++){Scene loadedScene = SceneManager.GetSceneAt(j);if (loadedScene.name == _scenesToUnload[i].SceneName){SceneManager.UnloadSceneAsync(_scenesToUnload[i].SceneName); // 异步卸载需要卸载的场景}}}}
}

挂载脚本,配置参数,记得配置角色标签为Player,地面我设置了不同颜色,好做区分
在这里插入图片描述
运行效果
在这里插入图片描述

六、最终效果

可以看到,只要配置得当就可以做到场景地图无缝加载,即使是很大的地图,我们也可以把他分割成几个小场景,不影响游戏运行性能
在这里插入图片描述

参考

【视频】https://www.youtube.com/watch?v=6-0zD9Xyu5c

源码

源码整理好了我会放上来,催更加急

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/170713.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

辅助驾驶功能开发-外部需求篇-导航式巡航辅助NCA外部依赖及需求

1.功能外部依赖 为了设计满足用户需求的 ICA/NCA 系统,需要用到的系统输入为:环境及驾驶员感知信息、 门锁监测信息、胎压监测信息、驾驶员权限管理、车辆模式管理信息、用户请求输入、转向系统 信息、惯性及导航定位信息、被动安全及约束信息、变速箱系统信息、制动系…

华为云之在Linux系统下安装可视化界面

华为云之在Linux系统下安装可视化界面 一、华为云弹性云服务器ECS介绍二、Linux图形化界面介绍三、本次实践介绍3.1 本次实践简介3.2 本次实践环境介绍 四、环境准备工作4.1 预置环境4.2 查看预置环境资源信息 五、连接弹性云服务器ECS5.1 登录华为云5.2 复制ECS弹性公网IP地址…

云计算学习哪些技术

1. 虚拟化技术 虚拟化是云计算的基础&#xff0c;因此了解虚拟化技术至关重要。学习虚拟化技术时&#xff0c;需要掌握以下知识点&#xff1a; - 操作系统虚拟化&#xff1a;了解基于宿主机和客户机的虚拟化技术&#xff0c;如VMware、Hyper-V等。 - 容器化技术&#xff1a;学习…

php的字符转义函数有那些,是干什么的

在 PHP 中&#xff0c;字符转义函数是用于处理字符串中的特殊字符&#xff0c;以防止这些字符被误解、滥用或引起安全问题的一组函数。这些函数的主要作用是确保在将用户提供的数据插入到数据库、构建 HTML 输出或进行其他与安全相关的操作时&#xff0c;不会导致潜在的安全漏洞…

人工智能 -- 神经网络

1、什么是神经网络 什么是人工智能&#xff1f;通俗来讲&#xff0c;就是让机器能像人一样思考。这个无需解释太多&#xff0c;因为通过各种科幻电影我们已经对人工智能很熟悉了。大家现在感兴趣的应该是——如何实现人工智能&#xff1f; 从1956年夏季首次提出“人工智能”这…

leetcode设计循环队列(链表方式来实现)

上次我们那个设计循环队列的时候用的是数组&#xff0c;因为那个时候还是不太会链表&#xff0c;现在有了链表的思路&#xff0c;我们一起来看看解题步骤吧。 https://leetcode.cn/problems/design-circular-queue/description/ 设计循环队列 那我们其实最主要的就是我们这个…

SpringBoot——配置及原理

优质博文&#xff1a;IT-BLOG-CN 一、Spring Boot全局配置文件 application.properties与application.yml配置文件的作用&#xff1a;可以覆盖SpringBoot配置的默认值。 ◀ YML&#xff08;is not a Markup Language&#xff1a;不仅仅是一个标记语言&#xff09;&#xff1…

centos 7.9 下利用miniconda里的pyinstaller打包python程序为二进制文件操作方法

centos 7.9 下利用miniconda里的pyinstaller打包python程序为二进制文件操作方法 一.centos 7.9 操作系统安装 参考&#xff1a;https://blog.csdn.net/qq_46015509/article/details/134572030?utm_sourceminiapp_weixin 安装完成后用后台连接工具连上虚拟机 二.安装python3 …

蓝桥杯第2119题 特殊时间 C++ 思维暴力

题目 思路和解题方法 1110 代表 1110年11月10号11点10分1110 4*4*4 有0111 1011 1101 1110 可以符合年 月日 时分秒的都有4种例如 1113有1113 1131 1311 3111 年份符合月日只有11 13 时分秒 只有11 13 11 31 13 11 无31 11 c 代码 #include <bits/stdc.h> using…

Linux进程管理,用户管理,文件压缩命令

gcc与g区别(补充了解): 比如有两个文件:main.c,mainc.cpp(分别用C语言和C语言写的)如果要用gcc编译呢? gcc -o mainc main.c gcc -o mainc mainc.cpp -lstdc 指明用c的标准库; 区别一: gcc默认只链接C库,并不会链接C的库;g会默认链接c标准库. 区别二: gcc编译.c文件,则按照C语…

【开源组件】- 关于Jetcache的使用

关于Jetcache的使用 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f31d;分享学习心得&#xff0c;欢迎指正&#xff0c;大家一起学习成长&#xff01; JetCache是由…

K8s 中 Pod OOMKilled 原因

目录 Exit Code 137 解决方案 JVM 感知 cgroup 限制 使用 JDK9 的容器感知机制尝试 问题分析 容器内部感知 CGroup 资源限制 在 Java10 中&#xff0c;改进了容器集成 JVM 参数 MaxDirectMemorySize -XX:MaxDirectMemorySize 的默认值是什么&#xff1f; 其他获取 ma…

电源控制系统架构(PCSA)之电源管理基础设施组件

目录 6.5 电源管理基础设施组件 6.5.1 电源策略单元 6.5.2 时钟控制器 6.5.3 低功耗Distributor 6.5.4 低功耗Combiner 6.5.5 P-Channel到Q-Channel转换器 6.5 电源管理基础设施组件 6.5.1 电源策略单元 本节介绍电源策略单元(Power Policy Unit, PPU)。PPU的完整细节见…

Java核心知识点整理大全14-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…

CSS特效019:图标图片悬浮旋转一周

CSS常用示例100专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花边是描述了一些CSS…

【数据结构实验】查找(二)基于线性探测法的散列表

文章目录 1. 引言2. 实验原理2.1 散列表2.2 线性探测法 3. 实验内容3.1 实验题目&#xff08;一&#xff09;输入要求&#xff08;二&#xff09;输出要求 3.2 算法实现三、实验设计3.3 代码整合 4. 实验结果 1. 引言 本实验将通过C语言实现基于线性探测法的散列表 2. 实验原理…

R语言期末复习一

创建一个长度为7的字符向量&#xff0c;元素为"A", "B", "C", "D", "E", "F", "G"&#xff0c;并命名为vec1。 创建一个因子&#xff0c;包含6个水果&#xff1a;"apple", "banana"…

Kubernetes 秘密暴露使大型区块链公司面临风险

领先的网络安全专家对公开的 Kubernetes 配置表示担忧&#xff0c;这可能会威胁许多组织供应链的安全。 受影响的公司包括两家主要的区块链公司&#xff08;出于安全原因&#xff0c;其名称已被隐去&#xff09;以及其他多家财富 500 强公司。 Aqua Security 研究人员报告称&…

NX二次开发UF_CURVE_ask_joined_parms 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_joined_parms Defined in: uf_curve.h int UF_CURVE_ask_joined_parms(tag_t joined_curve_feature, UF_STRING_p_t uf_curve_string, int * creation_method, double …

物联网后端个人第十二周总结

学习工作进度 物联网方面 1.模拟设备通过规则引擎将数据通过mqtt进行转发 在物联网平台上实现模拟设备通过规则引擎将数据通过mqtt进行转发已经全部完成了&#xff0c;所使用的物联网平台在这方面有不少的问题和bug&#xff0c;也可能是没有按照开发者的想法对平台进行使用才导…