[UE] 일섬 스킬 충돌, 해머 스킬 만들기
지난 시간에 만든 검 일섬 스킬의 충돌을 구현하였다. 이제 스킬을 구사하면 적이 스킬에 맞아 피격된다. 프로젝트 세팅의 콜리전에서 콜리전 프로파일을 하나 새로 만들어서 스킬 조건에 맞는 콜리전 세팅을 커스텀으로 만든다. 만든 콜리전 프로파일을 CSubAction_Sword에서 스킬 실행 시 적용되게 만들어준다.
목차
Plugins |
||||
Weapon |
||||
Resource |
||||
Icon128.png weapon_thumbnail_icon.png |
||||
Source |
||||
Weapon | ||||
SWeaponCheckBoxes.h .cpp SWeaponDetailsView.h .cpp SWeaponDoActionData.h .cpp SWeaponEquipmentData.h .cpp SWeaponHitData.h .cpp SWeaponLeftArea.h .cpp Weapon.Build.cs WeaponAssetEditor.h .cpp WeaponAssetFactory.h .cpp WeaponCommand.h .cpp WeaponContextMenu.h .cpp WeaponModule.h .cpp WeaponStyle.h .cpp |
||||
Source | ||
U2212_06 | ||
Characters | ||
CAnimInstance.h .cpp CEnemy.h .cpp CPlayer.h .cpp ICharacter.h .cpp |
||
Components | ||
CMontagesComponent.h .cpp CMovementComponent.h .cpp CStateComponent.h .cpp CStatusComponent.h .cpp CWeaponComponent.h .cpp |
||
Notifies | ||
CAnimNotifyState_BeginAction.h .cpp CAnimNotify_CameraShake.h .cpp CAnimNotifyState_EndAction.h .cpp CAnimNotify_EndState.h .cpp CAnimNotifyState.h .cpp CAnimNotifyState_CameraAnim.h .cpp CAnimNotifyState_Collision.h .cpp CAnimNotifyState_Combo.h .cpp CAnimNotifyState_Equip.h .cpp CAnimNotifyState_SubAction.h .cpp |
||
Utilities | ||
CHelper.h CLog.h .cpp |
||
Weapons | ||
CCamerModifier.h .cpp CGhostTrail.h .cpp CDoAction_Combo.h .cpp CSubAction_Fist.h .cpp CSubAction_Hammer.h .cpp 생성 CSubAction_Sword.h .cpp CAttachment.h .cpp CDoAction.h .cpp CEquipment.h .cpp CSubAction.h .cpp CWeaponAsset.h .cpp CWeaponStructures.h .cpp |
||
Global.h CGameMode.h .cpp U2212_06.Build.cs |
||
U2212_06.uproject | ||
일섬 스킬 구현하기
프로젝트 세팅 - 일섬 스킬 시 ㅖPawn(=Enemy 통과하기
검 일섬 스킬 시에Enemy를 통과시키기 위해 콜리전 충돌 프로파일을 하나 만든다.
이름: Sword_SubAction
콜리전 켜짐: Query Only(No Physics Collision)
오브젝트 유형: WorldStatic
무시(Ignore): Visibility, Camera
겹침(Overlap): WorldDynamic, Pawn
블록: Worldstatic, PhysicsBody, Vehicle, Destructible
- Pawn뿐만 아니라 (돌아다니는) 물체를 뚫을수도 있으니 WorldDynamic도체 겹침으로 체크해준다.
- World Static이 블록이되어야 맵(=지형, 구조물 등)과 충돌해서 서 있을 수 있다.
※ Unreal C++ 코드 (Collision)
ETraceTypeQuery::TraceTypeQuery1 Visibility
ETraceTypeQuery::TraceTypeQuery2 Camera
ETraceTypeQuery::TraceTypeQuery3 Pawn
CSubAction_Sword
CSubAction_Sword.h
#pragma once
#include "CoreMinimal.h"
#include "Weapons/CSubAction.h"
#include "Weapons/CWeaponStructures.h"
#include "Kismet/KismetSystemLibrary.h"
#include "CSubAction_Sword.generated.h"
UCLASS(Blueprintable)
class U2212_06_API UCSubAction_Sword : public UCSubAction
{
GENERATED_BODY()
private:
UPROPERTY(EditDefaultsOnly, Category = "Trace")
float Distance = 1000.0;//이동거리
UPROPERTY(EditDefaultsOnly, Category = "Trace")
float Speed = 200;//속도
UPROPERTY(EditDefaultsOnly, Category = "Trace")
TEnumAsByte<EDrawDebugTrace::Type> DrawDebug;//디버그용
private:
UPROPERTY(EditDefaultsOnly, Category = "Action")
FDoActionData ActionData;
UPROPERTY(EditDefaultsOnly, Category = "Action")
FHitData HitData;
private:
UPROPERTY(EditAnywhere, Category = "Add-On")
TSubclassOf<class ACGhostTrail> GhostTrailClass;
public:
void Pressed() override;
void Begin_SubAction_Implementation() override;
void End_SubAction_Implementation() override;
void Tick_Implementation(float InDeltaTime) override;
private:
UFUNCTION()
void OnAttachmentBeginOverlap(class ACharacter* InAttacker, AActor* InAttackCuaser, class ACharacter* InOther);//충돌 함수
private:
bool bMoving;
FVector Start;
FVector End;
//복구를 위해 저장해두는 변수: Overlapped, Hitted
TArray<class ACharacter*> Overlapped;
TArray<class ACharacter*> Hitted;
private:
class ACGhostTrail* GhostTrail;
};
충돌 함수 추가
- UFUNCTION()
void OnAttachmentBeginOverlap(class ACharacter* InAttacker, AActor* InAttackCuaser, class ACharacter* InOther);
복구를 위해 저장해두는 변수 추가
- TArray<class ACharacter*> Overlapped;
- TArray<class ACharacter*> Hitted;
- 원본을 저장해두었다 일섬 스킬이 끝나면 위의 변수를 활용해서 되돌려준다.
CSubAction_Sword.cpp
#include "Weapons/SubActions/CSubAction_Sword.h"
#include "Global.h"
#include "Weapons/CAttachment.h"
#include "Weapons/CDoAction.h"
#include "GameFramework/Character.h"
#include "Components/CapsuleComponent.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
#include "Components/CapsuleComponent.h"
#include "Weapons/AddOns/CGhostTrail.h"
void UCSubAction_Sword::Pressed()
{
CheckFalse(State->IsIdleMode());
CheckTrue(State->IsSubActionMode());
Super::Pressed();
State->SetActionMode();
State->OnSubActionMode();
GhostTrail = CHelpers::Play_GhostTrail(GhostTrailClass, Owner);
ActionData.DoAction(Owner);
}
void UCSubAction_Sword::Begin_SubAction_Implementation()
{
Super::Begin_SubAction_Implementation();
//Begin_SubAction이 시작할 때 DoAction의 충돌체를 빼주고 SubAction_Sword는 AddDynamic으로 추가해준다.
Attachment->OnAttachmentBeginOverlap.Remove(DoAction, "OnAttachmentBeginOverlap");
Attachment->OnAttachmentBeginOverlap.AddDynamic(this, &UCSubAction_Sword::OnAttachmentBeginOverlap);
bMoving = true;//이동할 수 있게 설정해준다.
Start = Owner->GetActorLocation();//시작 위치 = Owner의 위치
End = Start + Owner->GetActorForwardVector() * Distance;//끝 위치 = 시작 위치 + Owner의 앞 방향으로 (헤더에서 기본값 설정한)Distance 거리
float radius = Owner->GetCapsuleComponent()->GetScaledCapsuleRadius();//capsule의 radius
float height = Owner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();//capsule의 halfHeight
FRotator rotation = Owner->GetActorRotation();
TArray<AActor*> ignores;//제외시킬 것들을 담을 배열 변수
ignores.Add(Owner);//자기자신은 제외시킨다.
TArray<FHitResult> hitResults;
TArray<TEnumAsByte<EObjectTypeQuery>> objects;
objects.Add(EObjectTypeQuery::ObjectTypeQuery3);//ObjectTypeQuery3은 Pawn. Pawn을 추적하기 위해 objects에 추가하였다.
//Trace를 여러개 체크하기 위해 TraceMulti사용
UKismetSystemLibrary::BoxTraceMultiForObjects(Owner->GetWorld(), Start, End, FVector(0, radius, height), rotation, objects, false, ignores, DrawDebug, hitResults, true);//objects는 추적 타입들
for (const FHitResult& hitResult : hitResults)
{
ACharacter* character = Cast<ACharacter>(hitResult.GetActor());
if (!!character)
{
character->GetCapsuleComponent()->SetCollisionProfileName("Sword_SubAction");//프로젝트 세팅에서 만든 Profile인 Sword_SubAction 사용.
Overlapped.Add(character);
}
}
FHitResult lineHitResult;
UKismetSystemLibrary::LineTraceSingle(Owner->GetWorld(), Start, End, ETraceTypeQuery::TraceTypeQuery1, false, ignores, DrawDebug, lineHitResult, true);//TraceTypeQuery1은 Visibility
if(lineHitResult.bBlockingHit)//하나라도 충돌되었다면
{
FVector direction = (End - Start).GetSafeNormal2D();
End = lineHitResult.Location - (direction * radius * 2);//(벽에) 부딛혔을 때 밀착하는게 아니라 capsule * 2 거리에서 멈춘추도록 End 설정.
if (DrawDebug == EDrawDebugTrace::ForDuration)
DrawDebugSphere(Owner->GetWorld(), End, radius * 2, 20, FColor::Magenta, true, 2);
}
//Draw Debug
if (DrawDebug == EDrawDebugTrace::ForDuration)
DrawDebugDirectionalArrow(Owner->GetWorld(), Start, End, 25, FColor::Green, true, 5, 0, 3);
}
void UCSubAction_Sword::End_SubAction_Implementation()
{
Super::End_SubAction_Implementation();
//Begin_SubAction이 끝나면 SubAction_Sword의 충돌은 빼주고 DoAction의 충돌체는 AddDynamic으로 추가한다.
Attachment->OnAttachmentBeginOverlap.Remove(this, "OnAttachmentBeginOverlap");
Attachment->OnAttachmentBeginOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginOverlap);
bMoving = false;//동작이 끝났으니 이동하지 못하게 false로 만들어준다.
State->SetIdleMode();
State->OffSubActionMode();
Movement->Move();
Movement->DisableFixedCamera();
for (ACharacter* character : Overlapped)
character->GetCapsuleComponent()->SetCollisionProfileName("Pawn");//Sword_SubAction으로 변경했던 프로파일을 원래 프로파일 이었던 Pawn으로 돌려준다.
if (!!GhostTrail)
GhostTrail->Destroy();//GhostTrail를 없앤다.
}
void UCSubAction_Sword::Tick_Implementation(float InDeltaTime)
{
Super::Tick_Implementation(InDeltaTime);
CheckFalse(bMoving);
FVector location = Owner->GetActorLocation();
float radius = Owner->GetCapsuleComponent()->GetScaledCapsuleRadius();
//location이 radius 오차값 내에서 End와 같다면
//Owner(여기서는 Player)의 위치가 radius 오차값 내의 End 위치에 도달했다면
if(location.Equals(End, radius))
{
bMoving = false;//일섬 공격이 끝났으니 이동하지 못하게 false로 만들어준다.
Start = End = Owner->GetActorLocation();//시작과 끝 위치를 현재 Owner의 위치로 설정해준다. 초기화.
return;
}
//Empty로 비워주지 않으면 최초 피격 후에는 피격이 추가로 적용되지 않는다.
Overlapped.Empty();
Hitted.Empty();
FVector direction = (End - Start).GetSafeNormal2D();
Owner->AddActorWorldOffset(direction * Speed, true);
}
void UCSubAction_Sword::OnAttachmentBeginOverlap(ACharacter* InAttacker, AActor* InAttackCuaser, ACharacter* InOther)
{
CheckNull(InOther);
for (ACharacter* character : Hitted)
CheckTrue(character == InOther);
Hitted.AddUnique(InOther);
HitData.SendDamage(Owner, InAttackCuaser, InOther);
}
void UCSubAction_Sword::Begin_SubAction_Implementation()
- Begin_SubAction이 시작할 때 DoAction의 충돌체를 빼주고 SubAction_Sword는 AddDynamic으로 추가해준다.
- Attachment->OnAttachmentBeginOverlap.Remove(DoAction, "OnAttachmentBeginOverlap");
- Attachment->OnAttachmentBeginOverlap.AddDynamic(this, &UCSubAction_Sword ::OnAttachmentBeginOverlap);
- 캐릭터의 Capsule을 기준으로 radius, height를 설정해준다.
- 본인 자신을 콜리전에서 제외시킨다
- TArray<AActor*> ignores;//제외시킬 것들을 담을 배열 변수
- ignores.Add(Owner);
- 벽에 부딪치는 경우, 바로 앞이 아니라 Capsule radius 2배 거리만큼 전에서 멈추게 한다.
- End = lineHitResult.Location - (direction * radius * 2);
void UCSubAction_Sword::End_SubAction_Implementation()
- Begin_SubAction이 끝나면 SubAction_Sword의 충돌은 빼주고 DoAction의 충돌체는 AddDynamic으로 추가한다.
- Attachment->OnAttachmentBeginOverlap.Remove(this, "OnAttachmentBeginOverlap");
- Attachment->OnAttachmentBeginOverlap.AddDynamic(DoAction, &UCDoAction ::OnAttachmentBeginOverlap);
함수 정의
- void UCSubAction_Sword::OnAttachmentBeginOverlap(ACharacter* InAttacker, AActor* InAttackCuaser, ACharacter* InOther)
- 충돌이 일어나면 Damage를 전달한다.
실행화면
해머 스킬 만들기
Nigara Particle로 사용할 에셋 이주해서 불러오기- NS_Ulti_lv1
NS_Ulti_lv1
Initialize Particle의 Color를 조정해서 원하는 색으로 바꿔준다.
BP_CGhostTrail_Hammer
BP_CGhostTrail 복제 - BP_CGhostTrail_Hammer 생성
CSubAction_Hammer 생성
새 C++ 클래스 - CSubAction - CSubAction_Hammer 생성
CSubAction_Hammer.h
#pragma once
#include "CoreMinimal.h"
#include "Weapons/CSubAction.h"
#include "Weapons/CWeaponStructures.h"
#include "CSubAction_Hammer.generated.h"
UCLASS(Blueprintable)
class U2212_06_API UCSubAction_Hammer : public UCSubAction
{
GENERATED_BODY()
private:
UPROPERTY(EditDefaultsOnly, Category = "Action")
FDoActionData ActionData;
UPROPERTY(EditDefaultsOnly, Category = "Add-On")
TSubclassOf<class ACGhostTrail> GhostTrailClass;
public:
void Pressed() override;
void Begin_SubAction_Implementation() override;
void End_SubAction_Implementation() override;
private:
class ACGhostTrail* GhostTrail;
};
CSubAction_Hammer.cpp
#include "Weapons/SubActions/CSubAction_Hammer.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
#include "Weapons/CAttachment.h"
#include "Weapons/CDoAction.h"
#include "Weapons/AddOns/CGhostTrail.h"
void UCSubAction_Hammer::Pressed()
{
CheckFalse(State->IsIdleMode());
CheckTrue(State->IsSubActionMode());
Super::Pressed();
State->SetActionMode();
State->OnSubActionMode();
GhostTrail = CHelpers::Play_GhostTrail(GhostTrailClass, Owner);
ActionData.DoAction(Owner);
}
void UCSubAction_Hammer::Begin_SubAction_Implementation()
{
Super::Begin_SubAction_Implementation();
}
void UCSubAction_Hammer::End_SubAction_Implementation()
{
Super::End_SubAction_Implementation();
State->SetIdleMode();
State->OffSubActionMode();
Movement->Move();
Movement->DisableFixedCamera();
if (!!GhostTrail)
GhostTrail->Destroy();
}
BP_CSubAction_Hammer 생성
CSubAction_Hammer 기반 블루프린트 클래스 생성 - BP_CSubAction_Hammer 생성
'⭐ Unreal Engine > UE RPG Skill' 카테고리의 다른 글
[UE] 워프 구현하기 (0) | 2023.06.29 |
---|---|
[UE] 해머 스킬 만들기 (0) | 2023.06.27 |
[UE] 주먹 스킬 충돌처리, 전진 찌르기 스킬 구현하기 (0) | 2023.06.23 |
[UE] 잔상효과 구현하기 (0) | 2023.06.22 |
[UE] 카메라 애니메이션 구현하기 (0) | 2023.06.21 |
댓글
이 글 공유하기
다른 글
-
[UE] 워프 구현하기
[UE] 워프 구현하기
2023.06.29 -
[UE] 해머 스킬 만들기
[UE] 해머 스킬 만들기
2023.06.27 -
[UE] 주먹 스킬 충돌처리, 전진 찌르기 스킬 구현하기
[UE] 주먹 스킬 충돌처리, 전진 찌르기 스킬 구현하기
2023.06.23 -
[UE] 잔상효과 구현하기
[UE] 잔상효과 구현하기
2023.06.22