UE4 自动创建破碎物件的actor(C++版本)

         最近无聊时候,创建了一个自动生成破碎物件的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的位置来生成。

 

 

发布了30 篇原创文章 · 获赞 24 · 访问量 4万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览