이제까지 충돌할려는 것에서 트리거를 찾아서 등록을 했었는데. 이런 방식도 있다 라고 생각하면 될거 같다. 실제로 현업에서 사용하는 방법은 아니다. (비효율적)
새 클래스 생성 / 폴더 생성.
C01_SphereTrace
DebugDraw 블프에서 사용하였을 때 None Foward, Duration 사용하는 것들이 있다. 이게 Enum형으로 되어있다. EDrawDebugTrace 라고 정의된다. 일반적으로 Enum 선언 방식이 2가지가 있다.
Unreal에서 이런식으로 공개된 결과형 Type이다.
//현재 방식
UENUM(BlueprintType)
enum class EDraw : uint8
{
};
만약에 이런식으로 정의하면. A는 프로그램 전역에서 Enum이 되버린다. 이걸 구역으로 묶는 방법이 있는데.
enum EDraw
{
A = 0, B,
};
구역으로 묶는 법 (옛날 방식) - using namespace 는 자주 쓰인다.
//옛날 방식
using namespace EDraw
{
enum Type
{
A = 0, B,
};
}
/////////////////
//다른 곳에서 EDraw::A 이런식으로 쓴다.
하필 옛날방식처럼 정의 되어 있는 것들이 있다. EDrawDebugTrace 들어가서 보면 언리얼 에서 Enum은 사이즈를 uint8 로 규정해줘야 한다.
그래서 EDrawDebugTrace의 사이즈가 정의가 없는데. 이걸 블루프린트에 강제적으로 주는 방법이
TEnumAsByte (템플릿) : 블프에 공개하려고 사이즈를 강제적으로 주는 방법. 이Enum은 byte를 사용하겠다고 명시해 주는 것
private:
UPROPERTY(EditAnywhere)
TEnumAsByte<EDrawDebugTrace::Type> DebugType; // Enum형 Byte강제
UPROPERTY(EditAnywhere)
float DrawDuration = 5; // 얼마 동안 돌릴 것인가.
UPROPERTY(EditAnywhere)
float ImpulseAmount = 550; //힘을 받는 범위
언리얼에서 힙을 얘기 할 떄 (다른 곳에서도) Force.Impulse라고 있다.
force : 서로 부딪혔을 때 밀어내는 힘 주는 쪽이 Force, 충격을 받는 쪽이 Pulse ,
이 때 주의 할 점이, 주는 쪽이 force이고 날라가는것이 Impulse 인데 서버에서 구분 할때 주체가 달라지는데 , 힘을 받아서 날라가야하는데, 힘을 줘서 날라가니까. 다시 다른 쪽에 힘(force)을 주면, 가속이 일어난다, .또 만약에 서로 같은 force라면 상쇄가 일어난다. 그래서 force랑 Impulse를 항상 구분해서 사용해야 한다.
C01_SphereTrace.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Kismet/KismetSystemLibrary.h" //EDrawDebug 있는 곳
#include "C01_SphereTrace.generated.h"
UCLASS()
class U2110_03_API AC01_SphereTrace : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere)
TEnumAsByte<EDrawDebugTrace::Type> DebugType; // Enum형 Byte강제
UPROPERTY(EditAnywhere)
float DrawDuration = 5; // 얼마 동안 돌릴 것인가.
UPROPERTY(EditAnywhere)
float ImpulseAmount = 550;
private:
UPROPERTY(VisibleDefaultsOnly)
class UParticleSystemComponent* Particle;
public:
AC01_SphereTrace();
protected:
virtual void BeginPlay() override;
public:
UFUNCTION()
void OnActorBeginOverlap(AActor* OverlappedActor, AActor* OtherActor);
};
현재 로써는 충돌체가 없다. 그래서 Trigger를 하나 만들어 줄 것
C01_SphereTrace.cpp
#include "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/M5VFXVOL2/Particles/Explosion/Fire_Exp_00.Fire_Exp_00'");//particle 경로
Particle->SetTemplate(particle); //파티클 지정해주는 것
Particle->bAutoActivate = false; //AitoActivate 자동실행 꺼주기 (그냥 바로 폭발 하고 끝나는 거 막기 위함)
}
void AC01_SphereTrace::BeginPlay()
{
Super::BeginPlay();
}
void AC01_SphereTrace::OnActorBeginOverlap(AActor* OverlappedActor, AActor* OtherActor)
{
}
실행 셋팅 Simulate Physics
크기에 따라 질량이 달라진다.
어디 구역 들어갔을 때 호출
C01_Trigger 클래스 생성
C01_Trigger.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C01_Trigger.generated.h"
UCLASS()
class U2110_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 "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);
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Root);
//충돌체
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().Replace(L"Default__", L""));
}
void AC01_Trigger::BeginPlay()
{
Super::BeginPlay();
//배치 되어있는 거 찾아오기
AC01_SphereTrace* trace = CHelpers::FindActor<AC01_SphereTrace>(GetWorld());
CheckNull(trace);
OnActorBeginOverlap.AddDynamic(trace, &AC01_SphereTrace::OnActorBeginOverlap);
}
Box에 연결해둔 AC01_SphereTrace의 모양을 보면 OnActorBeginOverlap 해서 2개를 주었다. (OverlappedActor, OtherActor) 이게 결국 ActorOverlap과 같다.
void OnActorBeginOverlap(AActor* OverlappedActor, AActor* OtherActor);
OnActorBeginOverlap 에 들어가서 보면 앞에 3개 제외하고 뒤에 보면 똑같은 걸 볼 수 있다.
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams( FActorBeginOverlapSignature, AActor, OnActorBeginOverlap, **AActor*, OverlappedActor, AActor*, OtherActor** );
이 말은 (AActor* OverlappedActor, AActor* OtherActor) 그냥 직접 Trace에 있는거 연결해도 된다는 것 , Trace객체 안에 있는. AC01_SphereTrace에 OnActorBeginOverlap 을 이방법은 자신의 델리게이트에 다른 것을 가져다 연결해준다. (관리 해주는데 있어. 좀..;;)
OnActorBeginOverlap.AddDynamic(trace, &AC01_SphereTrace::OnActorBeignOverlap);
액터 끼리 겹치면 OnActorBeginOverlap 이 발생한다.
Box->SetRelativeScale3D(FVector(3));
Box->bHiddenInGame = false;
C01_SphereTrace.cpp
#include "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/M5VFXVOL2/Particles/Explosion/Fire_Exp_00.Fire_Exp_00'");//particle 경로
Particle->SetTemplate(particle); //파티클 지정해주는 것
Particle->bAutoActivate = false; //AitoActivate 자동실행 꺼주기 (그냥 바로 폭발 하고 끝나는 거 막기 위함)
}
void AC01_SphereTrace::BeginPlay()
{
Super::BeginPlay();
}
void AC01_SphereTrace::OnActorBeginOverlap(AActor* OverlappedActor, AActor* OtherActor)
{
//위치
FVector location = GetActorLocation();
TArray<TEnumAsByte<EObjectTypeQuery>> types;
types.Add(EObjectTypeQuery::ObjectTypeQuery4);
TArray<AActor *> ignores;
TArray<FHitResult> hitResults; //Hit결과를 배열로 넘겨오기
//하나라도 충돌 했다면, b가 True가 나올 것이다.
bool b = UKismetSystemLibrary::SphereTraceMultiForObjects(GetWorld(), location, location, 300, types, false, ignores, DebugType, hitResults, true, FLinearColor::Green, FLinearColor::Blue, DrawDuration);
CheckFalse(b);
//Particle Component ?
Particle->ResetParticles();
Particle->SetActive(true);
for (const FHitResult& hitResult : hitResults)
{
UStaticMeshComponent* mesh = Cast<UStaticMeshComponent> (hitResult.GetActor()->GetRootComponent());
if (!!mesh && mesh->IsSimulatingPhysics())
mesh->AddRadialImpulse(location, 1000, mesh->GetMass() * ImpulseAmount, ERadialImpulseFalloff::RIF_Linear);
}
}
UKismetSystemLibrary
KismetSystemLibrary에 Trace 붙은 것이 있다. LightTrace, BoxTrace, SphereTrace등등 이런 것들이 World에 있는 것을 호출한다.
UKismetSystemLibrary::SphereTraceMultiForObjects
//이곳에 디버깅이나. 편의기능을 좀 더 준 것이다.
location, location : 위치 달라지면 거기 까지 이어가는 것
1~ 잔뜩 뭔가 있다.
프로젝트 셋팅 → 콜리전 에서 보면 이미 1~7번까지 정해져 있는 것이다. 지금 현재는 PhysicsBody를 사용 할 것
Particle은 실제 System컴포넌트 , 이걸 가지고 반복플레이를 할 것이다. 한번 플레이가 됬다면, Reset을 해줘야한다.
//Particle Component ?
Particle->ResetParticles();
Particle->SetActive(true);
만약
for (FHitResult hitResult : hitResults)
{
}
//이런식으로 하면, hitResult를 가져와서 계속 복사 생성한다. 그래서 강제로 레퍼런스를 붙인다.
//hitResult값을 원본을 건드리는 것이 아니라. 가져다만 쓰는 거기 때문에,
//실제 실무에서 이렇게 쓰인다.
for (**const** FHitResult& hitResult : hitResults)
{
}
Impulse종류가 여러가지
설명
for (const FHitResult& hitResult : hitResults)
{
UStaticMeshComponent* mesh = Cast<UStaticMeshComponent> (hitResult.GetActor()->GetRootComponent());
if (!!mesh && mesh->IsSimulatingPhysics())
mesh->AddRadialImpulse(어디서 부터 나갈건지(우리위치), 얼마만큼 반격으로 날릴지, 힘이 얼마나 적용될지 질량 * ImpulseAmount, );
}
각각 다른
RIF_Constant : 거리가 멀든 아니든 , 일정한 힘,
RIF_Linear : 선형으로 갈수록 힘이 줄어듬
실행 : Trigger 로 가게 되면 폭발하게 된다.
만약 박스 모양을 더 작게 하면 멀리나갈까 작게 나갈까?
1000, mesh->GetMass() * ImpulseAmount 질량이 작으면 ImpulseAmount의 값이 작아진다. 그래서 원래는 절대질량을 뒤집어 줘야한다.