[UE] Collision(Override), BP와 C++ 실행순서
충돌 검사를 수행하고 나면, 충돌한 물체의 위치와 방향, 속도 등을 계산할 수 있다. 이를 바탕으로 충돌한 물체에 대한 반응을 구현할 수 있다. 이를 위해서는 충돌 응답(Collision Response) 코드를 작성해야 한다. 충돌 응답 코드는 충돌한 물체가 서로 어떻게 반응해야 하는지를 결정하는 것이다. 예를 들어, 물체가 서로 충돌하면 반대 방향으로 튕겨져 나가거나, 속도가 감소하는 등의 반응을 구현할 수 있다.
목차
Collision - Override
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 생성 C07_Override.h .cpp 생성 |
|
04_Trace | |
C01_Trigger.h .cpp 생성 C01_SphereTrace.h .cpp 생성 |
|
Utilities | |
CHelpers.h | |
CAnimInstance.h .cpp CGameMode.h .cpp CPlayer.h .cpp |
C07_Override
C07_Override.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C07_Override.generated.h"
UCLASS()
class U2212_03_API AC07_Override : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class UBoxComponent* Box;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC07_Override();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);
UFUNCTION()
void OnEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
protected:
UFUNCTION(BlueprintNativeEvent) //가상화
void ChangeColorWhite();
void ChangeColorWhite_Implementation(); //재정의하겠다. 언리얼C++에서 재정의를 할 때는 _Implementation을 붙인다.
UFUNCTION(BlueprintImplementableEvent) //추상화. 상속받은 이후 재정의가 가능하다.
void ChangeColorRed();
};
C07_Override.cpp
#include "03_Collision/C07_Override.h"
#include "Global.h"
#include "CPlayer.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"
AC07_Override::AC07_Override()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Root);
CreateTextRender();
Box->SetRelativeScale3D(FVector(3));
Box->bHiddenInGame = false;
}
void AC07_Override::BeginPlay()
{
Super::BeginPlay();
Box->OnComponentBeginOverlap.AddDynamic(this, &AC07_Override::OnBeginOverlap);
Box->OnComponentEndOverlap.AddDynamic(this, &AC07_Override::OnEndOverlap);
}
void AC07_Override::OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
{
ChangeColorRed();
}
void AC07_Override::OnEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
ChangeColorWhite();
}
void AC07_Override::ChangeColorWhite_Implementation()
{
ACPlayer* player = Cast<ACPlayer>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
CheckNull(player);
player->ChangeColor(FLinearColor::White);
}
BP_C07_Override
블루프린트에서 색을 수정하는 경우이다.
- C07_Override.h .cpp에서 만든 Change Color Red, Change Color White를 불러온다.
- Change Color로 각각 빨간색, 마젠타색을 지정해서 넣어준다.
- Change Color Red, Change Color White 코드 안에서 색을 정의했지만 Change Color로 재정의 할 수 있다.
CPlayer - Material 추가
CPlayer.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "CPlayer.generated.h"
UCLASS()
class U2212_03_API ACPlayer : public ACharacter
{
GENERATED_BODY()
private:
UPROPERTY(VisibleAnywhere)
class USpringArmComponent* SpringArm;
UPROPERTY(VisibleAnywhere)
class UCameraComponent* Camera;
public:
ACPlayer();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
private:
void OnMoveForward(float InAxisValue);
void OnMoveRight(float InAxisValue);
void OnHorizontalLook(float InAxisValue);
void OnVerticalLook(float InAxisValue);
private:
void OnRun();
void OffRun();
public:
UFUNCTION(BlueprintCallable, Category = "Color")//직렬화
void ChangeColor(FLinearColor InColor);//BP에서 접근 가능한 함수가 된다.
private:
TArray<class UMaterialInstanceDynamic*> Materials;
};
CPlayer.cpp
#include "CPlayer.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "Materials/MaterialInstanceDynamic.h"
ACPlayer::ACPlayer()
{
PrimaryActorTick.bCanEverTick = true;
CHelpers::CreateComponent<USpringArmComponent>(this, &SpringArm, "SpringArm", GetCapsuleComponent());
CHelpers::CreateComponent<UCameraComponent>(this, &Camera, "Camera", SpringArm);
USkeletalMesh* mesh;
CHelpers::GetAsset<USkeletalMesh>(&mesh, "SkeletalMesh'/Game/Character/Mesh/SK_Mannequin.SK_Mannequin'");
GetMesh()->SetSkeletalMesh(mesh);
GetMesh()->SetRelativeLocation(FVector(0, 0, -90));
GetMesh()->SetRelativeRotation(FRotator(0, -90, 0));
TSubclassOf<UCAnimInstance> animInstance;
CHelpers::GetClass<UCAnimInstance>(&animInstance, "AnimBlueprint'/Game/ABP_Character.ABP_Character_C'");
GetMesh()->SetAnimClass(animInstance);
bUseControllerRotationYaw = false;
GetCharacterMovement()->bOrientRotationToMovement = true;
GetCharacterMovement()->MaxWalkSpeed = 400;
SpringArm->SetRelativeLocation(FVector(0, 0, 60));
SpringArm->TargetArmLength = 200;
SpringArm->bUsePawnControlRotation = true;
SpringArm->bEnableCameraLag = true;
}
void ACPlayer::BeginPlay()
{
Super::BeginPlay(); //Super가 BP의 BeginPlay를 콜한다.
TArray<UMaterialInterface*> materials = GetMesh()->GetMaterials(); //UMaterialInterface는 Material의 최상위
for (int32 i = 0; i < materials.Num(); i++)
{
//InstanceDynamic으로 할당 후 넣어준다.
UMaterialInstanceDynamic* temp = UMaterialInstanceDynamic::Create(materials[i], this);
GetMesh()->SetMaterial(i, temp);
Materials.Add(temp);
}
ChangeColor(FLinearColor::Black);
}
void ACPlayer::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis("MoveForward", this, &ACPlayer::OnMoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ACPlayer::OnMoveRight);
PlayerInputComponent->BindAxis("HorizontalLook", this, &ACPlayer::OnHorizontalLook);
PlayerInputComponent->BindAxis("VerticalLook", this, &ACPlayer::OnVerticalLook);
PlayerInputComponent->BindAction("Run", EInputEvent::IE_Pressed, this, &ACPlayer::OnRun);
PlayerInputComponent->BindAction("Run", EInputEvent::IE_Released, this, &ACPlayer::OffRun);
}
void ACPlayer::OnMoveForward(float InAxisValue)
{
FRotator rotator = FRotator(0, GetControlRotation().Yaw, 0);
FVector direction = FQuat(rotator).GetForwardVector();
AddMovementInput(direction, InAxisValue);
}
void ACPlayer::OnMoveRight(float InAxisValue)
{
FRotator rotator = FRotator(0, GetControlRotation().Yaw, 0);
FVector direction = FQuat(rotator).GetRightVector();
AddMovementInput(direction, InAxisValue);
}
void ACPlayer::OnHorizontalLook(float InAxisValue)
{
AddControllerYawInput(InAxisValue);
}
void ACPlayer::OnVerticalLook(float InAxisValue)
{
AddControllerPitchInput(InAxisValue);
}
void ACPlayer::OnRun()
{
GetCharacterMovement()->MaxWalkSpeed = 600;
}
void ACPlayer::OffRun()
{
GetCharacterMovement()->MaxWalkSpeed = 400;
}
void ACPlayer::ChangeColor(FLinearColor InColor)
{
for (UMaterialInstanceDynamic* material : Materials)
material->SetVectorParameterValue("BodyColor", InColor);
}
BP_CPlayer
실행화면
언리얼엔진의 Blueprint와 Unreal C++ 호출순서 - 중요!
※ 언리얼엔진은 Blueprint를 먼저 읽은 후에 Unreal C++를 읽는다! 그래서 부모를 나중에 세팅해야 한다.
아래의 예시코드는 Player 매쉬의 색을 바꾸는 CPlayer.cpp 코드 중 일부를 사용하였다.
원본 코드
void ACPlayer::BeginPlay()
{
TArray<UMaterialInterface*> materials = GetMesh()->GetMaterials(); //UMaterialInterface는 Material의 최상위
for (int32 i = 0; i < materials.Num(); i++)
{
UMaterialInstanceDynamic* temp = UMaterialInstanceDynamic::Create(materials[i], this);
GetMesh()->SetMaterial(i, temp);
Materials.Add(temp);
}
Super::BeginPlay(); //Super가 BP의 BeginPlay를 콜한다.
}
- C++ 코드를 적용한 후에 Super::BeginPlay()로 Blueprint의 BeginPlay를 실행시킨다.
- 위의 경우에는 Unreal C++ → BP 순으로 실행한다.
오류 코드 - Super::BeginPlay()가 위로 올라온 경우
void ACPlayer::BeginPlay()
{
Super::BeginPlay(); //Super가 BP의 BeginPlay를 콜한다.
TArray<UMaterialInterface*> materials = GetMesh()->GetMaterials(); //UMaterialInterface는 Material의 최상위
for (int32 i = 0; i < materials.Num(); i++)
{
UMaterialInstanceDynamic* temp = UMaterialInstanceDynamic::Create(materials[i], this);
GetMesh()->SetMaterial(i, temp);
Materials.Add(temp);
}
}
- Super::BeginPlay()를 아래의 코드보다 먼저 실행시켰다.
- 위의 경우에는 BP → Unreal C++ 순서로 실행된다.
- 이 경우 mesh에 material을 할당하는 아래의 코드가 적용되지 않은 상태에서 Blueprint가 실행된다.
- Blueprint에서 ChangeColor를 실행할 때 정보를 찾지 못해 색이 바뀌지 않는다.
수정 코드 - ChangeColor 코드를 뒤에 추가한 경우
void ACPlayer::BeginPlay()
{
Super::BeginPlay(); //Super가 BP의 BeginPlay를 콜한다.
TArray<UMaterialInterface*> materials = GetMesh()->GetMaterials(); //UMaterialInterface는 Material의 최상위
for (int32 i = 0; i < materials.Num(); i++)
{
UMaterialInstanceDynamic* temp = UMaterialInstanceDynamic::Create(materials[i], this);
GetMesh()->SetMaterial(i, temp);
Materials.Add(temp);
}
ChangeColor(FLinearColor::Black);
}
- 위의 경우에는 BP → Unreal C++ → ChangeColor
- 맨 뒤에 ChangeColor를 넣어 순서 문제가 생기는 것을 방지할 수 있는 코드이다.
- ChangeColor로 색을 지정해준다.
Narrative vs. Implementation
Native Event = 가상화. Unreal C++에서 정의할테니 원하면 가져다가 써라.
Implementation = 추상화. 함수 호출 해줄테니 필요하면 재정의해서 써라.
Trace
큐브 배치하기
큐브 배치
- Simulate Physics 체크하기
- MassInKg = 매스의 무게
- 큐브 마다 매스의 무게를 조금씩 다르게 설정하였다.
C01_Trigger
C01_Trigger.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C01_Trigger.generated.h"
UCLASS()
class U2212_03_API AC01_Trigger : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class UBoxComponent* Box;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC01_Trigger();
protected:
virtual void BeginPlay() override;
};
C01_Trigger.cpp
#include "04_Trace/C01_Trigger.h"
#include "Global.h"
#include "C01_SphereTrace.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"
AC01_Trigger::AC01_Trigger()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Root);
CreateTextRender();
Box->SetRelativeScale3D(FVector(3));
Box->bHiddenInGame = false;
}
void AC01_Trigger::BeginPlay()
{
Super::BeginPlay();
AC01_SphereTrace* trace = CHelpers::FindActor<AC01_SphereTrace>(GetWorld());
CheckNull(trace);
OnActorBeginOverlap.AddDynamic(trace, &AC01_SphereTrace::BeginOverlap);
}
C01_SphereTrace
C01_SphereTrace.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Kismet/KismetSystemLibrary.h"
#include "C01_SphereTrace.generated.h"
UCLASS()
class U2212_03_API AC01_SphereTrace : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, Category = "Settings")
TEnumAsByte<EDrawDebugTrace::Type> DrawDebug; //TEnumAsByte는 직렬화
UPROPERTY(EditAnywhere, Category = "Settings")
float DrawTime = 5;;
UPROPERTY(EditAnywhere, Category = "Settings")
float MaxMass = 300;
UPROPERTY(EditAnywhere, Category = "Settings")
float ImpulseAmount = 500;
private:
UPROPERTY(VisibleAnywhere)
class UParticleSystemComponent* Particle;
public:
AC01_SphereTrace();
protected:
virtual void BeginPlay() override;
public:
UFUNCTION()
void BeginOverlap(AActor* OverlappedActor, AActor* OtherActor);
};
C01_SphereTrace.cpp
#include "04_Trace/C01_SphereTrace.h"
#include "Global.h"
#include "Particles/ParticleSystemComponent.h"
AC01_SphereTrace::AC01_SphereTrace()
{
CHelpers::CreateComponent<UParticleSystemComponent>(this, &Particle, "Particle");
UParticleSystem* particle;
CHelpers::GetAsset<UParticleSystem>(&particle, "ParticleSystem'/Game/AdvancedMagicFX12/particles/P_ky_hit_thunder.P_ky_hit_thunder'");
Particle->SetTemplate(particle);
Particle->bAutoActivate = false;
Particle->SetRelativeScale3D(FVector(3));
}
void AC01_SphereTrace::BeginPlay()
{
Super::BeginPlay();
}
void AC01_SphereTrace::BeginOverlap(AActor* OverlappedActor, AActor* OtherActor)
{
FVector location = GetActorLocation();
//오브젝트 콜리션 종류들
TArray<TEnumAsByte<EObjectTypeQuery>> types; //TEnumAsByte는 Enum의 사이즈를 알려주는 템플릿이다.
types.Add(EObjectTypeQuery::ObjectTypeQuery4); //4는 PhysicsBody
TArray<AActor*> ignores;
TArray<FHitResult> hitResults; //배열로 들어간다.
//여기 마지막 변수 체크
bool b = UKismetSystemLibrary::SphereTraceMultiForObjects(GetWorld(), location, location, 300, types, false, ignores, DrawDebug, hitResults, true, FLinearColor::Red, FLinearColor::Green, DrawTime);
CheckFalse(b); // b가 true라면 하나라도 충돌된게 있는 것이다.
Particle->ResetParticles(); //Particle 플레이가 끝나면 마지막 장면에 멈춰있기 때문에 포인터가 앞으로 오도록 리셋해준다.
Particle->SetActive(true); //Particle 플레이 해준다.
for(const FHitResult& hitResult : hitResults) //const로 변경방지, &로 복사방지
{
UStaticMeshComponent* mesh = Cast<UStaticMeshComponent>(hitResult.GetActor()->GetRootComponent());
if (!!mesh && mesh->IsSimulatingPhysics())
// RadialImpulse는 구형으면 Impulse, 무거운게 덜 날라가도록 strength항목에 MaxMass - mesh->GetMass() * ImpulseAmount //RIF_Linear 거리에 따라 선형으로 힘이 줄어들음.
mesh->AddRadialImpulse(location, 1000, (MaxMass - mesh->GetMass()) * ImpulseAmount, ERadialImpulseFalloff::RIF_Linear);
}
}
TEnumAsByte는 Enum의 사이즈를 알려주는 템플릿이다.
Enum을 과거에 사용하던 방식으로 계속 사용하는 경우도 있다. Legacy Type에는 사이즈가 없기 때문에 이 방식으로 사용하려면 TEnumAsByte를 사용하여 사이즈를 알려줘야 한다.
UObject* WorldContextObject = 월드를 넣어준다.
실행화면
Trace
원기둥 배치하기
C02_Cylinder
C02_Cylinder.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C02_Cylinder.generated.h"
UCLASS()
class U2212_03_API AC02_Cylinder : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class UStaticMeshComponent* Mesh;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC02_Cylinder();
protected:
virtual void BeginPlay() override;
};
C02_Cylinder.cpp
#include "04_Trace/C02_Cylinder.h"
#include "Global.h"
#include "Components/StaticMeshComponent.h"
#include "Components/TextRenderComponent.h"
AC02_Cylinder::AC02_Cylinder()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UStaticMeshComponent>(this, &Mesh, "Mesh", Root);
CreateTextRender();
Text->SetRelativeLocation(FVector(0, 0, 150));
UStaticMesh* mesh;
CHelpers::GetAsset<UStaticMesh>(&mesh, "StaticMesh'/Game/Meshes/Cylinder.Cylinder'");
Mesh->SetStaticMesh(mesh);
Mesh->SetRelativeScale3D(FVector(1, 1, 2.5f));
}
void AC02_Cylinder::BeginPlay()
{
Super::BeginPlay();
}
C02_LineTrace
02_LineTrace.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C02_LineTrace.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FLineTraceResult, class AActor*, InActor, FLinearColor, InColor);
UCLASS()
class U2212_03_API AC02_LineTrace : public AActor
{
GENERATED_BODY()
public:
AC02_LineTrace();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
private:
UFUNCTION()
void StartLaunch(class AActor* InActor, FLinearColor InColor);//Dynamic은 매개변수 이름이 똑같아야 한다.
public:
FLineTraceResult OnLineTraceResult;
private:
TArray<class AC02_Cylinder*> Cylinders;
};
02_LineTrace.cpp
#include "04_Trace/C02_LineTrace.h"
#include "Global.h"
#include "C02_Cylinder.h"
#include "GameFramework/Character.h" //실제적으로 실행시켜주는 역할
AC02_LineTrace::AC02_LineTrace()
{
PrimaryActorTick.bCanEverTick = true;
}
void AC02_LineTrace::BeginPlay()
{
Super::BeginPlay();
CHelpers::FindActors<AC02_Cylinder>(GetWorld(), Cylinders);
//Delegate 사용
OnLineTraceResult.AddDynamic(this, &AC02_LineTrace::StartLaunch);
}
void AC02_LineTrace::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
FVector start = Cylinders[0]->GetActorLocation();
FVector end = Cylinders[1]->GetActorLocation();
//DrawDebugLIne
{
start.Z -= 20;
end.Z -= 20;
DrawDebugLine(GetWorld(), start, end, FColor::Blue);
}
}
void AC02_LineTrace::StartLaunch(AActor* InActor, FLinearColor InColor)
{
}
실행화면
'⭐ Unreal Engine > UE FPS TPS' 카테고리의 다른 글
[UE] TPS Weapon - Weapon Framework 짜기 (0) | 2023.03.16 |
---|---|
[UE] Line Trace, Multi Trace, TPS 기본 세팅 (0) | 2023.03.15 |
[UE] Collsion(trigger, MultiTrigger, Explosion) (0) | 2023.03.13 |
[UE] Collision(Overlap, hit) (0) | 2023.03.09 |
[UE] Character Animation, Collsion (0) | 2023.03.08 |
댓글
이 글 공유하기
다른 글
-
[UE] TPS Weapon - Weapon Framework 짜기
[UE] TPS Weapon - Weapon Framework 짜기
2023.03.16 -
[UE] Line Trace, Multi Trace, TPS 기본 세팅
[UE] Line Trace, Multi Trace, TPS 기본 세팅
2023.03.15 -
[UE] Collsion(trigger, MultiTrigger, Explosion)
[UE] Collsion(trigger, MultiTrigger, Explosion)
2023.03.13 -
[UE] Collision(Overlap, hit)
[UE] Collision(Overlap, hit)
2023.03.09