[UE] Collsion(trigger, MultiTrigger, Explosion)
충돌(Collision)의 가장 기본적인 방법은 두 물체의 바운딩 박스(Bounding Box)를 비교하는 것이다. 바운딩 박스란 물체를 둘러싸는 사각형 영역을 의미한다. 이 방법은 빠르고 간단하지만, 물체의 모양에 대한 정확한 충돌 검사는 수행하지 않는다.
목차
Trigger
충돌(Collision)의 가장 기본적인 방법은 두 물체의 바운딩 박스(Bounding Box)를 비교하는 것이다. 바운딩 박스란 물체를 둘러싸는 사각형 영역을 의미한다. 이 방법은 빠르고 간단하지만, 물체의 모양에 대한 정확한 충돌 검사는 수행하지 않는다.
보다 정확한 충돌 검사를 위해서는, 물체의 형태를 고려한 검사가 필요하다. 이를 위해 언리얼 C++에서는 물체의 형태를 기하학적인 도형으로 표현할 수 있는 Collision Shape을 사용한다. Collision Shape은 물체의 모양과 크기를 정확히 나타내기 위해 사용된다.
언리얼 C++에서는 다양한 Collision Shape을 제공한다. 가장 간단한 방법은 Sphere Collision Shape을 사용하는 것이다. Sphere Collision Shape은 구 형태의 충돌 모델을 사용한다. 이 방법은 빠르고 간단하지만, 물체의 모양을 구 형태로 근사하는 것이 필요하다.
보다 정확한 충돌 검사를 위해서는, 복잡한 형태의 Collision Shape을 사용할 수 있다. 언리얼 C++에서는 Box, Capsule, Convex Hull, Mesh 등 다양한 Collision Shape을 제공한다.
충돌 검사를 수행하고 나면, 충돌한 물체의 위치와 방향, 속도 등을 계산할 수 있다. 이를 바탕으로 충돌한 물체에 대한 반응을 구현할 수 있다. 이를 위해서는 충돌 응답(Collision Response) 코드를 작성해야 한다. 충돌 응답 코드는 충돌한 물체가 서로 어떻게 반응해야 하는지를 결정하는 것이다. 예를 들어, 물체가 서로 충돌하면 반대 방향으로 튕겨져 나가거나, 속도가 감소하는 등의 반응을 구현할 수 있다.
01_Spawn | |
C01_Properties.h .cpp C02_Mesh C02_Mesh_Sphere C02_Mesh_Cone C03_Spawner.h .cpp |
|
02_Profiler | |
C01_Log.h .cpp C02_DrawDebug.h .cpp |
|
03_Collision | |
C01_ActorOverlap.h .cpp C02_ComponentOverlap.h .cpp C03_OverlapAndHit.h .cpp C04_Trigger.h .cpp C04_Light.h .cpp C05_MultiTrigger.h .cpp 생성 C05_FallingBox.h .cpp 생성 C05_SpotLight.h .cpp 생성 C06_EventTrigger.h .cpp 생성 C06_Explosion.h .cpp 생성 |
|
Utilities | |
CHelpers.h | |
CAnimInstance.h .cpp CGameMode.h .cpp CPlayer.h .cpp |
C04_Trigger
C04_Trigger.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C04_Trigger.generated.h"
DECLARE_DELEGATE(FBoxLightOverlap); //void func_name()
DECLARE_DELEGATE_RetVal_OneParam(FString, FBoxLightColorOverlap, FLinearColor);
UCLASS()
class U2212_03_API AC04_Trigger : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleAnywhere)
class USceneComponent* Root;
UPROPERTY(VisibleAnywhere)
class UBoxComponent* Box;
UPROPERTY(VisibleAnywhere)
class UTextRenderComponent* Text;
public:
AC04_Trigger();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);
UFUNCTION()
void OnComponentEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
public:
FBoxLightOverlap OnBoxLightBeginOverlap; //이벤트 변수
FBoxLightOverlap OnBoxLightEndOverlap; //이벤트 변수
FBoxLightColorOverlap OnBoxLightColorOverlap;
};
C04_Trigger.cpp
#include "03_Collision/C04_Trigger.h"
#include "Global.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"
AC04_Trigger::AC04_Trigger()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Root);
CreateTextRender();
Box->bHiddenInGame = false;
Box->SetRelativeScale3D(FVector(3));
}
void AC04_Trigger::BeginPlay()
{
Super::BeginPlay();
Box->OnComponentBeginOverlap.AddDynamic(this, &AC04_Trigger::OnComponentBeginOverlap);
Box->OnComponentEndOverlap.AddDynamic(this, &AC04_Trigger::OnComponentEndOverlap);
}
void AC04_Trigger::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
{
if (OnBoxLightBeginOverlap.IsBound())
OnBoxLightBeginOverlap.Execute();
if (OnBoxLightBeginOverlap.IsBound())
{
FString str = OnBoxLightColorOverlap.Execute(FLinearColor::MakeRandomColor());
CLog::Print(str);
}
}
void AC04_Trigger::OnComponentEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (OnBoxLightEndOverlap.IsBound())
OnBoxLightEndOverlap.Execute();
}
C04_Light
C04_Light.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C04_Light.generated.h"
UCLASS()
class U2212_03_API AC04_Light : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleAnywhere)
class USceneComponent* Root;
UPROPERTY(VisibleAnywhere)
class UPointLightComponent* PointLight;
UPROPERTY(VisibleAnywhere)
class UPointLightComponent* PointLight2;
UPROPERTY(VisibleAnywhere)
class UTextRenderComponent* Text;
public:
AC04_Light();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnLight();
UFUNCTION()
void OffLight();
UFUNCTION()
FString OnRandomColor(FLinearColor InColor);
};
C04_Light.cpp
#include "03_Collision/C04_Light.h"
#include "Global.h"
#include "C04_Trigger.h"
#include "Components/PointLightComponent.h"
#include "Components/TextRenderComponent.h"
AC04_Light::AC04_Light()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UPointLightComponent>(this, &PointLight, "PointLight", Root);
CHelpers::CreateComponent<UPointLightComponent>(this, &PointLight2, "PointLight2", Root);
CreateTextRender();
PointLight->SetRelativeLocation(FVector(0, -50, 0));//Actor로부터의 상대간격
PointLight->LightColor = FColor::Red;
PointLight->Intensity = 1e+4f; //1 * 10 ^ 4
PointLight->AttenuationRadius = 200; //감쇄 반경
PointLight2->SetRelativeLocation(FVector(0, +50, 0));
PointLight2->LightColor = FColor::Red;
PointLight2->Intensity = 1e+4f; //1 * 10 ^ 4
PointLight2->AttenuationRadius = 200; //감쇄 반경
}
void AC04_Light::BeginPlay()
{
Super::BeginPlay();
//for (AActor* actor : GetWorld()->GetCurrentLevel()->Actors)
//{
// if (!!actor && actor->IsA<AC04_Trigger>())
// CLog::Log(actor->GetName());
//}
OffLight();
AC04_Trigger* trigger = CHelpers::FindActor<AC04_Trigger>(GetWorld());
CheckNull(trigger);
trigger->OnBoxLightBeginOverlap.BindUFunction(this, "OnLight");
trigger->OnBoxLightEndOverlap.BindUFunction(this, "OffLight");
trigger->OnBoxLightColorOverlap.BindUFunction(this, "OnRandomColor");
}
void AC04_Light::OnLight()
{
PointLight->SetVisibility(true);
}
void AC04_Light::OffLight()
{
PointLight->SetVisibility(false);
PointLight2->SetVisibility(false);
}
FString AC04_Light::OnRandomColor(FLinearColor InColor)
{
PointLight2->SetVisibility(true);
PointLight2->SetLightColor(InColor);
return "Color : " + InColor.ToString();
}
실행화면
왼쪽 빛은 Red로 오른쪽 빛은 Random하게 출력된다.
MultiTrigger & Falling Box
C05_MultiTrigger
C05_MultiTrigger.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C05_MultiTrigger.generated.h"
//Multicast의 경우 Event와 RetVal를 동시에 사용할 수 없다.
DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiLightOverlap, int32, FLinearColor);
UCLASS()
class U2212_03_API AC05_MultiTrigger : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleAnywhere)
class USceneComponent* Root;
UPROPERTY(VisibleAnywhere)
class UBoxComponent* Box;
UPROPERTY(VisibleAnywhere)
class UTextRenderComponent* Text;
public:
AC05_MultiTrigger();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);
public:
FMultiLightOverlap OnMultiLightOverlap;
};
DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiLightOverlap, int32, FLinearColor);
- Multicast의 경우 Event와 RetVal를 사용할 수 없다.
C05_MultiTrigger.cpp
#include "03_Collision/C05_MultiTrigger.h"
#include "Global.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"
AC05_MultiTrigger::AC05_MultiTrigger()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Root);
CreateTextRender();
Box->bHiddenInGame = false;
Box->SetRelativeScale3D(FVector(3));
}
void AC05_MultiTrigger::BeginPlay()
{
Super::BeginPlay();
Box->OnComponentBeginOverlap.AddDynamic(this, &AC05_MultiTrigger::OnComponentBeginOverlap);
}
void AC05_MultiTrigger::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
{
CheckFalse(OnMultiLightOverlap.IsBound());
int32 index = UKismetMathLibrary::RandomIntegerInRange(0, 2); //Global.h 내에 KismetMathLibrary가 있다.
FLinearColor color = FLinearColor::MakeRandomColor();
OnMultiLightOverlap.Broadcast(index, color);//Multicast를 사용할 때 Broadcast 사용.
}
OnMultiLightOverlap.Broadcast(index, color)
- Multicast를 사용할 때 Broadcast를 사용한다.
- 반면에 Singlecast를 사용할 때는 Unitcast를 사용한다. 여기서는 Multicast로 만들었기 때문에 사용할 수 없다.
C05_FallingBox
C05_FallingBox.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C05_FallingBox.generated.h"
UCLASS()
class U2212_03_API AC05_FallingBox : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class UStaticMeshComponent* Meshes[3];//Static Mesh 3개 배열로 생성
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC05_FallingBox();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnPhysics(int32 InIndex, FLinearColor InColor);
private:
class UMaterialInstanceDynamic* Materials[3]; //Material
FVector WorldLocation[3]; //최초 위치 기록
};
C05_FallingBox.cpp
#include "03_Collision/C05_FallingBox.h"
#include "Global.h"
#include "C05_MultiTrigger.h"
#include "Components/StaticMeshComponent.h"
#include "Components/TextRenderComponent.h"
#include "Materials/MaterialInstanceConstant.h"
#include "Materials/MaterialInstanceDynamic.h"
AC05_FallingBox::AC05_FallingBox()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
UStaticMesh* mesh;
CHelpers::GetAsset<UStaticMesh>(&mesh, "StaticMesh'/Game/Meshes/Cube.Cube'");
for(int32 i = 0; i<3; i++)
{
FString str;
str.Append("Meshes");
str.Append(FString::FromInt(i + 1));
CHelpers::CreateComponent<UStaticMeshComponent>(this, &Meshes[i], FName(str), Root);
Meshes[i]->SetRelativeLocation(FVector(0, i * 150, 0));
Meshes[i]->SetStaticMesh(mesh);
Meshes[i]->SetSimulatePhysics(true);
}
CreateTextRender();
}
void AC05_FallingBox::BeginPlay()
{
Super::BeginPlay();
UMaterialInstanceConstant* material;
CHelpers::GetAssetDynamic<UMaterialInstanceConstant>(&material, "MaterialInstanceConstant'/Game/Materials/M_White_Inst.M_White_Inst'");
for (int32 i = 0; i < 3; i++)
{
Materials[i] = UMaterialInstanceDynamic::Create(material, this);
Materials[i]->SetVectorParameterValue("Color", FLinearColor::White);
Meshes[i]->SetMaterial(0, Materials[i]);
Meshes[i]->SetSimulatePhysics(false);
FTransform transform = Meshes[i]->GetComponentToWorld();
WorldLocation[i] = transform.GetLocation();
}
AC05_MultiTrigger* trigger = CHelpers::FindActor<AC05_MultiTrigger>(GetWorld());
CheckNull(trigger);
trigger->OnMultiLightOverlap.AddUFunction(this, "OnPhysics");
trigger->OnMultiLightOverlap.Broadcast(0, FLinearColor::Red);
}
void AC05_FallingBox::OnPhysics(int32 InIndex, FLinearColor InColor)
{
for (int32 i = 0; i < 3; i++)
{
Materials[i]->SetVectorParameterValue("Color", FLinearColor::White);
Meshes[i]->SetSimulatePhysics(false);
Meshes[i]->SetWorldLocation(WorldLocation[i]);
}
//InIndex로 받은 mesh만 Red 색과 피직스 적용.
Materials[InIndex]->SetVectorParameterValue("Color", FLinearColor::Red);
Meshes[InIndex]->SetSimulatePhysics(true);
}
- Clear: 연결된 것 전체 제거
- Remove: 하나씩 제거
- RemoveAll: 객체를 줘서 제거. Clear와 유사하다.
이벤트
여러 함수에 바인딩하여 모두 한 번에 실행시킬 수 있는 델리게이트이다.
언리얼 공식문서 (한국어/영어)
실행화면
C05_SpotLight
C05_SpotLight.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C05_SpotLight.generated.h"
UCLASS()
class U2212_03_API AC05_SpotLight : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class USpotLightComponent* Lights[3]; //Light 3개 생성
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC05_SpotLight();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnLight(int32 InIndex, FLinearColor InColor);
};
C05_SpotLight.cpp
#include "03_Collision/C05_SpotLight.h"
#include "Global.h"
#include "C05_MultiTrigger.h"
#include "Components/SpotLightComponent.h"
#include "Components/TextRenderComponent.h"
AC05_SpotLight::AC05_SpotLight()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
for (int32 i = 0; i < 3; i++)
{
FString str;
str.Append("Lights");
str.Append(FString::FromInt(i + 1));
CHelpers::CreateComponent<USpotLightComponent>(this, &Lights[i], FName(str), Root);
Lights[i]->SetRelativeLocation(FVector(0, i * 150, 0));
Lights[i]->SetRelativeRotation(FRotator(-90, 0, 0));//Pitch, Yaw, Roll 순서
Lights[i]->Intensity = 1e+5f;
Lights[i]->OuterConeAngle = 25;
}
CreateTextRender();
}
void AC05_SpotLight::BeginPlay()
{
Super::BeginPlay();
AC05_MultiTrigger* trigger = CHelpers::FindActor<AC05_MultiTrigger>(GetWorld());
CheckNull(trigger);
trigger->OnMultiLightOverlap.AddUFunction(this, "OnLight");
}
void AC05_SpotLight::OnLight(int32 InIndex, FLinearColor InColor)
{
for (int32 i = 0; i < 3; i++)
Lights[i]->SetLightColor(FLinearColor::White);
Lights[InIndex]->SetLightColor(InColor);
}
Event Trigger & Explosion
C06_EventTrigger
C06_EventTrigger.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C06_EventTrigger.generated.h"
UCLASS()
class U2212_03_API AC06_EventTrigger : public AActor
{
GENERATED_BODY()
private:
DECLARE_EVENT_OneParam(AC06_EventTrigger, FExplosionEvent, int32);
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class UBoxComponent* Box;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC06_EventTrigger();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
public:
FExplosionEvent OnExplosionEvent;
};
C06_EventTrigger.cpp
#include "03_Collision/C06_EventTrigger.h"
#include "Global.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"
AC06_EventTrigger::AC06_EventTrigger()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Root);
CreateTextRender();
Box->SetRelativeScale3D(FVector(3));
Box->bHiddenInGame = false;
}
void AC06_EventTrigger::BeginPlay()
{
Super::BeginPlay();
Box->OnComponentBeginOverlap.AddDynamic(this, &AC06_EventTrigger::OnComponentBeginOverlap);
}
void AC06_EventTrigger::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
CheckFalse(OnExplosionEvent.IsBound());
int32 index = UKismetMathLibrary::RandomIntegerInRange(0, 2);
OnExplosionEvent.Broadcast(index);
}
C06_Explosion
06_Explosion.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C06_Explosion.generated.h"
UCLASS()
class U2212_03_API AC06_Explosion : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, Category = "Particles")
class UParticleSystem* Particles[3];
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC06_Explosion();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnExplosion(int32 InIndex);
};
06_Explosion.cpp
#include "03_Collision/C06_Explosion.h"
#include "Global.h"
#include "C06_EventTrigger.h" //trigger를 가져다가 쓰기 위해 헤더 추가
#include "Particles/ParticleSystem.h"
#include "Components/TextRenderComponent.h"
AC06_Explosion::AC06_Explosion()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CreateTextRender();
CHelpers::GetAsset<UParticleSystem>(&Particles[0], "ParticleSystem'/Game/AdvancedMagicFX12/particles/P_ky_hit.P_ky_hit'");
CHelpers::GetAsset<UParticleSystem>(&Particles[1], "ParticleSystem'/Game/AdvancedMagicFX12/particles/P_ky_hit_dark.P_ky_hit_dark'");
CHelpers::GetAsset<UParticleSystem>(&Particles[2], "ParticleSystem'/Game/AdvancedMagicFX12/particles/P_ky_hit_fire.P_ky_hit_fire'");
}
void AC06_Explosion::BeginPlay()
{
Super::BeginPlay();
//trigger를 연결해준다.
AC06_EventTrigger* trigger = CHelpers::FindActor<AC06_EventTrigger>(GetWorld());
CheckNull(trigger);
trigger->OnExplosionEvent.AddUFunction(this, "OnExplosion");
trigger->OnExplosionEvent.Broadcast(0);
}
void AC06_Explosion::OnExplosion(int32 InIndex)
{
//Global.h 내의 Kismet/GameplayStatics.h를 사용.
//BP에서는 World가 자동으로 들어가지만 UnrealC++에서는 자동으로 들어가지 않기 때문에 GetWorld()를 넣어주어야 한다.
//Particles에 들어온 번호(InIndex)를 플레이시킨다.
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), Particles[InIndex], GetActorLocation());
}
실행화면
'⭐ Unreal Engine > UE FPS TPS' 카테고리의 다른 글
[UE] Line Trace, Multi Trace, TPS 기본 세팅 (0) | 2023.03.15 |
---|---|
[UE] Collision(Override), BP와 C++ 실행순서 (0) | 2023.03.14 |
[UE] Collision(Overlap, hit) (0) | 2023.03.09 |
[UE] Character Animation, Collsion (0) | 2023.03.08 |
[UE] Character, GameMode (0) | 2023.03.07 |
댓글
이 글 공유하기
다른 글
-
[UE] Line Trace, Multi Trace, TPS 기본 세팅
[UE] Line Trace, Multi Trace, TPS 기본 세팅
2023.03.15 -
[UE] Collision(Override), BP와 C++ 실행순서
[UE] Collision(Override), BP와 C++ 실행순서
2023.03.14 -
[UE] Collision(Overlap, hit)
[UE] Collision(Overlap, hit)
2023.03.09 -
[UE] Character Animation, Collsion
[UE] Character Animation, Collsion
2023.03.08