TA 타겟액터 생성
GameplayAbilityTagetActor를 상속받아 PPTA_Trace 클래스를 생성
PPTA_Trace 헤더파일
#include "CoreMinimal.h"
#include "Abilities/GameplayAbilityTargetActor.h"
#include "PPTA_Trace.generated.h"
/**
*
*/
UCLASS()
class PROJECT_P_API APPTA_Trace : public AGameplayAbilityTargetActor
{
GENERATED_BODY()
public:
APPTA_Trace();
virtual void StartTargeting(UGameplayAbility* Ability) override;
virtual void ConfirmTargetingAndContinue() override;
void SetShowDebug(bool InShowDebug) { bShowDebug = InShowDebug; }
protected:
virtual FGameplayAbilityTargetDataHandle MakeTargetData() const;
bool bShowDebug = false;
};
- APPTA_Trace();
- 생성자
- virtual void StartTargeting(UGameplayAbility* Ability) override;
- 부모함수에서 상속받은 함수
- 타겟 액터를 초기화 및 처음 필요한 로직을 실행하는 함수
- virtual void ConfirmTargetingAndContinue() override;
- 부모함수에서 상속받은 함수
- 부모로직은 사용하지 않음
그러므로 Cpp에서 Super키워드로 부모 로직을 실행시키면 안됨
- void SetShowDebug(bool InShowDebug) { bShowDebug = InShowDebug; }
- TA가 생성하는 콜라이더를 디버그할지 설정하는 함수
- virtual FGameplayAbilityTargetDataHandle MakeTargetData() const;
- 타겟 데이터를 만드는 함수
- bool bShowDebug = false;
- 디버그할지 안할지 저장할 bool 변수
Cpp 파일
생성자
APPTA_Trace::APPTA_Trace()
{
}
생성자에서는 설정할게 없음
StartTargeting
void APPTA_Trace::StartTargeting(UGameplayAbility* Ability)
{
Super::StartTargeting(Ability);
SourceActor = Ability->GetCurrentActorInfo()->AvatarActor.Get();
}
- Super::StartTargeting(Ability);
- 부모 함수 실행
- 부모함수에선 OwningAbility 변수를 들어온 변수 Ability로 초기화
- SourceActor = Ability->GetCurrentActorInfo()->AvatarActor.Get();
- 추가적으로 SourceActor를 초기화
ConfirmTargetingAndContinue
void APPTA_Trace::ConfirmTargetingAndContinue()
{
//Super::ConfirmTargetingAndContinue();
if (SourceActor && IsConfirmTargetingAllowed())
{
FGameplayAbilityTargetDataHandle DataHandle = MakeTargetData();
TargetDataReadyDelegate.Broadcast(DataHandle);
}
}
ConfirmTargetingAndContinue 함수는 타겟데이터핸들을 생성해 반환해주는 함수
TargetDataReadyDelegate에 콜백함수를 연결해야 타겟데이터를 반환받을 수 있음
- ConfirmTargeting
- IsConfirmTargetingAllowed()가 true일시 ConfirmTargetingAndContinue함수를 호출해 데이터핸들을 만듦
bDestroyOnConfirmation 변수가 true이면 바로 Destroy함수 호출
- IsConfirmTargetingAllowed()가 true일시 ConfirmTargetingAndContinue함수를 호출해 데이터핸들을 만듦
- CancelTargeting
- 타겟데이터의 타겟팅을 취소하는 함수
- CanceledDelegate로 Brodcast를해 빈 데이터핸들을 전달함
- //Super::ConfirmTargetingAndContinue();
- ConfirmTargetingAndContinue 부모함수의 로직은
비어있는 TargetDataHandle을 만들어 Brodcast함
그래서 부모로직을 실행시킬 필요가 없음 - 또한 부모함수 check(ShouldProduceTargetData()); 에서
ShouldProduceTargetData함수가 false를 반환해 check함수에서 에디터가 꺼짐
- ConfirmTargetingAndContinue 부모함수의 로직은
- if (SourceActor && IsConfirmTargetingAllowed())
- 소스액터가 있고 IsConfirmTargetingAllowed가 true면 실행
- IsConfirmTargetingAllowed 함수는 단순히 return true를 실행
필요하다면 override를 해 필요한 로직을 작성해야함
- IsConfirmTargetingAllowed 함수는 단순히 return true를 실행
- FGameplayAbilityTargetDataHandle DataHandle = MakeTargetData();
- MakeTargetData 함수를 이용하여 데이터핸들을 생성
- TargetDataReadyDelegate.Broadcast(DataHandle);
- 생성한 데이터핸들을 브로드캐스트
- TargetDataReadyDelegate 콜백함수에서 EndTask를 호출하여
TA를 소유한 어빌리티 태스크가 종료되어 AT→OnDestroy함수가 호출
OnDestroy에서 TA →Destroy를 실행하여 TA를 없앰
- 소스액터가 있고 IsConfirmTargetingAllowed가 true면 실행
MakeTargetData
FGameplayAbilityTargetDataHandle APPTA_Trace::MakeTargetData() const
{
ACharacter* Character = CastChecked<ACharacter>(SourceActor);
FHitResult OutHitResult;
const float AttackRadius = 50.0f;
const float AttackRange = 100.0f;
//Params(SCENE_QUERY_STAT(태그이름), 복잡한 트레이스 할지, 충돌 검출 안할 액터)
//SCENE_QUERY_STAT(태그이름) 들어간 인자로 태그를 생성
FCollisionQueryParams Params(SCENE_QUERY_STAT(PPTA_Trace), false, Character);
const FVector FowardVector = Character->GetActorForwardVector();
const FVector Start = Character->GetActorLocation() + FowardVector * Character->GetCapsuleComponent()->GetScaledCapsuleRadius();
const FVector End = Start + FowardVector * AttackRange;
bool HitDetected = GetWorld()->SweepSingleByChannel(OutHitResult, Start, End, FQuat::Identity, CCHANNEL_PPACTION,
FCollisionShape::MakeSphere(AttackRadius), Params);
FGameplayAbilityTargetDataHandle TargetDataHandle;
if (HitDetected)
{
FGameplayAbilityTargetData_SingleTargetHit* TargetData = new FGameplayAbilityTargetData_SingleTargetHit(OutHitResult);
TargetDataHandle.Add(TargetData);
}
#if ENABLE_DRAW_DEBUG
if (bShowDebug)
{
FVector CapsuleOrigine = Start + (End - Start) * 0.5;
float CapsuleHalfHeight = AttackRange * 0.5;
FColor DrawColor = HitDetected ? FColor::Green : FColor::Red;
DrawDebugCapsule(GetWorld(), CapsuleOrigine, CapsuleHalfHeight, AttackRadius, FRotationMatrix::MakeFromZ(FowardVector).ToQuat(), DrawColor, false, 3.0f);
}
#endif
return TargetDataHandle;
}
- ACharacter* Character = CastChecked<ACharacter>(SourceActor);
- 소스액터를 캐릭터로 형변환
- FHitResult OutHitResult;
- Sweep결과를 저장할 HitResult
- const float AttackRadius = 50.0f;
const float AttackRange = 100.0f;- 공격 범위, 사거리를 저장하는 변수
현재는 하드코딩으로 작성했지만 추후 어트리뷰트 추가 후
어트리뷰트를 이용하여 가져올 예정
- 공격 범위, 사거리를 저장하는 변수
- FCollisionQueryParams Params(SCENE_QUERY_STAT(PPTA_Trace), false, Character);
- Params(SCENE_QUERY_STAT(태그이름), 복잡한 트레이스 할지, 충돌 검출 안할 액터)
- Parmas의 첫번째 인자는 Parmas에 지정할 이름인데 SCENE_QUERY_STAT매크로를 이용하여 지정
- 추후 Sweep에 들어갈 Params
- Params(SCENE_QUERY_STAT(태그이름), 복잡한 트레이스 할지, 충돌 검출 안할 액터)
- const FVector FowardVector = Character->GetActorForwardVector();
- 캐릭터로 부터 FowardVector를 가져옴
- const FVector Start = Character->GetActorLocation() +
FowardVector * Character->GetCapsuleComponent()->GetScaledCapsuleRadius();- 시작 지점 = 캐릭터의 로케이션 + (포워드 백터 * 캡슐의 반지름)
- (포워드 백터 * 캡슐의 반지름)으로 캐릭터의 콜라이더 끝부분으로 시작지점을 지정
- 시작 지점 = 캐릭터의 로케이션 + (포워드 백터 * 캡슐의 반지름)
- const FVector End = Start + FowardVector * AttackRange;
- 끝 지점 = 스타트 지점 + FowardVector * 공격 사거리
- 스타트 지점에 공격 사거리를 더해줌
- 끝 지점 = 스타트 지점 + FowardVector * 공격 사거리
- bool HitDetected = GetWorld()>
SweepSingleByChannel(OutHitResult, Start, End, FQuat::Identity, CCHANNEL_PPACTION,
FCollisionShape::MakeSphere(AttackRadius), Params);- SweepSingleByChannel 함수를 이용해 공격판정
Sweep(도형)Single(한개의 결과)ByChannel(채널을 이용) - SweepSingleByChannel(결과를 저장할 구조체, 시작지점, 끝지점, 로테이션, 트레이스채널, 생성할 도형, 쿼리 파람)
- 생성한 도형이 Start지점부터 End까지 이동하여 첫번째로 부짖히는 액터
(해당 액터의 콜리전 프리셋에서 설정한 트레이스 채널의 이벤트가 Block이 설정되어야 됨)
에 Block 이벤트를 발생하여 HitReuslt에 저장됨
- SweepSingleByChannel 함수를 이용해 공격판정
- FGameplayAbilityTargetDataHandle TargetDataHandle;
- 빈 타겟데이터 핸들을 만듦
- if (HitDetected)
- Sweep이 성공했으면
- FGameplayAbilityTargetData_SingleTargetHit* TargetData =
new FGameplayAbilityTargetData_SingleTargetHit(OutHitResult);- 싱글히트 결과인 경우 FGameplayAbilityTargetData_SingleTargetHit 를 사용하여 인스턴스를 만들 수 있음
- new FGameplayAbilityTargetData_SingleTargetHit(OutHitResult)
- OutHitResult 를 넣어 FGameplayAbilityTargetData를 생성
- TargetDataHandle.Add(TargetData);
- 타겟 데이터 핸들에 생성한 타겟 데이터를 넣어줌
- return TargetDataHandle;
- 최종적으로 만든 데이터를 리턴
- #if ENABLE_DRAW_DEBUG
- 디버그 드로우가 활성화 되어있으면
- if (bShowDebug)
- FVector CapsuleOrigine = Start + (End - Start) * 0.5;
float CapsuleHalfHeight = AttackRange * 0.5;- 그릴 캡슐의 중심점과 높이의 반절을 구함
- FColor DrawColor = HitDetected ? FColor::Green : FColor::Red;
- 색 지정
- DrawDebugCapsule(GetWorld(), CapsuleOrigine, CapsuleHalfHeight, AttackRadius, FRotationMatrix::MakeFromZ(FowardVector).ToQuat(), DrawColor, false, 3.0f);
- DrawDebugCapsule 함수를 이용하여 캡슐을 그림
- FVector CapsuleOrigine = Start + (End - Start) * 0.5;
콜리전 관련 참고할 글
https://frompero.github.io/post/unreal/unreal-10/
[Unreal] 언리얼 충돌 처리 방법, 월드 트레이싱 함수
충돌체를 만들자!
frompero.github.io
'포트폴리오 제작 > Project_P' 카테고리의 다른 글
Project_P AttributeSet을 사용하여 스탯 만들기 (0) | 2024.10.16 |
---|---|
Project_P 캐릭터에 구현된 Move함수 실행시 GameplayTag 부여 (0) | 2024.10.04 |
Project_P 공격 판정 구현(3) Trace 어빌리티 태스크 생성 (0) | 2024.09.06 |
Project_P 공격 판정 구현(2) AttackCheck GA 생성 (0) | 2024.09.06 |
Project_P 공격 판정 구현(1) 애니메이션 노티파이 생성 및 콤보어택몽타주 생성 (1) | 2024.09.05 |