最近无聊时候,创建了一个自动生成破碎物件的Actor, C++版本,主要时测试,实际使用还有些缺陷,后期有时间我会慢慢补足对应功能。下边就上源码了
先是.h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "PhysicsEngine/DestructibleActor.h"
#include "DestructibleCreator.generated.h"
USTRUCT(Blueprintable)
struct FSpawnPoint
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 x = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 y = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 z = 0;
FSpawnPoint(int32 tx = 0, int32 ty = 0, int32 tz = 0) : x(tx), y(ty), z(tz)
{
}
__inline bool operator == (const FSpawnPoint &Other)
{
return (Other.x == x && Other.y == y && Other.z == z);
}
};
/**
* //本文为CSDN博主执手画眉弯原创,未经允许不得转载!
*/
UCLASS()
class VEHICLEPROJECT_API ADestructibleCreator : public ADestructibleActor
{
GENERATED_BODY()
public:
ADestructibleCreator();
virtual void OnConstruction(const FTransform& Transform);
UFUNCTION(BlueprintCallable, Category = "OnHit")
void OnHit(UPrimitiveComponent* MyComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
UFUNCTION(BlueprintCallable, Category = "OnOverlap")
void OnOverlap( AActor* OtherActor);
//随机生成
void SpawnByRandom();
//根据保存的序列生成
void SpawnBySave();
//查找这个点是否存在保存的数组中
bool FindSpawnPoint(const FSpawnPoint &Other);
//查找下方是否有元素,防止搭空台
bool IsHaveItemUnderIt(const FSpawnPoint &Other);
public:
//whitch DestructibleMesh you will be create
//UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "CreateMesh")
//class UDestructibleMesh* CreateDestructibleMesh;
//End Point, MakeEditWidget == Show3DWidget
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EndPoint", Meta = (MakeEditWidget = true))
FVector EndPoint;
//Mesh Length : X
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "CreateMesh")
float Length = 100.f;
//Mesh Width : Y
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "CreateMesh")
float Width = 100.f;
//Mesh Height : X
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "CreateMesh")
float Height = 100.f;
//Create Weight 0.1f - 1.f
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "CreateMesh", Meta = (UIMin = 0.1f, UIMax = 1.f))
float CreateWeight = 1.f;
//Mesh Height : X
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpawnTrigger")
bool bSpawnMesh = false;
//Save : X
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpawnTrigger")
bool bSave = false;
int32 LengthNum = 0;
int32 HeightNum = 0;
int32 WidthNum = 0;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CreateMesh")
int32 TotalNum = 0;
//Spawn Array
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SpawnArray")
TArray <FSpawnPoint> SpawnArray;
};
然后是cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
//#include "MyProject.h" 这里是你的工程头文件
#include "DestructibleCreator.h"
ADestructibleCreator::ADestructibleCreator()
{
PrimaryActorTick.bCanEverTick = true;
bReplicates = true;
//Simulation Generates Hit Events
GetDestructibleComponent()->SetNotifyRigidBodyCollision(true);
}
void ADestructibleCreator::OnConstruction(const FTransform& Transform)
{
if (!bSpawnMesh)
return;
if (bSave)
{
SpawnBySave();
}
else
{
SpawnByRandom();
}
//注册所有组件
RegisterAllComponents();
}
//本文为CSDN博主执手画眉弯原创,未经允许不得转载!
void ADestructibleCreator::OnHit(UPrimitiveComponent* MyComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
//碰撞时候给所有子组件施加伤害,保证同时破碎
TArray<UActorComponent*> ChildComponents = GetComponentsByClass(UDestructibleComponent::StaticClass());
if (ChildComponents.Num() > 0)
{
for (int32 i = 0; i < ChildComponents.Num(); i++)
{
UDestructibleComponent *pChild = Cast<UDestructibleComponent>(ChildComponents[i]);
if (pChild)
{
pChild->ApplyDamage(100.f, pChild->K2_GetComponentLocation(), NormalImpulse, 0.f);
}
}
}
}
void ADestructibleCreator::OnOverlap(AActor* OtherActor)
{
//Overlap时候给所有子组件施加伤害,保证同时破碎
TArray<UActorComponent*> ChildComponents = GetComponentsByClass(UDestructibleComponent::StaticClass());
if (ChildComponents.Num() > 0)
{
for (int32 i = 0; i < ChildComponents.Num(); i++)
{
UDestructibleComponent *pChild = Cast<UDestructibleComponent>(ChildComponents[i]);
if (pChild)
{
pChild->ApplyDamage(100.f, pChild->K2_GetComponentLocation(), FVector::ZeroVector, 0.f);
}
}
}
}
void ADestructibleCreator::SpawnByRandom()
{
class UDestructibleMesh* theMesh = GetDestructibleComponent()->GetDestructibleMesh();
if (theMesh == nullptr)
return;
if (SpawnArray.Num() > 0)
SpawnArray.Empty();
bool bUsePhysics = GetDestructibleComponent()->IsSimulatingPhysics();
LengthNum = UKismetMathLibrary::FFloor(UKismetMathLibrary::Abs(EndPoint.X) / Length);
WidthNum = UKismetMathLibrary::FFloor(UKismetMathLibrary::Abs(EndPoint.Y) / Width);
HeightNum = UKismetMathLibrary::FFloor(UKismetMathLibrary::Abs(EndPoint.Z) / Height);
float fxDir = EndPoint.X > 0.f ? 1.f : -1.f;
float fyDir = EndPoint.Y > 0.f ? 1.f : -1.f;
float fzDir = EndPoint.Z > 0.f ? 1.f : -1.f;
TotalNum = 0;
SpawnArray.Add(FSpawnPoint(0.f, 0.f, 0.f));
for (int32 i = 0; i <= LengthNum; i++)
{
for (int32 j = 0; j <= WidthNum; j++)
{
for (int32 k = 0; k <= HeightNum; k++)
{
//使用物理时候,第一个会消失,重新生成一次
if (!bUsePhysics)
{
if (i == 0 && j == 0 && k == 0)
{
TotalNum++;
continue;
}
}
if (UKismetMathLibrary::RandomFloat() > CreateWeight)
continue;
FSpawnPoint tempPoint = FSpawnPoint(i, j, k);
if(!IsHaveItemUnderIt(tempPoint))
continue;
SpawnArray.Add(tempPoint);
UDestructibleComponent *pChildComponent = NewObject<UDestructibleComponent>(this, UDestructibleComponent::StaticClass());
pChildComponent->CreationMethod = EComponentCreationMethod::UserConstructionScript;
pChildComponent->SetDestructibleMesh(theMesh);
pChildComponent->SetRelativeLocation(FVector(i * Length * fxDir, j * Width * fyDir, k * Height * fzDir));
pChildComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
pChildComponent->SetSimulatePhysics(bUsePhysics);
//Simulation Generates Hit Events
pChildComponent->SetNotifyRigidBodyCollision(true);
TotalNum++;
}
}
}
}
void ADestructibleCreator::SpawnBySave()
{
class UDestructibleMesh* theMesh = GetDestructibleComponent()->GetDestructibleMesh();
if (theMesh == nullptr)
return;
bool bUsePhysics = GetDestructibleComponent()->IsSimulatingPhysics();
LengthNum = UKismetMathLibrary::FFloor(UKismetMathLibrary::Abs(EndPoint.X) / Length);
WidthNum = UKismetMathLibrary::FFloor(UKismetMathLibrary::Abs(EndPoint.Y) / Width);
HeightNum = UKismetMathLibrary::FFloor(UKismetMathLibrary::Abs(EndPoint.Z) / Height);
float fxDir = EndPoint.X > 0.f ? 1.f : -1.f;
float fyDir = EndPoint.Y > 0.f ? 1.f : -1.f;
float fzDir = EndPoint.Z > 0.f ? 1.f : -1.f;
TotalNum = 0;
for (int32 i = 0; i <= LengthNum; i++)
{
for (int32 j = 0; j <= WidthNum; j++)
{
for (int32 k = 0; k <= HeightNum; k++)
{
//使用物理时候,第一个会消失,重新生成一次
if (!bUsePhysics)
{
if (i == 0 && j == 0 && k == 0)
{
TotalNum++;
continue;
}
}
if(!FindSpawnPoint(FSpawnPoint(i, j, k)))
continue;
UDestructibleComponent *pChildComponent = NewObject<UDestructibleComponent>(this, UDestructibleComponent::StaticClass());
pChildComponent->CreationMethod = EComponentCreationMethod::UserConstructionScript;
pChildComponent->SetDestructibleMesh(theMesh);
pChildComponent->SetRelativeLocation(FVector(i * Length * fxDir, j * Width * fyDir, k * Height * fzDir));
pChildComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
pChildComponent->SetSimulatePhysics(bUsePhysics);
//Simulation Generates Hit Events
pChildComponent->SetNotifyRigidBodyCollision(true);
TotalNum++;
}
}
}
}
bool ADestructibleCreator::FindSpawnPoint(const FSpawnPoint &Other)
{
for (int32 i = 0; i < SpawnArray.Num(); i++)
{
if (SpawnArray[i] == Other)
{
return true;
}
}
return false;
}
bool ADestructibleCreator::IsHaveItemUnderIt(const FSpawnPoint &Other)
{
if (Other.z == 0)
return true;
return FindSpawnPoint(FSpawnPoint(Other.x , Other.y, Other.z - 1));
}//本文为CSDN博主执手画眉弯原创,未经允许不得转载!
最后在蓝图中回调了2个事件
设置下每个元素在x,y,z上生成的间距,勾选上spawnMesh 就可以生成了, CreateWeight是生成的权重值,从0.1-1.0,权重越大,0.1代表10%的生成几率,1.0代表100%的生成。Save代表保存现在布局,不会因为移动或者选中而改变。 totalNum可以查看一共生成了多少元素。
放在地图中,选中endPoint ,移动endPoint的位置来生成。