关于物体的创建销毁、层级操作、组件挂载

3

主题

4

帖子

11

积分

新手上路

Rank: 1

积分
11
发表于 2022-12-26 14:41:02 | 显示全部楼层
前言

——UE的Actor对应U3D的GameObject,但有些东西不太一样。比如Actor除了在大纲视图(对应U3D中的Hierarchy面板)中可以构建父子关系外,在一个Actor自身上也可以构建这种层级关系。



大纲视图(对照U3D Hierarchy面板)



细节面板(对照U3D Inspector面板)

——这种机制又不太像U3D中那种每个物体上都能挂一些功能性的Component组件、以此构成一个不带层级关系的组件列表(UE中的每个Actor上的子层级上又有很多像是Transform之类的组件),硬要类比的话,UE中的一个场景对象更像是U3D中的预制体(Prefab),只不过在UE中,这些预制的层级关系不在大纲视图中表现出来。
——如果把这种Actor导出成类似预制的资产文件,在UE中就叫【蓝图类】。
UE蓝图

创建



——可能是最常用的创建手段,注意要先选Class【这里务必选StaticMeshActor,至少不要选Actor,原因之后说】。下面举个例子,循环生成3x3个球。




——需要注意的是,这样创建出来的Actor是相互独立的,也就是不带层级关系。
※※※
——这里有个大坑点,也是之前说不要选Actor的原因。假如你选了Actor,然后手动去挂StaticMesh的组件


——就会有下面的奇怪现象。


——可以发现,我们对Transform的设置无效,并且更悲剧的是,你如果现在去手动改Transform里的值,UE会直接崩掉!!!


——究其原因大概是因为UE的Transform和U3D不同,它并不是每个Actor都带Transform。(至少蓝图Spawn出来的Actor没有)


——仅在Actor的根组件是继承自一个叫SceneRoot的组件时他才会有Transform,而直接Spawn出的Actor不是这样,所以会导致以上问题。
组件

——获得组件很容易,就是下面的节点。


——还有个GetChildComponents可以拿到子对象数组。
——关于UE的组件怎么挂还在研究···(AddComponentByClass节点有问题,挂完之后细节面板显示不出来,但实际上是挂上了。然而一但移动物体又会自动销毁组件)
销毁



层级操作



——可以用AttachXXX系列的节点来做这件事。比如在上面的基础上连一个AttachActorToActor节点便可以让生成的9个球都成为原物体的子物体(大纲面板)。


——但这里有个坑点,UE创建的Actor的Transform默认是static,而静态类型不允许做移动和attach等操作(毕竟涉及lightmap烘焙等操作),所以需要改层级的话记得手动或者用SetMobility节点把相关的层级改成非Static模式。


UE C++

——参考上面的蓝图实现,大概有下面这些方法是亲测有效的。
//创建(SpawnActor,在【非构造函数】中使用)
UWorld* World = GetWorld();//可以理解为获得当前场景的指针
UClass* TempClass = ActorIN->GetClass();//需要用GetClass获得要实例化的ActorIN的UClass*,因为SpawnActor的参数只能传UClass*类型
World->SpawnActor<AActor>(TempClass, FVectorIN, FRotatorIN);//不同于节点,这里可以配置一些Transform相关的参数,并且是有效的(应该是因为ActorIN往往带有RootComponent)

//创建组件(CreateDefaultSubobject,在【构造函数】中使用)
UStaticMeshComponent* SMC = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SMC "));//作为参数的名字无所谓,好像是和Log的输出有关,一般和参数名一致即可
//需要注意的是,这个方法并不会对你现有的已实例化的蓝图类进行改变(除非调用了构造函数)。

//创建组件(NewObject,AddInstanceComponent,在【非构造函数】中使用)
UStaticMeshComponent* SMC = NewObject<UStaticMeshComponent>(ActorIN);//NewObject在UE里相当于new关键字
SMC->SetStaticMesh(MeshIN);
SMC->RegisterComponent();//这行最关键,没了这行渲染效果就不会显示。看了下源码,大概是在场景里对需要处理的物体做了些注册什么的
ActorIN->AddInstanceComponent(SMC);//不要用其他的几个API,否则要不没效果要不UE会崩

//销毁
ActorIN->Destroy();
ComponentIN->DestroyComponent();

//层级(大纲视图)
ActorIN->GetAttachParentActor();//获得ActorIN的父对象
ActorIN->AttachToActor(ActorParent, FAttachmentTransformRules::KeepWorldTransform);//将ActorIN放到ActorParent的层级下,可通过第二个参数控制transform的调整模式

ActorIN->GetAttachedActors(Childs, false);//获得ActorIN的子对象数组赋予Childs。第二个参数控制是否递归查找所有子分支

//层级(细节面板)
ActorIN->GetRootComponent();//获得ActorIN的根组件
ComponentIN->GetAttachParent();//获得ComponentIN的父对象
ComponentIN->AttachToComponent(ComponentParent, FAttachmentTransformRules::KeepWorldTransform);//将ComponentIN放到ComponentParent的层级下,可通过第二个参数控制transform的调整模式

ComponentIN->GetNumChildrenComponents();//ComponentIN下子对象的数量
ComponentIN->GetChildComponent(i);//获得ComponentIN下索引为i的子对象

TArray<USceneComponent*> Childs = ComponentIN->GetAttachChildren();//获得ComponentIN下子对象的数组,TArray类似于C#中的List
ComponentIN->GetChildrenComponents(true, Childs);//作用和GetAttachChildren类似,把子集数组赋予Childs,但当第一个参数为true时可以递归查找所有层级嵌套的子分支
——然后补充一些我在查阅过程中觉得不错的资料。
U3D

//创建
GameObject newObj = new GameObject();//在场景中创建一个空对象
Instantiate(objIN);//克隆输入的对象objIN

//销毁
Destroy(objIN);//除了场景物体,也可以销毁组件
DestroyImmediate(objIN);//用Destroy报错时再换这个,一般除了Editor插件外不会用到

//组件
gameObject.GetComponent<类型>();//获得gameObject上挂载的首个指定类型的组件
gameObject.AddComponent<类型>();//给gameObject添加指定类型的组件

//层级
transform.parent = transformIN;//设置transform父对象的transform为transformIN,也可以transform.SetParent(transformIN)
transform.Find(nameIN);//获得transform下名为nameIN的对象

transform.childCount;//transform下子对象的数量
transform.GetChild(i);//获得transform下索引为i的子对象

transform.GetSiblingIndex();//获得transform在父层级中的索引
transform.SetSiblingIndex(idx);//设置transform在父层级中的索引为idx(改变层级列表中的位置)
回复

举报 使用道具

您需要登录后才可以回帖 登录 | 立即注册
快速回复 返回顶部 返回列表