【虚幻引擎】UE4源码解析FWorldContent、UWorld、ULevel、UGameInstance、UEngine

news2024/11/15 12:38:30

一、UEngine

  • Engine,因为也是很基础的类,再加上开发过程中会经常访问到该类型,因此UE4引擎也在代码全局范围内定义了一个该类型的全局变量:UEngine* GEngine供开发者直接调用。该最基础的类型分化成了两个子类:UGameEngine和UEditorEngine。
  • UGameEngine保存了唯一的一个UGameInstance* GameInstance指针,这是符合情理的,因为当我们在实际运行游戏(而不是运行项目或在项目里PIE)时,整个游戏只会有一个GameInstance,因此UGameEngine就直接保存了该GameInstance的指针。
  • UEditorEngine包含了两个UWorld指针:一个是UWorld* PlayWorld指针,一个是UWorld* EditorWorld,这也说明了我们的编辑器其实就是UE4引擎创建的一个World,一个“游戏”,然后我们在这个“游戏”里面去创建新的游戏。无论是哪一个World,我们都可以通过其对象查找到其WorldContext,然后再查找到其GameInstance,也就是说在编辑器模式下其实是有两个GameInstance的。

二、UGameInstance

  • UGameInstance是一个运行游戏的高级管理者,用来保存FWorldContext对象和整个游戏信息。 它拥有一个FWorldContext指针,一般来说,一个游戏只会实例化一个GameInstance,生存周期持续到游戏结束,编辑器模式下,生存周期为打开Editor到关闭Editor。实例化的位置:GameInstance在EngineLoop::PreInit()->PreInitPostStartupScreen()->LoadModulesForProject()->…->UClass::CreateDefaultObject()。
  • UGameInstance类型除了会保存FWorldContext* WorldContext,还保存了当前游戏里所有的Local Player、Game Session等信息。
  • 我们在切换Level的时候,其内的各种数据都会被释放然后重新生成,也就是说会丢失数据,哪怕是管理Level的World也是(只要切换Persistent Level,UWorld都会被释放然后重新生成新UWorld再来存放Persistent Level,从而造成数据丢失),因此UGameInstance就非常适合用于编写独立于所有Level和World之外的功能。

三、FWorldContent

  • 在UE4引擎中,有些时候(例如开发的时候)并不会只存在一个World,因此UE4引擎提供了一个类型来管理多个World——FWorldContext。需要注意这个类型以F开头,也就是说该类型不再派生自UObject或AActor。
  • FWorldContext是UEngine用来管理世界生成、销毁、切换的类。看看它主要成员变量:
    UWorld* ThisCurrentWorld;
    UGameInstance* OwningGameInstance;
    它拥有一个UWorld,也拥有一个指向UGameInstance的指针。
  • 对于独立运行的游戏,WorldContext只有唯一的一个(Game WorldContext);对于编辑器模式,则是一个WorldContext给编辑器(Editor Context),一个WorldContext给PIE(PIE WorldContext),甚至还会有其他的WorldContext,如编辑器视图里面还没有运行的游戏场景的World(Preview World)
  • FWorldContext类型的成员变量UWorld* ThisCurrentWorld会指向当前的World。当需要从一个World切换到另一个World的时候(如点击“播放”按钮之后,UE4引擎从编辑器视图的Preview World切换到PIE World),FWorldContext就会用来保存切换过程信息和目标World的上下文信息。

四、UWorld

  • 很多时候仅仅只有一个关卡是不够的,如果我们的游戏场景尺寸非常巨大,要将这些庞大数量的Actor全部都塞进一个关卡里,势必会造成关卡的臃肿和维护的困难,若我们将这个巨大的场景根据一定规则划分,并能够实现在我们需要的时候读取一部分内容,或者释放掉我们不需要的内容,无论是在性能上还是开发过程都会起到良好的作用。因此UE4引擎提供了一个能够容纳多个关卡的类型——World。
  • UWorld类型是从ULevel类型直接继承而来的,并添加了多个数组用于保存子关卡及其各自的Actors,以及保存了指向“Persistent Level”和“Current Level”的指针。
  • UWorld使用的关卡就是“Persistent Level”,也就是项目编辑器视口打开了的持久性关卡,而UWorld使用的AWorldSettings也就是持久性关卡的AWorldSettings。但并不是说其他子关卡的AWorldSettings就完全没有用,部分配置例如光照配置,就是使用的各自关卡AWorldSettings的设置而不是照搬持久性关卡的设置。
  • UWorld里面可以访问得到所有关卡(包括持久性关卡和子关卡)里的所有Actor,但是并不是说UWorld直接保存这些Actors,而仅仅只是通过遍历ULevel然后再遍历其Actor。
  • UWorld是可视化场景的最高级对象,是放置和移除关卡的地方,它拥有一个PersistentLevel和一组StreamLevel。在standaloneGame下,一般只存在一个World;在编辑器模式下,存在不止一个World,比如场景编辑、PIE、各种带渲染的交互编辑工具窗口等,都是World。
    主要成员变量:
    TArray<class ULevel*> Levels; //所有Level
    class ULevel* PersistentLevel;
    FPhysScene* PhysicsScene;

五、ULevel

  • 丰富多彩的Actor和Component构成了一个个功能强大的对象,现在需要有一个容器能够存放下这些所有的对象,存放这些所有元素的对象就是UE4提供的ULevel类型。
  • 关卡(Level)类型在C++代码里命名可知,Level类型也是继承自UObject类型的。
  • 既然是继承自UObject类型,那自然也会继承了UObject提供的各种特性,其中也包括“编写脚本”的能力,因此每个ULevel对象也都自带了一个“ALevelScriptActor”对象用来实现“关卡蓝图”的功能。
  • 关卡本身也需要支持一些可自定义的属性,例如设置关卡里的光照贴图、本关卡使用的游戏模式等等,因此该类型也自带着一个“书记官”——“AWorldSettings”类型用于记录这些每个关卡本身的可自定义属性。
  • 关卡本身支持添加多个子关卡,又因为每个关卡都可以定义自己的游戏模式等属性,因此当一个“持久性关卡(Persistent Level)”里面被添加了多个子关卡时,实际使用到的“AWorldSettings”对象只会是持久性关卡的那一个。
  • 关卡的作用是用来存放Actor及其派生类,因此关卡本身会有一个变量“TArray<AActor*> Actors”用来存放关卡内所有生成的Actor,“ALevelScriptActor”和“AWorldSettings”也理所当然地被保存到该数组里面。
  • Level是一个场景内容的收集者,包括光照、声音、实例化网格体等等,一些通用的内容比如光照质量,集成到WorldSetting这个类里设置。
    主要成员变量:
    TArray<AActor*> Actors;
    AWorldSettings* WorldSettings;
    ALevelScriptActor* LevelScriptActor; //关卡蓝图
     

最后总得来说就是,引擎初始化New一个GEngine出来,然后创建一个Gameinstance拥有一个FWorldContext指针,保存了所有的world参数信息,然后创建WorldContent里面包含了一个UWord的指针UWorld* ThisCurrentWorld指向当前的World,当我们使用Openlevel的时候会用到FWorldContext的参数,先卸载掉当前的World,然后在加载OpenLevel的world。

 

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

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

相关文章

【面试题】 JavaScript 字符串截取方法有哪些?

大厂面试题分享 面试题库后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★地址&#xff1a;前端面试题库在 JavaScript 中&#xff0c;可以使用 substr()、slice() 和 substring() 方法截取字符串。substring()substring() 方法返回一个字符串在开始…

Lock锁心得

lock接口最常见的实现类ReentrantLock&#xff0c;通常情况下&#xff0c;lock只允许一个线程访问共享资源&#xff0c;也有特殊情况&#xff0c;比如读写锁里的读锁。lock和synchronizrd是常见的锁&#xff0c;都可以让代码变得安全。但是功能上有差别&#xff0c;二者不是能替…

笃行不怠勾勒人才图,望城区人才工作为高质量发展增添强劲动力

功以才成&#xff0c;业以才广。人才是经济高质量发展的重要资源。党的二十大报告明确“深入实施人才强国战略”&#xff0c;指出“实施更加积极、更加开放、更加有效的人才政策”。作为湖南“一核两副三带四区”区域经济发展格局的战略支点&#xff0c;望城区积极发挥着政策主…

TCP协议详解—TCP各个报头属性的作用

文章目录一.TCP是什么二.TCP协议格式1.报头属性解释TCP首部长度/如何解包分用三.确认应答机制-tcp如何保证可靠性1.确认应答机制2.序号/确认序号-如何保证报文按序到达3.为什么要两个序号四.16位窗口大小-调整发送策略五.6个标志位一.TCP是什么 首先我们需要知道TCP是什么,TCP全…

你知道Object类和Objects的常用方法吗

文章目录Object的常用方法Objects的常用方法hashCodehashisNullequalsrequireNonNullcomparenonNull大家好&#xff0c;Leo又来了!!!最近在网上看到别人分析Objects中isNullfanfan方法来判断&#xff0c;我就想到之前写的一坨坨null&#xff0c;突然很惭愧&#xff0c;特地去研…

IIC总线式驱动开发(mpu6050)

目录 一、I2C总线背景知识 二、Exynos4412 I2C收发实现之裸机版 2.1 发送 2.2 接收 三、Linux内核对I2C总线的支持 四、MPU6050 五、应用层直接使用I2C通道 5.1 预备工作&#xff1a; 5.1.1 5.1.2 5.2 应用层直接使用i2c总线的代码实现 5.2.1 调用read、write实现接…

解决“vue“不是内部或外部命令问题

通过vue指令使用脚手架初始化项目时&#xff0c;在cmd中输入vue init webpack vue_project&#xff0c;终端报错&#xff1a; vue 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。解决方案&#xff1a; 1、确定npm是否已正确安装&#xff0c;在cmd中输入如下…

AcWing算法提高课-3.1.3香甜的黄油

宣传一下算法提高课整理 <— CSDN个人主页&#xff1a;更好的阅读体验 <— 题目传送门点这里 题目描述 农夫John发现了做出全威斯康辛州最甜的黄油的方法&#xff1a;糖。 把糖放在一片牧场上&#xff0c;他知道 N 只奶牛会过来舔它&#xff0c;这样就能做出能卖好价…

Dynamics 365 环境搭建 之 SQL Server 2019问题汇总

前言 随着产品的迭代&#xff0c;SQL Server 2016 已经是7-8年前的产品&#xff0c;新环境的搭建必然要随之更新。截至目前&#xff08;2023年3月&#xff09;Dynamics 365 9.1 op版本的软件要求如下。 Windows ServerSQL ServerWindows Server 2019 标准 Windows Server 20…

Vue2与Vue3响应式的详解与比对

目录前言一&#xff0c;响应式的理解1.1 Mvvm模式的复习1.2 什么是响应式二&#xff0c; Vue2中响应式的应用三&#xff0c;Vue2响应式的原理及实现3.1 数据代理3.2 数据代理的原理3.3 数据劫持四&#xff0c;Vue3中响应式的应用3.1 ref与reactive3.2 ref函数的使用讲解3.3 为什…

Anaconda配置Python新版本tensorflow库(CPU、GPU通用)的方法

本文介绍在Anaconda环境中&#xff0c;下载并配置Python中机器学习、深度学习常用的新版tensorflow库的方法。 在之前的两篇文章基于Python TensorFlow Estimator的深度学习回归与分类代码——DNNRegressor&#xff08;https://blog.csdn.net/zhebushibiaoshifu/article/detail…

圣杯布局的实现方式

1.什么是圣杯布局&#xff1f; 左右盒子固定&#xff0c;中间盒子自适应 2.实现方式 &#xff08;1&#xff09;flex布局 思路&#xff1a;左右盒子给固定的宽高&#xff0c;中间盒子flex:1 <!DOCTYPE html> <html lang"en"> <head> <met…

JavaSE学习进阶 day1_01 static关键字和静态代码块的使用

好的现在我们进入进阶部分的学习&#xff0c;看一张版图&#xff1a; 前面我们已经学习完基础班的内容了&#xff0c;现在我们已经来到了第二板块——基础进阶&#xff0c;这部分内容就不是那么容易了。学完第二板块&#xff0c;慢慢就在向java程序员靠拢了。 面向对象进阶部分…

入门力扣自学笔记240 C++ (题目编号:2373)

2373. 矩阵中的局部最大值 题目&#xff1a; 给你一个大小为 n x n 的整数矩阵 grid 。 生成一个大小为 (n - 2) x (n - 2) 的整数矩阵 maxLocal &#xff0c;并满足&#xff1a; maxLocal[i][j] 等于 grid 中以 i 1 行和 j 1 列为中心的 3 x 3 矩阵中的 最大值 。 换句…

学习渗透测试,考CISP-PTE还是考NISP-PT证书呢?

其实两者都可以&#xff0c;但是要看考生的实际需求&#xff01; 为什么说两者都可以&#xff1f; 两个证书都由中国信息安全测评中心颁发&#xff0c;CISP-PTE&#xff08;注册信息安全渗透测试工程师&#xff09;,NISP-PT&#xff08;国家信息安全水平考试渗透测试工程师),…

月薪30k测试岗技术要求,简简单单,你学废了吗?

如果还只会点点点&#xff0c;那么可以往自动化测试的方向发展&#xff0c;然后再往测试开发的方向发展&#xff0c;做一个测试开发的工程师&#xff0c;这样薪资是非常可观的。当然过程中需要学习很多的知识&#xff0c;比如&#xff1a;编程语言&#xff0c;自动化测试框架&a…

2023年工程师中级和高级有什么区别,他们评审的要求有哪些不同?

2023年工程师中级和高级有什么区别&#xff0c;他们评审的要求有哪些不同&#xff1f; 职称主要分为初、中、高三个等级。在大部分地区都是逐级申报的&#xff0c;先初级再中级最后高级。不少人都想直接评中级&#xff0c;这是不可行的的&#xff0c;除少数地区破格来说&#x…

软件测试工程师该怎么做自己的职业规划呢

软件测试需求量不仅稳健&#xff0c;还会加大 疫情前&#xff0c;人们的“吃、穿、住、用、行”方方面面都有对应APP软件。疫情后&#xff0c;复工最快&#xff0c;最迅速的企业也都是通过互联网技术实现。 过去&#xff0c;互联网技术只是让某些企业活的好。未来&#xff0c…

面经-Spring框架相关

面试题 Spring、SpringMVC、SpringBoot的区别 Spring是轻量级的开发框架&#xff0c;主要提供了IOC依赖注入容器和AOP面向切面编程的功能。 SpringMVC是基于Spring的一个用来解决Web开发的问题&#xff0c;主要处理web开发中路径映射和视图渲染等 SpringBoot是融合了Spring…

关于算力的未来,新一代PowerEdge告诉你答案

从ChatGPT等大模型海量参数的训练&#xff0c;自动驾驶领域感知模型的训练与仿真&#xff0c;到蛋白质机构预测、流体力学仿真等AIScience&#xff0c;再到矿山、交通、能源等部署广泛的边缘计算设备……如今&#xff0c;我们愈发确切地认识到&#xff0c;算力在数字经济时代不…