필요한 개념
<Targeting>
타켓팅 작업은 플레이어든 적이든 어느 캐릭터에도 붙여서 사용할 수 있도록 ActorComponent로 제작함
이 안에 타겟팅 변수가 있다면 수행하고 아니라면 타켓팅을 수행하지 않는 컴포넌트
C에서는 Interpolation(보간)을 사용하여 부드럽게 처리함
* CTargetComponent 생성
SphereTraceMultiByProfile()로 일정 반경(TraceRadius)안에 있는 객체들을 찾아옴
// UCTargetComponent.h
private:
// 컴포넌트에서 공개는 EditAnywhere가 좋다.
// 추적할 반경
UPROPERTY(EditAnywhere)
float TraceRadius = 1000.0f;
// Trace Draw Debug 지속할 건지
// Type이 enum이어서 크기를 알 수 없음
// 그래서 TEnumAsByte로 크기를 알려줌
UPROPERTY(EditAnywhere)
TEnumAsByte<EDrawDebugTrace::Type> Debug;
// 추적할 수 있는 타켓 목록
TArray<class ACharacter*> TraceTargets
// UCTargetComponent.cpp
void UCTargetComponent::SetTraceTargets()
{
FVector start = OwnerCharacter->GetActorLocation();
// Sphere Multi 사용할 건데, 이건 위치가 같으면 안나옴(그래서 위치만 살짝 높임)
FVector end = FVector(start.X, start.Y, start.Z + 1);
TArray<AActor*> ignoreActors;
ignoreActors.Add(OwnerCharacter);
// SphereTraceMulti를 사용할 거라 여러개의 충돌결과가 나옴
TArray<FHitResult> hitResults;
// Profile : 프리셋의 이름으로 딱 한종류만 추적하기 위해 사용(프로젝트 설정 -> 콜리전 -> 프리셋)
// 2 : 시작 위치 3 : 끝 위치 4 : 반경 5 : 어떤 거를 찾아올건지 6 : 복합 충돌 할건지 7 : 충돌 무시 액터 8 : 디버그 지정, 9 : 반환받을 충돌결과(TArray<HitResult>) 10 : 자가자신 제외할 건지 11 : 디버그 컬러 12 : 충돌된 애들 디버그 컬러 13 : 시간
UKismetSystemLibrary::SphereTraceMultiByProfile(GetWorld(), start, end, TraceRadius, "Pawn", false, ignoreActors, Debug, hitResults, true, FLinearColor::Green, FLinearColor::Red, 1.0f);
// 반경안에 추적할 객체들
for (const FHitResult& result : hitResults)
{
if (result.GetActor()->GetClass() == OwnerCharacter->GetClass())
continue;
ACharacter* character = Cast<ACharacter>(result.GetActor());
// casting 되었다면 AddUnique()로 중복 안되게 넣어줌
if (!!character)
TraceTargets.AddUnique(character);
}
}
타켓팅 : 컨트롤러에 제일 가까운 적을 선택(우리는 카메라 방향으로 세팅(캐릭터 방향 x))
* 프로젝트 세팅 -> 입력 -> 액션 매핑에 Target 입력키 세팅
* CPlayer에 TargetComponent 맴버로 추가 & 액션 매핑 세팅
PlayerInputComponent->BindAction("Target", EInputEvent::IE_Pressed, this, &ACPlayer::OnTarget);
- 적을 여러개 월드에 배치했다면, 그 중 하나를 타켓팅하는 것이다.
* 이전에는 적만을 타켓팅해서 카메라 컨트롤러를 사용했지만, 이번에는 플레이어나 적 모두 타켓팅으로 사용할 수 있으므로 캐릭터가 가지고 있는 컨트롤러의 회전을 이용할 것임
이전에는 선정할때 카메라의 정면에서 가장 가까운 애를 선택했다. 이제는 플레이어, Enemy도 가질 수 있어서 내용은 같지만 약간 다름
OwnerCharacter의 Controller를 사용해서 정면에 있는것을 찾는다.
void UCTargetComponent::SetTarget()
{
float angle = -2.0f;
ACharacter* target = NULL;
for (ACharacter* character : TraceTargets)
{
// 플레이어는 플레이어 컨트롤러여서, 플레이어 컨트롤러는 카메라랑 관련있어서
// 카메라의 방향이 나옴
// 적이면 AIController에 의해서 회전해서, 즉 적의 회전 방향이 나온다.
// 전방방향을 가지고 옴
// UseControlRotationYaw을 켜 놓으면 어차피 전방이라 액터의 방향을 설정해도 되지만
// 끌 수도 있다. 적도 마찬가지로 타켓을 잡아서 플레이어를 바라볼 수 도 있지만, 아닐 수도 있음
// 즉 -> GetContolRotation()을 추가 한 이유는 캐릭터의 전방방향이 아닌
// 컨트롤러의 전방 방향을 사용한다.
FVector direction = FQuat(OwnerCharacter->GetControlRotation()).GetForwardVector();
FVector offset = character->GetActorLocation() - OwnerCharacter->GetActorLocation();
// direction은 GetFowardVector()는 어차피 Normallize()된 백터로 리턴하니깐
offset = offset.GetSafeNormal();
// return X*V.X + Y*V.Y + Z*V.Z;
// 내적은 각 요소의 x,y,z를 곱하고 더함
// 언리얼에서는 | operator를 제공(FVector::DotProduct()와 동일)
float temp = direction | offset;
// angle보다 작다면 안함
if (temp < angle)
continue;
// 크다면 세팅
// 내적의 값이 가장 큰것이 바라보는 방향과 제일 일치하다는 얘기
angle = temp;
target = character;
// 전방백터를 이용해서 전방백터에 가장가까운 애를 찾음
/*
float AActor::GetDotProductTo(const AActor* OtherActor) const
{
if (OtherActor)
{
FVector Dir = GetActorForwardVector(); // 전방 백터 가져오고
FVector Offset = OtherActor->GetActorLocation() - GetActorLocation(); // 플레이어가 OtherActor을 쳐다보는 방향이 만들어짐
Offset = Offset.GetSafeNormal(); // 단위 백터가 됨
return FVector::DotProduct(Dir, Offset); // 두 값을 내적함(
}
return -2.0;
}
*/
//AActor::GetDotProductTo()
// 즉 -> DotProduceTo()에서 GetControlRoation() 부분만 추가됨
}
}
결과를 보면 카메라의 정면에 가까운 애들이 선택된다.(일치한다면 내적 값이 가장 크다, But 두 벡터가 이루는 각이 90도라면, 일치하는 정도가 없기 때문에, 0이 나옴)
해골 마크 이펙트를 추가해서 이 이펙트가 추가된 애가 Target으로 잡힌 액터이다.
<Target으로 잡힌 액터에 해골 마크 추가>
* Skel_Mannequin에 spine_03에 Spine_Target 소켓 추가
// 타켓에 해골모양 파티클 붙이기 위한
UPROPERTY(EditAnywhere)
class UParticleSystem* Particle;
// 타겟을 지정 + 거기에 커서를 붙임
void ChangeCursor(class ACharacter* InTarget);
Tip)
UGameplayStatics의 Spawn으로 시작되는 함수들은 실행하는 액터나 어태치되는 액터에 자동으로 컴포넌트를 생성해서 플레이하고, 플레이 종료가 일어나면 자동으로 삭제한다.
-> 하지만 무한 루프일 경우 필요할 때, 프로그래머가 제거할 수 있도록 자동으로 생성된 컴포넌트를 리턴해준다.
// Spawn되는 함수의 임시생성되는 컴포넌트를 저장(제거 안됨 방지)
class UParticleSystemComponent* Attached;
* 타겟 지정 + 거기에 커서를 붙임
SetTarget()에서 ChangeCursor() 함수를 호출해서 InTarget을 넘겨줌
void UCTargetComponent::ChangeCursor(class ACharacter* InTarget)
{
if (!!InTarget)
{
// 이미 컴포넌트가 존재한다면 제거해라
if (!!Attached)
Attached->DestroyComponent();
// 소켓에다 파티클을 붙임
Attached = UGameplayStatics::SpawnEmitterAttached(Particle, InTarget->GetMesh(), "Spine_Target");
// 타겟 지정
Target = InTarget;
return;
}
// Null이라면 EndTargeting으로 간다.
EndTargeting();
}
void UCTargetComponent::EndTargeting()
{
// EndTargeting에서는 초기화 해줌
Target = NULL;
TraceTargets.Empty();
if (!!Attached)
Attached->DestroyComponent();
}
<타겟을 잡고 Q(Left), E(Right)를 누르면 옆 타겟이 이동하는 작업>
void UCTargetComponent::ChangeTarget(bool InRight)
{
CheckNull(Target);
// 거리값이자 방향값 float
TMap<float, ACharacter*> map;
for (ACharacter* character : TraceTargets)
{
if (Target == character)
continue;
FVector targetLocation = character->GetActorLocation();
FVector ownerLocation = OwnerCharacter->GetActorLocation();
// owner가 target을 바라봐야 하니까
FVector ownerToTarget = targetLocation - ownerLocation;
// 카메라의 방향 값
FQuat quat = FQuat(OwnerCharacter->GetControlRotation());
// forwar, up 구해줌
FVector forward = quat.GetForwardVector();
FVector up = quat.GetUpVector();
/*
^은 외적 operator
Y * V.Z - Z * V.Y,
Z * V.X - X * V.Z,
X * V.Y - Y * V.X
*/
// 나오는 수직 백터의 값이 거리이자 방향이다.
FVector cross = forward ^ ownerToTarget;
// cross와 up을 내적해서 z값만 가지고 옴
float dot = cross | up;
map.Add(dot, character);
}
float min = FLT_MAX;
ACharacter* target = NULL;
TArray<float> keys;
map.GetKeys(keys);
for (float key : keys)
{
if (InRight == true)
{
// 키가 0보다 작거나 왼쪽 키값이다.
if (key < 0.0f)
continue;
}
// 이번에는 left니까 0보다 큰 애들을 잘라냄
else
{
if (key > 0.0f)
continue;
}
// 크다면 넘김(최소값을 구할거라)
if (FMath::Abs(key) > min)
continue;
// 가장 가까운 = 최소값의 target을 넣음
min = FMath::Abs(key);
target = *map.Find(key);
}
ChangeCursor(target);
}
*Player에 입력 이벤트 연결
PlayerInputComponent->BindAction("TargetLeft", EInputEvent::IE_Pressed, this, &ACPlayer::OnTargetLeft);
PlayerInputComponent->BindAction("TargetRight", EInputEvent::IE_Pressed, this, &ACPlayer::OnTargetRight);
void ACPlayer::OnTargetLeft()
{
Target->ChangeTargetLeft();
}
void ACPlayer::OnTargetRight()
{
Target->ChangeTargetRight();
}
* 버그 발생
Q, E를 누르면 왼쪽, 오른쪽으로 각각 가다가 왔다갔다하는 증상이 있다.
-> 카메라가 회전을 안해서 그럼
그래서 ControlRotation을 조금 돌려줄 것이다.
적도 AI에 의해서 회전 값을 포커스에 맞도록 이동해줄 것이다.
void UCTargetComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
CheckNull(Target);
// 즉, 바라보는 방향의 회전값으로 세팅되도록 만듬(left, right target 버그 해결)
FVector start = OwnerCharacter->GetActorLocation();
FVector target = Target->GetActorLocation();
// start에서 target을 바라보는 회전값이 만들어짐
FRotator rotator = UKismetMathLibrary::FindLookAtRotation(start, target);
// SetControlRotation()은 private이어서 Contoller를 통해 가져와야함
OwnerCharacter->GetController()->SetControlRotation(rotator);
}
* 부드럽게 회전할 값 만듬
UPROPERTY(EditAnywhere)
float interopSpeed = 2.5f;
1이하면 버그가 생김(값이 너무 크면 부드러워 지면, 카메라가 너무 천천히 이동하면 Targeting에 버그가 생김)
버그 해결하고 싶다면, 옮겨질려는 애한테 어느정도 회전값이 들어왔는지 판단한 다음, 하면 됨
FRotator current = OwnerCharacter->GetControlRotation();
// RInterpTo(Rotation Interpolation To) : 시작 방향에서 종료 방향까지 시간에 비례한 속도로 자연스럽게 보간해주는 함수
rotator = UKismetMathLibrary::RInterpTo(current, rotator, DeltaTime, interopSpeed);
* 버그가 생김 : 너무 빠르게 누를시, Target이 사라짐
회전 속도를 올려주거나, 회전이 완료되지 않았다면 키 입력을 무시
*Tip) BP의 컴포넌트 디테일이 안뜨는 경우가 있음
-> BP 우클릭 -> 애셋액션 -> 리로드 하거나
-> 새로 BP를 생성하면 됨
CTargetComponent.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Kismet/KismetSystemLibrary.h"
#include "CTargetComponent.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class UONLINE_04_ACTION_API UCTargetComponent : public UActorComponent
{
GENERATED_BODY()
private:
// 컴포넌트에서 공개는 EditAnywhere가 좋다.
// 추적할 반경
UPROPERTY(EditAnywhere)
float TraceRadius = 1000.0f;
UPROPERTY(EditAnywhere)
float interopSpeed = 2.5f;
// Trace Draw Debug 지속할 건지
// Type이 enum이어서 크기를 알 수 없음
// 그래서 TEnumAsByte로 크기를 알려줌
UPROPERTY(EditAnywhere)
TEnumAsByte<EDrawDebugTrace::Type> Debug;
// 타켓에 해골모양 파티클 붙이기 위한
UPROPERTY(EditAnywhere)
class UParticleSystem* Particle;
public:
UCTargetComponent();
protected:
virtual void BeginPlay() override;
public:
// 한번 누르면 타켓팅, 누르지 않으면 타켓팅이 풀림
void ToggleTarget();
void ChangeTargetLeft();
void ChangeTargetRight();
private:
void StartTargeting();
void EndTargeting();
// 일정반경안에 있는지 보고 타켓을 잡을 수 있는 객체들을 찾아옴(BP와 똑같음)
void SetTraceTargets();
// 목록 중에 하나의 타겟을 정함
void SetTarget();
// 왼, 오른쪽 타겟으로 이동하기 위한 작업
void ChangeTarget(bool InRight);
// 타겟을 지정 + 거기에 커서를 붙임
void ChangeCursor(class ACharacter* InTarget);
public:
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private:
// Player든, 적이든 타켓팅컴포넌트를 사용 가능하도록
class ACharacter* OwnerCharacter;
// 타켓팅될 캐릭터
class ACharacter* Target;
// Spawn되는 함수의 임시생성되는 컴포넌트를 저장(제거 안됨 방지)
class UParticleSystemComponent* Attached;
// 추적할 수 있는 타켓 목록
TArray<class ACharacter*> TraceTargets;
};
CTargetComponent.cpp
#include "CTargetComponent.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Particles/ParticleSystem.h"
#include "Particles/ParticleSystemComponent.h"
UCTargetComponent::UCTargetComponent()
{
PrimaryComponentTick.bCanEverTick = true;
// 기본 값 설정
CHelpers::GetAsset<UParticleSystem>(&Particle, "ParticleSystem'/Game/Effects/P_Enrage_Base.P_Enrage_Base'");
}
void UCTargetComponent::BeginPlay()
{
Super::BeginPlay();
OwnerCharacter = Cast<ACharacter>(GetOwner());
}
void UCTargetComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
CheckNull(Target);
// 즉, 바라보는 방향의 회전값으로 세팅되도록 만듬(left, right target 버그 해결)
FVector start = OwnerCharacter->GetActorLocation();
FVector target = Target->GetActorLocation();
// start에서 target을 바라보는 회전값이 만들어짐
FRotator rotator = UKismetMathLibrary::FindLookAtRotation(start, target);
FRotator current = OwnerCharacter->GetControlRotation();
// RInterpTo : 시작 방향에서 종료 방향까지 시간에 비례한 속도로 자연스럽게 보간해주는 함수
rotator = UKismetMathLibrary::RInterpTo(current, rotator, DeltaTime, interopSpeed);
// SetControlRotation()은 private이어서 Contoller를 통해 가져와야함
OwnerCharacter->GetController()->SetControlRotation(rotator);
}
void UCTargetComponent::ToggleTarget()
{
if (!!Target)
{
EndTargeting();
return;
}
// 기존 타켓팅이 없다면 수행함
StartTargeting();
}
void UCTargetComponent::StartTargeting()
{
SetTraceTargets();
SetTarget();
}
void UCTargetComponent::EndTargeting()
{
// EndTargeting에서는 초기화 해줌
Target = NULL;
TraceTargets.Empty();
if (!!Attached)
Attached->DestroyComponent();
}
void UCTargetComponent::SetTraceTargets()
{
FVector start = OwnerCharacter->GetActorLocation();
// Sphere Multi 사용할 건데, 이건 위치가 같으면 안나옴(그래서 위치만 살짝 높임)
FVector end = FVector(start.X, start.Y, start.Z + 1);
TArray<AActor*> ignoreActors;
ignoreActors.Add(OwnerCharacter);
// SphereTraceMulti를 사용할 거라 여러개의 충돌결과가 나옴
TArray<FHitResult> hitResults;
// Profile : 프리셋의 이름으로 딱 한종류만 추적하기 위해 사용(프로젝트 설정 -> 콜리전 -> 프리셋)
// 2 : 시작 위치 3 : 끝 위치 4 : 반경 5 : 어떤 거를 찾아올건지 6 : 복합 충돌 할건지 7 : 충돌 무시 액터 8 : 디버그 지정, 9 : 반환받을 충돌결과(TArray<HitResult>) 10 : 자가자신 제외할 건지 11 : 디버그 컬러 12 : 충돌된 애들 디버그 컬러 13 : 시간
UKismetSystemLibrary::SphereTraceMultiByProfile(GetWorld(), start, end, TraceRadius, "Pawn", false, ignoreActors, Debug, hitResults, true, FLinearColor::Green, FLinearColor::Red, 1.0f);
// 반경안에 추적할 객체들
for (const FHitResult& result : hitResults)
{
if (result.GetActor()->GetClass() == OwnerCharacter->GetClass())
continue;
ACharacter* character = Cast<ACharacter>(result.GetActor());
// casting 되었다면 AddUnique()로 중복 안되게 넣어줌
if (!!character)
TraceTargets.AddUnique(character);
}
}
void UCTargetComponent::SetTarget()
{
float angle = -2.0f;
ACharacter* target = NULL;
for (ACharacter* character : TraceTargets)
{
// 플레이어는 플레이어 컨트롤러여서, 플레이어 컨트롤러는 카메라랑 관련있어서
// 카메라의 방향이 나옴
// 적이면 AIController에 의해서 회전해서, 즉 적의 회전 방향이 나온다.
// 전방방향을 가지고 옴
// UseControlRotationYaw을 켜 놓으면 어차피 전방이라 액터의 방향을 설정해도 되지만
// 끌 수도 있다. 적도 마찬가지로 타켓을 잡아서 플레이어를 바라볼 수 도 있지만, 아닐 수도 있음
// 즉 -> GetContolRotation()을 추가 한 이유는 캐릭터의 전방방향이 아닌
// 컨트롤러의 전방 방향을 사용한다.
FVector direction = FQuat(OwnerCharacter->GetControlRotation()).GetForwardVector();
FVector offset = character->GetActorLocation() - OwnerCharacter->GetActorLocation();
// direction은 GetFowardVector()는 어차피 Normallize()된 백터로 리턴하니깐
offset = offset.GetSafeNormal();
// return X*V.X + Y*V.Y + Z*V.Z;
// 내적은 각 요소의 x,y,z를 곱하고 더함
// 언리얼에서는 | operator를 제공(FVector::DotProduct()와 동일)
float temp = direction | offset;
// angle보다 작다면 안함
if (temp < angle)
continue;
// 크다면 세팅
// 이러면 가장 작은 Angle을 가진 캐릭터만 남음
// 내적의 값이 가장 작은게 바라보는 방향과 제일 일치하다는 얘기
// 내적 값이 0이면 완전 일치라서
angle = temp;
target = character;
// 전방백터를 이용해서 전방백터에 가장가까운 애를 찾음
/*
float AActor::GetDotProductTo(const AActor* OtherActor) const
{
if (OtherActor)
{
FVector Dir = GetActorForwardVector(); // 전방 백터 가져오고
FVector Offset = OtherActor->GetActorLocation() - GetActorLocation(); // 플레이어가 OtherActor을 쳐다보는 방향이 만들어짐
Offset = Offset.GetSafeNormal(); // 단위 백터가 됨
return FVector::DotProduct(Dir, Offset); // 두 값을 내적함(
}
return -2.0;
}
*/
//AActor::GetDotProductTo()
// 즉 -> DotProduceTo()에서 GetControlRoation() 부분만 추가됨
}
//CLog::Print(target->GetActorLabel());
ChangeCursor(target);
}
void UCTargetComponent::ChangeTargetLeft()
{
ChangeTarget(false);
}
void UCTargetComponent::ChangeTargetRight()
{
ChangeTarget(true);
}
void UCTargetComponent::ChangeTarget(bool InRight)
{
CheckNull(Target);
// 거리값이자 방향값 float
TMap<float, ACharacter*> map;
for (ACharacter* character : TraceTargets)
{
if (Target == character)
continue;
FVector targetLocation = character->GetActorLocation();
FVector ownerLocation = OwnerCharacter->GetActorLocation();
// owner가 target을 바라봐야 하니까
FVector ownerToTarget = targetLocation - ownerLocation;
// 카메라의 방향 값
FQuat quat = FQuat(OwnerCharacter->GetControlRotation());
// forwar, up 구해줌
FVector forward = quat.GetForwardVector();
FVector up = quat.GetUpVector();
/*
^은 외적 operator
Y * V.Z - Z * V.Y,
Z * V.X - X * V.Z,
X * V.Y - Y * V.X
*/
// 나오는 수직 백터의 값이 거리이자 방향이다.
FVector cross = forward ^ ownerToTarget;
// cross와 up을 내적해서 z값만 가지고 옴
float dot = cross | up;
map.Add(dot, character);
}
float min = FLT_MAX;
ACharacter* target = NULL;
TArray<float> keys;
map.GetKeys(keys);
for (float key : keys)
{
if (InRight == true)
{
// 키가 0보다 작거나 왼쪽 키값이다.
if (key < 0.0f)
continue;
}
// 이번에는 left니까 0보다 큰 애들을 잘라냄
else
{
if (key > 0.0f)
continue;
}
// 크다면 넘김(최소값을 구할거라)
if (FMath::Abs(key) > min)
continue;
// 가장 가까운 = 최소값의 target을 넣음
min = FMath::Abs(key);
target = *map.Find(key);
}
ChangeCursor(target);
}
void UCTargetComponent::ChangeCursor(class ACharacter* InTarget)
{
if (!!InTarget)
{
// 이미 컴포넌트가 존재한다면 제거해라
if (!!Attached)
Attached->DestroyComponent();
// 소켓에다 파티클을 붙임
Attached = UGameplayStatics::SpawnEmitterAttached(Particle, InTarget->GetMesh(), "Spine_Target");
// 타겟 지정
Target = InTarget;
return;
}
// Null이라면 EndTargeting으로 간다.
EndTargeting();
}
CPlayer.h 수정된 내용
...
UCLASS()
class UONLINE_04_ACTION_API ACPlayer : public ACharacter, public IICharacter
{
GENERATED_BODY()
private:
...
UPROPERTY(VisibleDefaultsOnly)
class UCTargetComponent* Target;
private:
void OnTarget();
void OnTargetLeft();
void OnTargetRight();
};
CPlayer.cpp 수정된 내용
...
#include "Components/CTargetComponent.h"
ACPlayer::ACPlayer()
{
...
CHelpers::CreateActorComponent<UCTargetComponent>(this, &Target, "Target");
}
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
...
PlayerInputComponent->BindAction("Target", EInputEvent::IE_Pressed, this, &ACPlayer::OnTarget);
PlayerInputComponent->BindAction("TargetLeft", EInputEvent::IE_Pressed, this, &ACPlayer::OnTargetLeft);
PlayerInputComponent->BindAction("TargetRight", EInputEvent::IE_Pressed, this, &ACPlayer::OnTargetRight);
}
void ACPlayer::OnTarget()
{
Target->ToggleTarget();
}
void ACPlayer::OnTargetLeft()
{
Target->ChangeTargetLeft();
}
void ACPlayer::OnTargetRight()
{
Target->ChangeTargetRight();
}
결과
카메라의 방향으로 적을 타켓팅 한다.
'Unreal Engine 4 > C++' 카테고리의 다른 글
<Unreal C++> 63 - Action RPG (FireStorm) (0) | 2022.05.30 |
---|---|
<Unreal C++> 61 - Action RPG (Dead) (0) | 2022.05.30 |
<Unreal C++> 56 - Action RPG (Warp Mode) (0) | 2022.05.16 |
<Unreal C++> 55 - Action RPG (Fist Mode) (0) | 2022.05.16 |
<Unreal C++> 54 - Action RPG (TwoHand Mode) (0) | 2022.05.16 |