필요한 개념
// ECollisionChannel을 이용해 여러개의 오브젝트 채널을 등록
// ECC_EngineTraceChannel1은 우리가 쓰지 않는다.
Mesh->SetCollisionObjectType(ECollisionChannel::ECC_PhysicsBody);
enum ECollisionChannel
{
ECC_WorldStatic UMETA(DisplayName="WorldStatic"), -> 0
ECC_WorldDynamic UMETA(DisplayName="WorldDynamic"), -> 1
ECC_Pawn UMETA(DisplayName="Pawn"),
ECC_Visibility UMETA(DisplayName="Visibility" , TraceQuery="1"),
ECC_Camera UMETA(DisplayName="Camera" , TraceQuery="1"),
ECC_PhysicsBody UMETA(DisplayName="PhysicsBody"),
ECC_Vehicle UMETA(DisplayName="Vehicle"),
ECC_Destructible UMETA(DisplayName="Destructible"), -> 7번
/** Reserved for gizmo collision */
ECC_EngineTraceChannel1 UMETA(Hidden), -> 8번
ECC_EngineTraceChannel2 UMETA(Hidden),
ECC_EngineTraceChannel3 UMETA(Hidden),
ECC_EngineTraceChannel4 UMETA(Hidden),
ECC_EngineTraceChannel5 UMETA(Hidden),
ECC_EngineTraceChannel6 UMETA(Hidden),
ECC_GameTraceChannel1 UMETA(Hidden), -> 14번
ECC_GameTraceChannel2 UMETA(Hidden),
ECC_GameTraceChannel3 UMETA(Hidden),
ECC_GameTraceChannel4 UMETA(Hidden),
ECC_GameTraceChannel5 UMETA(Hidden),
ECC_GameTraceChannel6 UMETA(Hidden),
ECC_GameTraceChannel7 UMETA(Hidden),
ECC_GameTraceChannel8 UMETA(Hidden),
ECC_GameTraceChannel9 UMETA(Hidden),
ECC_GameTraceChannel10 UMETA(Hidden),
ECC_GameTraceChannel11 UMETA(Hidden),
ECC_GameTraceChannel12 UMETA(Hidden),
ECC_GameTraceChannel13 UMETA(Hidden),
ECC_GameTraceChannel14 UMETA(Hidden),
ECC_GameTraceChannel15 UMETA(Hidden),
ECC_GameTraceChannel16 UMETA(Hidden),
ECC_GameTraceChannel17 UMETA(Hidden),
ECC_GameTraceChannel18 UMETA(Hidden),
}
프로젝트 세팅 -> 콜리전 -> Preset -> NoCollision에서 트레이스 유형, 오브젝트 유형보면
WorldStatic, WorldDynamic, Pawn, PhysicsBody, Vehicle, Destructible 이후로 1번, 2번 3번.... 이렇게 간다.
이 것과 위의 ECollisionChannel의 구조가 동일하다.

그 다음 오브젝트 타입을 만들게 되면 ECC_GameTraceChannel1, 2, 3, 4 이런식으로 순서대로 지정된다.
Tip)
SpawnEmitter를 사용하게 되면 호출하는 AActor 객체가 자동으로 Component가 생성되고 플레이가 끝나면 자동으로 해제하는 역할을 함
즉, UParticleSystemComponent를 할당해놓고 따로 해제 없이 계속 반복해 호출이 가능하다.(계속 콜하면서 사용하면 됨)
(ParticleSystem을 생성했다가 사라짐, 즉 안쓰고 컴포넌트 만들어놔도 된다는 얘기, SpawnEmitter() 얘는 컴포넌트를 만들어 줬다가 해제하는 역할)
SphereTraceMultiForObjects() : 구형으로 트레이스를 여러개 해서 오브젝트 타입을 여러개 넣어서 해당하는 오브젝트 타입들의 객체를 검출해옴
인자로 들어가는 EObjectTypeQuery형태는 enum형이어서 TEnumAsByte<EObjectTypeQuery>로 해서 값을 전달한다.(타입을 알 수 있도록)
C05_SweepTrigger.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C05_SweepTrigger.generated.h"
// 여기다가 04_Explosion을 연결할 것이다.
UCLASS()
class UONLINE_03_CPP_API AC05_SweepTrigger : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Scene;
UPROPERTY(VisibleDefaultsOnly)
class UBoxComponent* Box;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC05_SweepTrigger();
protected:
virtual void BeginPlay() override;
};
C05_SweepTrigger.cpp
#include "C05_SweepTrigger.h"
#include "Global.h"
#include "C04_Explosion.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"
AC05_SweepTrigger::AC05_SweepTrigger()
{
CHelpers::CreateComponent<USceneComponent>(this, &Scene, "Scene");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Scene);
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Scene);
Box->SetRelativeScale3D(FVector(3));
Box->bHiddenInGame = false;
Text->SetRelativeLocation(FVector(0, 0, 100));
Text->SetRelativeRotation(FRotator(0, 180, 0));
Text->SetRelativeScale3D(FVector(2));
Text->TextRenderColor = FColor::Red;
Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;
Text->Text = FText::FromString(GetName());
}
void AC05_SweepTrigger::BeginPlay()
{
Super::BeginPlay();
TArray<AC04_Explosion*> explosions;
CHelpers::FindActors(GetWorld(), explosions);
// 외부것을 연결
OnActorBeginOverlap.AddDynamic(explosions[0], &AC04_Explosion::ActorBeginOverlap);
}
C03_Cube.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C03_Cube.generated.h"
UCLASS()
class UONLINE_03_CPP_API AC03_Cube : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class UStaticMeshComponent* Mesh;
public:
AC03_Cube();
protected:
virtual void BeginPlay() override;
};
C03_Cube.cpp
#include "C03_Cube.h"
#include "Global.h"
#include "Components/StaticMeshComponent.h"
AC03_Cube::AC03_Cube()
{
CHelpers::CreateComponent<UStaticMeshComponent>(this, &Mesh, "Mesh");
UStaticMesh* mesh;
CHelpers::GetAsset<UStaticMesh>(&mesh, "StaticMesh'/Game/Meshes/M_Cube.M_Cube'");
Mesh->SetStaticMesh(mesh);
Mesh->SetSimulatePhysics(true);
// ECollisionChannel을 이용해 여러개의 오브젝트 채널을 등록
Mesh->SetCollisionObjectType(ECollisionChannel::ECC_PhysicsBody);
}
void AC03_Cube::BeginPlay()
{
Super::BeginPlay();
}

C04_Explosion.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C04_Explosion.generated.h"
UCLASS()
class UONLINE_03_CPP_API AC04_Explosion : public AActor
{
GENERATED_BODY()
public:
AC04_Explosion();
private:
UPROPERTY(VisibleDefaultsOnly)
class UParticleSystemComponent* Particle;
protected:
virtual void BeginPlay() override;
public:
// 이번에는 밖에다가 함수를 세팅, 다이나믹 델리게이트여서 이름도 일치해야함
UFUNCTION()
void ActorBeginOverlap(AActor* OverlappedActor, AActor* OtherActor);
};
C04_Explosion.cpp
#include "C04_Explosion.h"
#include "Global.h"
#include "Particles/ParticleSystemComponent.h"
AC04_Explosion::AC04_Explosion()
{
CHelpers::CreateComponent<UParticleSystemComponent>(this, &Particle, "Particle");
UParticleSystem* particle;
CHelpers::GetAsset<UParticleSystem>(&particle, "ParticleSystem'/Game/Effects/P_Explosion2.P_Explosion2'");
// BP에서 보면 template 부분에 할당해줬다.
// 파티클 세팅부분
Particle->SetTemplate(particle);
// 바로 플레이 안되도록
Particle->bAutoActivate = false;
}
void AC04_Explosion::BeginPlay()
{
Super::BeginPlay();
}
void AC04_Explosion::ActorBeginOverlap(AActor* OverlappedActor, AActor* OtherActor)
{
// ResetParticles() : 이전에 플레이되었던 결과를 초기화 시킴
Particle->ResetParticles();
Particle->SetActive(true);
/*
bool UKismetSystemLibrary::SphereTraceMultiForObjects(UObject* WorldContextObject, const FVector Start, const FVector End, float Radius, const TArray<TEnumAsByte<EObjectTypeQuery> > & ObjectTypes, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, TArray<FHitResult>& OutHits, bool bIgnoreSelf, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime)
{
static const FName SphereTraceMultiName(TEXT("SphereTraceMultiForObjects"));
FCollisionQueryParams Params = ConfigureCollisionParams(SphereTraceMultiName, bTraceComplex, ActorsToIgnore, bIgnoreSelf, WorldContextObject);
FCollisionObjectQueryParams ObjectParams = ConfigureCollisionObjectParams(ObjectTypes);
if (ObjectParams.IsValid() == false)
{
UE_LOG(LogBlueprintUserMessages, Warning, TEXT("Invalid object types"));
return false;
}
// UWorld에 있는 추적함수를 사용하게 되면 충돌체의 모양을 정의해서 사용할 수 있으며
// UkismetSystemLibrary에도 각 모양으로 추적할 수 있도록 함수들이 정의되어 있음
// Make~()함수로 그릴 수 있다.(그렇게 해서 충돌체를 그려서) 공간을 찾아낼 수 있음
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
bool const bHit = World ? World->SweepMultiByObjectType(OutHits, Start, End, FQuat::Identity, ObjectParams, FCollisionShape::MakeSphere(Radius), Params) : false;
#if ENABLE_DRAW_DEBUG
DrawDebugSphereTraceMulti(World, Start, End, Radius, DrawDebugType, bHit, OutHits, TraceColor, TraceHitColor, DrawTime);
#endif
return bHit;
}
*/
FVector start = GetActorLocation();
// end와 start가 같으면 안됨
// 위까지 구가 찬다고 생각하면 됨
FVector end = FVector(start.X, start.Y, start.Z + 10);
// 여기 들어갈 수 있는 것은 오브젝트 타입들
TArray<TEnumAsByte<EObjectTypeQuery>> queries;
// EObjectTypeQuery에 죄다 숫자 밖에 없다. 프로젝트 세팅 -> 콜리전 -> preset -> NoCollision -> 오브젝트 유형에 있는 것들이 1, 2, 3, 4...
// Cube때의 ECollisionChannel때와 같은 애를 가리키지만, 다른 방식으로 가리키는 것 뿐임
// ECollisionChannel는 미리 정의 되어있는 앞에 있는 것을 쓰고, 이후 추가적으로 숫자로 정의된 것을 쓰라는 것(출력할때)
// ECollisionChannel는 채널 하나만 지정가능
// EObjectTypeQuery는 오브젝트 타입
// EObjectTypeQuery은 배열로 넣을 수 있도록 할려고 분할해놓은 거로 보임
// 결국에는 같은 애
queries.Add(EObjectTypeQuery::ObjectTypeQuery4);
TArray<AActor*> ignoreActors;
ignoreActors.Add(this);
TArray<FHitResult> hitResults;
// 얘는 object타입을 여러개 지정가능
// Sphere말고 box나 다른형으로 쓸거면 다른걸로 쓰면됨
// 여기선 구형 씀
// 1. 월드 2,3 어느지점 부터 어느지점까지 찾을 거냐 4. 반지름(구의 넓이) 5. 오브젝트 타입들 6.일일히 삼각형 단위로 충돌할거냐 7.무시할 액터들, 8 드로우모드 지정 (EDrawDebugTrace::ForOneFrame(매프레임마다 그려라)),
// 9. 리턴될 HitResult 배열(Multi여서 여러개를 리턴받음), 10 : 자기자신 제거여부
// 인자 5번 보면 const TArray<TEnumAsByte<EObjectTypeQuery> > & ObjectTypes
// EObjectTypeQuery가 Enum class가 아니라서 어떤 타입인지 언리얼에서는 어떻게 다뤄야할지 몰른다.
// 언리얼 에서는
/*
enum class A : uint8 -> 이런식으로 뒤에 자료형뭔지 알 수 있도록 정의되어있음
{
}
이래서 그냥 enum 같은 경우는 자료형을 알 수가 없다.
즉, enum class는 정의시 어떤 크기로 정의되는지 명시가 되지만, enum 자체로 사용하게 되면
해당 enum 자료형의 크기를 알 수 없으므로 TEnumAsByte를 사용해 Byte(uint8)으로 크기를 지정해준다.
*/
// 하나라도 검출되면 true나옴
if (UKismetSystemLibrary::SphereTraceMultiForObjects(GetWorld(), start, end, 200, queries, false, ignoreActors, EDrawDebugTrace::ForOneFrame, hitResults, true))
{
for (const FHitResult& hitResult : hitResults)
{
UStaticMeshComponent* meshComponent = Cast<UStaticMeshComponent>(hitResult.GetActor()->GetRootComponent());
// null이 아니라면(!= NULL)
if (!!meshComponent)
{
// 구형으로 퍼져나가는 힘을 받는 함수
// 2 : 범위, 3 : 강도 4 : 어떻게 퍼질 거냐
// meshComponent->GetMass()(질량) * 700.0f -> 질량 * 700
// ERadialImpulseFalloff::RIF_Linear -> 거리에 따라 받는 힘이 줄어들도록
meshComponent->AddRadialImpulse(GetActorLocation(), 1000, meshComponent->GetMass() * 700.0f, ERadialImpulseFalloff::RIF_Linear);
}
}
}
}
결과
'Unreal Engine 4 > C++' 카테고리의 다른 글
| <Unreal C++> 27 - Gun Shooting Mode(Aiming), Fire & CrossHair (0) | 2022.04.25 |
|---|---|
| <Unreal C++> 24 - Gun Shooting Mode(Rifle Equip) (0) | 2022.04.24 |
| <Unreal C++> 20 - Line Trace / Dynamic Delegate (0) | 2022.04.15 |
| <Unreal C++> 19 - Function Override (0) | 2022.04.15 |
| <Unreal C++> 18 - Event (0) | 2022.04.15 |