지난 시간에 만든 검 일섬 스킬의 충돌을 구현하였다. 이제 스킬을 구사하면 적이 스킬에 맞아 피격된다. 프로젝트 세팅의 콜리전에서 콜리전 프로파일을 하나 새로 만들어서 스킬 조건에 맞는 콜리전 세팅을 커스텀으로 만든다. 만든 콜리전 프로파일을 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  생성