参考
参考
原理就是利用一个房间的三个方向(排除进入口)出口(可以减少,即设置墙壁),从而获得下一次房间生成的位置,其中涉及到对于多个房间重叠,生成结束后如何对缺口进行修补等功能实现
RoomBaseActor
该Actor类是后续创建房间的基类,如果想要固定所有房间形状即只改变出口个数,那么在该类中可以添加StaticMeshComponent,实现房间的统一。
基本成员
这些成员变量或者函数是所有房间都需要具备的。
- BoxComponent:盒型碰撞器,该组件将用来检测生成时房间的重叠
- TArray<UArrowComponent*> 该数组将存储当前房间的出口
- TArray<UBoxComponent*> 该数组将存储当前房间的所有BoxComponent
Child Room Actor
如果在RoomBase只设置了基本成员,没有添加StaticMesh,那么就可以在Child中自定义房间类型,只需要注意每个房间的出入口匹配就可以了。在Child类中,才进行UArrowComponent组件的构建,因为只有Child类才会确定房间的出口
加载模型
即StaticMeshComponent在构造函数中加载模型,实现效果如同在蓝图中选择Mesh的示例。首先需要在项目文件夹中存在对应的模型,这样才能进行加载。
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("StaticMesh'/Game/StarterContent/Architecture/Wall_400x200.Wall_400x200'"));
if (MeshAsset.Succeeded())
{
WallClose1->SetStaticMesh(MeshAsset.Object);
}
利用该函数ConstructorHelpers::FObjectFinder可以在项目文件夹中找到所需资源即TEXT后面的文本,而该文本可以直接在打开编辑器后,右键资源Copy Ref即可
Room Gernerate Actor
控制房屋生成的主要类
主要成员
-
生成结束封闭所有开放口的Actor
-
第一个生成的房间Actor
-
后续生成的房间Actor列表:将从中随机选择Actor
上述3个成员变量,将利用TSubclassOf的方式在编辑器中选择对应的蓝图进行生成 -
TArray<UArrowComponent*> 该数组将添加新创建房间的对应数组,并移除已使用的Arrow,之后的创建位置将通过Arrow获得
-
TArray<UPrimitiveComponent*> 存放当前添加房间的BoxComponent的重叠结果,如果数组长度大于0,说明该位置已经有房间,那么最新生成的房间应该失效,即被删除
成员函数
初始化函数
该函数将生成第一个房间,初始化TArray<UArrowComponent*>数组
void AXRoomGenerate::GernerateStartRoom()
{
AXRoomBase* SpawnTemp = GetWorld()->SpawnActor<AXRoomBase>(SpawnClass, GetActorTransform());
LatestRoom = SpawnTemp;
NextSpawDir.Append(LatestRoom->ArrowList);
}
检测当前位置是否已有生成
首先需要设置一个GameTrace,因为对于默认的BoxComponent他将对所有Trace检测出Overlap,而为了只检测已有房间的BoxComponent,需要将BoxComponent的Trace设置为新增Trace,然后设置BoxComponent的碰撞检测,只开启新增Trace,其他全部Ignore
在该函数中,将遍历新创建房间的TArray<UBoxComponent>数组,对每个BoxComponent进行检测,当有重叠,会将结果加入到TArray<UPrimitiveComponent>数组中。
bool AXRoomGenerate::CheckSpawnInSameLoc()
{
for (auto& it : LatestRoom->BoxComponentList)
{
//存放重叠的可能
TArray<UPrimitiveComponent*> temp;
it->GetOverlappingComponents(temp);
UnderOverlapList.Append(temp);
}
if (UnderOverlapList.Num() != 0) return false; // need Destroy
else return true;
}
生成下一个房间
该函数为一个递归函数,通过设置的生成房间个数以及TArray<UArrowComponent>个数确定退出条件,每次会从TArray<UArrowComponent>随机选择一个Arrow位置来进行生成,删除Arrow,之后检测该房间位置是否已有生成,如果有,那么删除新生成的房间,并清空TArray<UPrimitiveComponent>数组,递归。如果没有,清空TArray<UPrimitiveComponent>数组,然后将该房间的Arrow数组添加到TArray<UArrowComponent*>数组中,控制次数-1,递归。
void AXRoomGenerate::SpawnNextRoom()
{
if (CurSpawnTimes <= 0 || NextSpawDir.Num() == 0)
{
CloseHoles();
return;
}
UArrowComponent* NextArrow = NextSpawDir[FMath::RandRange(0, NextSpawDir.Num() - 1)];
NextSpawDir.Remove(NextArrow);
FActorSpawnParameters FASP;
FASP.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
AXRoomBase* NextSpawnTemp = GetWorld()->SpawnActor<AXRoomBase>(
NextSpawnRoomList[FMath::RandRange(0, NextSpawnRoomList.Num() - 1)],
NextArrow->GetComponentTransform(),
FASP
);
LatestRoom = NextSpawnTemp;
if (!CheckSpawnInSameLoc())
{
UE_LOG(LogTemp, Warning, TEXT("Destroy"));
UnderOverlapList.Empty();
LatestRoom->Destroy();
GetWorldTimerManager().SetTimer(SpawnTimer, this, &AXRoomGenerate::SpawnNextRoom, 1.0f, false);
//SpawnNextRoom();
}
else
{
NextSpawDir.Append(LatestRoom->ArrowList);
UnderOverlapList.Empty();
CurSpawnTimes--;
GetWorldTimerManager().SetTimer(SpawnTimer, this, &AXRoomGenerate::SpawnNextRoom, 1.0f, false);
//SpawnNextRoom();
}
}
标签:房间,迷宫,C++,生成,BoxComponent,Actor,数组,UE4,TArray
From: https://www.cnblogs.com/XTG111/p/18264141