UE4引擎分析 | 您所在的位置:网站首页 › ue4组件列表 › UE4引擎分析 |
UE游戏世界的构建 UE的3D游戏世界是由Object->Actor+Component->Level->World->WorldContext->GameInstance->Engine来逐渐层层构建而成的。 UE类 Actor 1)Actor不自带Transform matrix来表示其位置,,但大部分Actor其实是有Transform的,其实内部都是转发到RootComponent;UE把Transform封装进了SceneComponent,当作RootComponent。如(Get/Set)ActorLocation等,其实内部都是转发到RootComponent。同理,Actor能接收处理Input事件的能力,其实也是转发到内部的UInputComponent* InputComponent; 2)Actor可以说是由Component组成的。在UE里,Component表达的是“功能”的概念。比如说你要实现一个可以响应的WASD移动的功能,或者是VR里抓取的功能,或者是加入一个可以载入模型的mesh,甚至是嵌套另一个Actor的功能,这些都是一个个组件。正确理解“功能”和“游戏业务逻辑”的区分是理解Component的关键要点。Component是与游戏本身无关的通用功能,一个游戏的Component可以迁移到另一个游戏中使用; 3)InputComponent是在Actor里面的,意味着实际上你也可以在Actor上绑定处理输入事件; 4)Actor的概念在UE里其实不是某种具象化的3D世界里的对象,而是世界里的种种元素,用更泛化抽象的概念来看,小到一个个地上的石头,大到整个世界的运行规则,都是Actor;运行规则的Actor,如AInfo(派生类AWorldSetting,AGameMode,AGameSession,APlayerState,AGameState等),AHUD,APlayerCameraManager等,代表了这个世界的某种信息、状态、规则。 5)UActorComponent也是基础于UObject的一个子类,这意味着其实Component也是有UObject的那些通用功能; 6)一个Actor若想可以被放进Level里,就必须实例化USceneComponent* RootComponent; 7)ActorComponent下面最重要的一个Component是SceneComponent;SceneComponent提供了两大能力:一是Transform,二是SceneComponent的互相嵌套(不推荐); 8)从功能上来说,UE更倾向于编写功能单一的Component(如UMovementComponent),而不是一个整合了其他Component的大管家Component(当然如果你偏要这么干,那UE也阻止不了你);从游戏逻辑的实现来说,UE也是不推荐把游戏逻辑写在Component里面; 9)Actor之间的父子关系是通过Component确定的,UE里是通过Child:AttachToActor或Child:AttachToComponent来创建父子连接; 10)Actor其实更像是一个容器,只提供了基本的创建销毁,网络复制,事件触发等一些逻辑性的功能,而把父子的关系维护都交给了具体的Component,所以更准确的说,其实是不同Actor的SceneComponent之间有父子关系,而Actor本身其实并不太关心; Level 1)*.map文件为ULevel类,ULevel类继承自UObject类; 2)ULevel类自带了一个ALevelScriptActor类,即关卡蓝图,关卡蓝图里可以编写脚本; 3)ULevel里有一个继承自AInfo的类AWorldSettings,AWorldSettings记录着ULevel的各种规则属性,如GameMode,光照信息等; 注:AWorldSettings只和ULevel相关,和World无关,每个ULevel都有一个AWorldSettings属性; 4)ALevelScriptActor类,派生自AActor,本身是一个看不见的Actor,可以在上面用Actor的各种操作,如GetActorLocation(); World 1)一个World里有多个Level,UE里每个World支持一个PersistentLevel和多个其他Level,Persistent的意思是一开始就加载进World,Streaming是后续动态加载的意思; 2)Levels(UWorld里保存Level指针的数组)里保存有所有的当前已经加载的Level,StreamingLevels保存整个World的Levels配置列表。 3)PersistentLevel和CurrentLevel只是个快速引用。在编辑器里编辑的时候,CurrentLevel可以指向其他Level,但运行时CurrentLevel只能是指向PersistentLevel; 4)当别的Level被添加进当前World之后,我们能直接在WorldOutliner里看到其他Level的Actor们。 5)同一个UWorld里的不同Level共享同一个PhysicsScene(物理,如碰撞等); 6)同一个UWorld里的不同Level分别保存了各自的Actors,而非由World统一管理,这样做的坏处是无法整体处理Actors的作用范围和判定问题,多了拼接导航等步骤;好处是动态加载和释放Level时,不会产生较大计算损耗;UE设置的方法是尽量的把损耗平摊,不会因产生比较大的帧率波动,而让玩家感觉到卡帧。 7)UE里拼装Level的两种方式 SubLevel WorldComposition的方式会自动把项目里的所有Level都组合起来,并设置摆放位置 WorldContext 1)UE用来管理和跟踪World的工具就是WorldContext;一般就来说,对于独立运行的游戏,WorldContext只有唯一个。而对于编辑器模式,则是一个WorldContext给编辑器,一个WorldContext给PIE(Play In Editor)的World; 2)UE里World可以有多个,比如编辑器本身就也是一个World,里面显示的游戏场景也是一个World,这两个World互相协作构成了我们的编辑体验。然后点播放的时候,引擎又可以生成新的类型World来让我们测试。 3)UE里World的类型 GameInstance 1)GameInstance是比World更高的层次,GameInstance里会保存着当前的WorldConext和其他整个游戏的信息。 2)独立于Level的逻辑或数据要在GameInstance中存储; 3)UE还不支持同时运行多个World(当前只能一个,但可以切换),所以GameInstance其实也是唯一的; Engine 1)UEngine分化出了两个子类:UGameEngine和UEditorEngine; 2)Standlone Game:会使用UGameEngine来创建出唯一的一个GameWorld,因为也只有一个,所以为了方便起见,就直接保存了GameInstance指针。 3)而对于编辑器来说,EditorWorld其实只是用来预览,所以并不拥有OwningGameInstance,而PlayWorld里的OwningGameInstance才是间接保存了GameInstance. GamePlayStatics 1)这个类比较简单,相当于一个C++的静态类,只为蓝图暴露提供了一些静态方法。 2)在蓝图里见到的GetPlayerController、SpawActor和OpenLevel等都是来至于这个类的接口。 Component Pawn和Character 产生原因:UE的3D游戏世界中,有数量庞大的Actor来表示游戏中的各种对象(如构建游戏世界的地板,石头,植物以及各种角色等),但其中只有一部分需要与玩家进行交互; Pawn继承自Actor,并在Actor的基础上新定义了3块基本的模板方法接口;Pawn实现的是“可被控制”的概念; 1)可被Controller(可以加入AIController,通过行为树来控制Actor)控制; 2)PhysicsCollision(碰撞设置-物理表示)表示; 3)MovementInput的基本响应接口; 以一个继承自Pawn的防御塔示例: Pawn概念的重点是在于更清楚的去表示Actor本身(即防御塔本身的构成-mesh,碰撞等),而不是重点在于Pawn被当作逻辑的载体,逻辑应该靠Controller机制,即AIController及行为树(Pawn自身为AI时)或玩家的控制(Pawn自身为玩家时); Pawn派生出的三个重要的类: DefaultPawn DefaultPawn里默认带了一个DefaultPawnMovementComponent、spherical CollisionComponent(球形碰撞组件)和StaticMeshComponent。 SpectatorPawn SpectatorPawn提供了一个基本的USpectatorPawnMovement(不带重力漫游),并关闭了StaticMesh的显示,碰撞也设置到了“Spectator”通道;用来提供某些游戏里解说视角,即可以不显示玩家角色,但玩家可以控制摄像机观察整个游戏世界; Character Character可以理解为一个人形的Pawn,在Pawn的基础上新增了像人一样行走的CharacterMovementComponent(移动组件),CapsuleComponent(胶囊体组件),mesh(骨骼上蒙皮的网格); AController 1)AController和APawn是一对一的关系,跟APawn是平级的关系,只在运行的时候引用关联,所以对彼此独立存在不做强制约束,提高了灵活性。 2)Controller不能像Actor层级嵌套; 3)Controller有位置信息; 4)从存在性来说,Controller的生命期比Pawn要长一些,Pawn被Destroy后,就算之后再Respawn创建出来一个新的,但是Pawn身上保存的变量状态都已经被重置了。所以对于那些需要在Pawn之外还要持续存在的逻辑和状态,放进Controller中是更好的选择。 5)RPG中Pawn和Cotroller是在GameMode中关联的; APlayerState 1)APlayerState派生的AInfo,跟Pawn和Controller是平级的关系,可以通过在GameMode中配置的PlayerStateClass来自动生成。 2)PlayerState只为players存在,不为NPC生成,一个玩家对应一个PlayerState; 3)玩家在切换关卡的时候,APlayerState也会被释放掉,所有PlayerState实际上表达的是当前关卡的玩家得分等数据;那些跨关卡的统计数据等就也不应该放进PlayerState里了,应该放在外面的GameInstance,然后用SaveGame保存起来。 APlayerController 1)一个游戏中只有一个PlayerController,在不同的关卡中你可以使用不同的PlayerController,但是同一时刻响应的只能是一个PlayerController。 2)类里的主要模块:Camera的管理、Input系统、UPlayer关联、Level的切换、Voice; 3)PlayerController是可被替换的,PlayerController也不一定存在;在任一刻,Player:PlayerController:PlayerState是1:1:1的关系。但是PlayerController可以有多个备选用来切换,PlayerState也可以相应多个切换; AAIController 1)同PlayerController对比,少了Camera、Input、UPlayer关联,HUD显示,Voice、Level切换接口; 2)增加的组件:Navigation,用于智能根据导航寻路;AI组件,运行启动行为树,使用黑板数据,探索周围环境,以后如果有别的AI算法方法实现成组件,也应该在本组件内组合启动;Task系统,让AI去完成一些任务,也是实现GameplayAbilities系统的一个接口; AGameMode 功能实现上的接口主要可以分为以下几大块: 1)Class登记,GameMode里登记了游戏里基本需要的类型信息,在需要的时候通过UClass的反射可以自动Spawn出相应的对象来添加进关卡中。 2)游戏内实体的Spawn; 3)游戏的进度,一个游戏支不支持暂停,怎么重启等这些涉及到游戏内状态的操作也都是GameMode的工作之一,SetPause、ResartPlayer等函数可以控制相应逻辑。 4)Level的切换,或者说World的切换更加合适,GameMode也决定了刚进入一场游戏的时候是否应该开始播放开场动画(cinematic),也决定了当要切换到下一个关卡时是否要bUseSeamlessTravel,一旦开启后,你可以重载GameMode和PlayerController的GetSeamlessTravelActorList方法和GetSeamlessTravelActorList来指定哪些Actors不被释放而进入下一个World的Level。 5)多人游戏的步调同步,在多人游戏的时候,我们常常需要等所有加入的玩家连上之后,载入地图完毕后才能一起开始逻辑。因此UE提供了一个MatchState来指定一场游戏运行的状态,意义看名称也是不言自明的,就是用了一个状态机来标记开始和结束的状态,并触发各种回调。 |
CopyRight 2018-2019 实验室设备网 版权所有 |