지난 시간에는 BlendSpace1D를 사용하여 활이 구부러지는것을 구현하였다. 오늘은 활의 SkeletalMesh에 AnimInstance를 만들어 활의 시위가 당겨지는 것을 구현하겠다. CAnimInstance_Bow, CAttachment_Bow, 그리고 CSubAction_Bow는 서로 상속관계가 아니므로  활 시위가 당겨지는 float 변수(여기서는 float Bend)를 만들어 이어줘야 한다.

 

 

 

 


 

 

 
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
    CAura.h .cpp
CCamerModifier.h .cpp
CGhostTrail.h .cpp
CRotate_Object.h .cpp
CThornObject.h .cpp
CAnimInstance_Bow.h .cpp 생성
CAttachment_Bow.h .cpp
CDoAction_Around.h .cpp
CDoAction_Combo.h .cpp
CDoAction_Warp.h .cpp
CSubAction_Around.h .cpp
CSubAction_Bow.h .cpp
CSubAction_Fist.h .cpp
CSubAction_Hammer.h .cpp
CSubAction_Sword.h .cpp
CDoAction_Warp.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
 

 

 

 

 

활 시위 당기기

 

 


 

 

CAnimInstance_Bow 생성  +  ABP_ElevenBow

 

새 C++ 클래스 - AnimInstance - CAnimInstance_Bow 생성

 

 

CAnimInstance_Bow.h

더보기
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "Components/CWeaponComponent.h"
#include "CAnimInstance.generated.h"
UCLASS()
class U2212_06_API UCAnimInstance : public UAnimInstance
{
GENERATED_BODY()
protected:
UPROPERTY(BlueprintReadOnly, Category = "Animation")
float Speed;
UPROPERTY(BlueprintReadOnly, Category = "Animation")
float Pitch;
UPROPERTY(BlueprintReadOnly, Category = "Animation")
float Direction;
UPROPERTY(BlueprintReadOnly, Category = "Animation")
bool bBow_Aiming;
protected:
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Animation")
EWeaponType WeaponType = EWeaponType::Max;
public:
void NativeBeginPlay() override;
void NativeUpdateAnimation(float DeltaSeconds) override;
private:
UFUNCTION()
void OnWeaponTypeChanged(EWeaponType InPrevType, EWeaponType InNewType);
private:
class ACharacter* OwnerCharacter;
class UCWeaponComponent* Weapon;
private:
FRotator PrevRotation;
};

 

 

 

CAnimInstance_Bow.cpp

더보기
#include "Weapons/AnimInstances/CAnimInstance_Bow.h"
#include "Global.h"
void UCAnimInstance_Bow::NativeBeginPlay()
{
Super::NativeBeginPlay();
}
void UCAnimInstance_Bow::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
}

 

 

 

 

 

ABP_ElevenBow

애니메이션 - 애니메이션 블루프린트 생성 - CAnimInstance_Bow, Skeletal_ElvenBow - ABP_ElevenBow 생성

CAnimInstance_Bow에서 만든 변수 Bend 사용. Bend 변수를 활 시위의 당기는 정도로 사용한다.

 


 

 

CAttachment_Bow

 

 

CAttachment_Bow.h

더보기
#pragma once
#include "CoreMinimal.h"
#include "Weapons/CAttachment.h"
#include "CAttachment_Bow.generated.h"
UCLASS()
class U2212_06_API ACAttachment_Bow : public ACAttachment
{
GENERATED_BODY()
private:
UPROPERTY(EditDefaultsOnly, Category = "View")
FVector2D ViewPitchRange = FVector2D(-40, +30);//Pitch 제한각 설정
private:
UPROPERTY(VisibleAnywhere)
class USkeletalMeshComponent* SkeletalMesh;
UPROPERTY(VisibleAnywhere)
class UPoseableMeshComponent* PoseableMesh;
public:
float* GetBend();
public:
ACAttachment_Bow();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
public:
void OnBeginEquip_Implementation() override;
void OnUnequip_Implementation() override;
private:
FVector2D OriginViewPitchRange;
};

함수 추가

  • float* GetBend();

 

 

 

CAttachment_Bow.cpp

더보기
#include "Weapons/Attachments/CAttachment_Bow.h"
#include "Global.h"
#include "Weapons/AnimInstances/CAnimInstance_Bow.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/PoseableMeshComponent.h"
ACAttachment_Bow::ACAttachment_Bow()
{
PrimaryActorTick.bCanEverTick = true;//실시간 적용이 되도록 넣어준다. 안 넣어주면 활 시위가 구부러지는것이 업데이트 되지 않을 수도 있다.
CHelpers::CreateComponent<USkeletalMeshComponent>(this, &SkeletalMesh, "SkeletalMesh", Root);
CHelpers::CreateComponent<UPoseableMeshComponent>(this, &PoseableMesh, "PoseableMesh", Root);
USkeletalMesh* mesh;
CHelpers::GetAsset<USkeletalMesh>(&mesh, "SkeletalMesh'/Game/Character/Weapons/ElvenBow/SK_ElvenBow.SK_ElvenBow'");
SkeletalMesh->SetSkeletalMesh(mesh);
SkeletalMesh->SetCollisionProfileName("NoCollision");
TSubclassOf<UCAnimInstance_Bow> animInstacne;
CHelpers::GetClass<UCAnimInstance_Bow>(&animInstacne, "AnimBlueprint'/Game/Weapons/Bow/ABP_ElvenBow.ABP_ElvenBow_C'");//ABP_ElvenBow 레퍼런스 복사하여 생성.
SkeletalMesh->SetAnimInstanceClass(animInstacne);
}
void ACAttachment_Bow::BeginPlay()
{
Super::BeginPlay();
AttachTo("Holster_Bow");
SkeletalMesh->SetVisibility(false);
PoseableMesh->SetSkeletalMesh(SkeletalMesh->SkeletalMesh);//SkeletalMesh 내의 SkeletalMesh 사용.
PoseableMesh->CopyPoseFromSkeletalComponent(SkeletalMesh);//포즈를 캡처해둔다.
}
void ACAttachment_Bow::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
PoseableMesh->CopyPoseFromSkeletalComponent(SkeletalMesh);
}
void ACAttachment_Bow::OnBeginEquip_Implementation()
{
Super::OnBeginEquip_Implementation();
AttachTo("Hand_Bow_Left");//Hand_Bow_Left 소켓에 장착.
APlayerController* controller = OwnerCharacter->GetController<APlayerController>();
if (!!controller)
{
OriginViewPitchRange.X = controller->PlayerCameraManager->ViewPitchMin;
OriginViewPitchRange.Y = controller->PlayerCameraManager->ViewPitchMax;
controller->PlayerCameraManager->ViewPitchMin = ViewPitchRange.X;
controller->PlayerCameraManager->ViewPitchMax = ViewPitchRange.Y;
}
}
void ACAttachment_Bow::OnUnequip_Implementation()
{
Super::OnUnequip_Implementation();
AttachTo("Holster_Bow");//Holster_Bow 소켓에 장착.
APlayerController* controller = OwnerCharacter->GetController<APlayerController>();
if (!!controller)
{
controller->PlayerCameraManager->ViewPitchMin = OriginViewPitchRange.X;
controller->PlayerCameraManager->ViewPitchMax = OriginViewPitchRange.Y;
}
}
float* ACAttachment_Bow::GetBend()
{
return Cast<UCAnimInstance_Bow>(SkeletalMesh->GetAnimInstance())->GetBend();//UCAnimInstance_Bow 안의 GetBend() 함수로 Bend값 리턴. UCAnimInstance_Bow 안의 Bend값을 사용한다.
}

헤더 추가

  • #include "Weapons/AnimInstances/CAnimInstance_Bow.h"

 

ACAttachment_Bow::ACAttachment_Bow()

  • PrimaryActorTick.bCanEverTick = true;
    • 실시간 적용이 되도록 넣어준다. 안 넣어주면 활 시위가 구부러지는것이 업데이트 되지 않을 수도 있다.
  • TSubclassOf<UCAnimInstance_Bow> animInstacne;
  • CHelpers::GetClass<UCAnimInstance_Bow>(&animInstacne, "AnimBlueprint'/Game/Weapons/Bow/ ABP_ElvenBow.ABP_ElvenBow_C'");
    • ABP_ElvenBow 레퍼런스 복사하여 생성.
  • SkeletalMesh->SetAnimInstanceClass(animInstacne);

 

float* ACAttachment_Bow::GetBend()

  • return Cast<UCAnimInstance_Bow>(SkeletalMesh->GetAnimInstance())->GetBend();
    • UCAnimInstance_Bow 안의 GetBend() 함수로 Bend값 리턴. UCAnimInstance_Bow 안의 Bend값을 사용한다.

 

 

 


 

 

CSubAction_Bow

 

 

CSubAction_Bow.h

더보기
#pragma once
#include "CoreMinimal.h"
#include "Weapons/CSubAction.h"
#include "Components/TimelineComponent.h"
#include "CSubAction_Bow.generated.h"
USTRUCT()
struct FAimData
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere)
float TargetArmLength = 100;
UPROPERTY(EditAnywhere)
FVector SocketOffset = FVector(0, 30, 10);
UPROPERTY(EditAnywhere)
bool bEnableCameraLag;
UPROPERTY(EditAnywhere)
FVector CameraLocation;
};
UCLASS(Blueprintable)
class U2212_06_API UCSubAction_Bow : public UCSubAction
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, Category = "Aiming")
class UCurveVector* Curve;
UPROPERTY(EditAnywhere, Category = "Aiming")
FAimData AimData;
UPROPERTY(EditAnywhere, Category = "Aiming")
float AimingSpeed = 200;
public:
UCSubAction_Bow();
public:
virtual void Pressed() override;
virtual void Released() override;
public:
void BeginPlay(class ACharacter* InOwner, class ACAttachment* InAttachment, class UCDoAction* InDoAction) override;
public:
void Tick_Implementation(float InDeltaTime) override;
private:
UFUNCTION()
void onAiming(FVector Output);
private:
class USpringArmComponent* SpringArm;
class UCameraComponent* Camera;
private:
FTimeline Timeline;
//SubAction는 Actor가 아니기 때문에 Component를 가질 수 없다. SubAction은 UObject 상속이다.
//그래서 TimelineComponent가 아닌 Timeline으로 작업한다.
private:
FAimData OriginData;
private:
float* Bend;
};

변수 추가

  • float Bend;

 

 

 

CSubAction_Bow.cpp

더보기
#include "Weapons/SubActions/CSubAction_Bow.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "Components/CStateComponent.h"
#include "Weapons/Attachments/CAttachment_Bow.h"
UCSubAction_Bow::UCSubAction_Bow()
{
CHelpers::GetAsset<UCurveVector>(&Curve, "CurveVector'/Game/Weapons/Bow/Curve_Aiming.Curve_Aiming'");//Editor에서 만든 CurveVector를 할당한다.
}
void UCSubAction_Bow::Pressed()
{
CheckTrue(State->IsSubActionMode());
CheckNull(SpringArm);
CheckNull(Camera);
Super::Pressed();
State->OnSubActionMode();
OriginData.TargetArmLength = SpringArm->TargetArmLength;
OriginData.SocketOffset = SpringArm->SocketOffset;
OriginData.bEnableCameraLag = SpringArm->bEnableCameraLag;
OriginData.CameraLocation = Camera->GetRelativeLocation();
SpringArm->TargetArmLength = AimData.TargetArmLength;
SpringArm->SocketOffset = AimData.SocketOffset;
SpringArm->bEnableCameraLag = AimData.bEnableCameraLag;
Camera->SetRelativeLocation(AimData.CameraLocation);
Timeline.PlayFromStart();//Timeline 동작 시작.
}
void UCSubAction_Bow::Released()
{
CheckFalse(State->IsSubActionMode());
CheckNull(SpringArm);
CheckNull(Camera);
Super::Released();
State->OffSubActionMode();
SpringArm->TargetArmLength = OriginData.TargetArmLength;
SpringArm->SocketOffset = OriginData.SocketOffset;
SpringArm->bEnableCameraLag = OriginData.bEnableCameraLag;
Camera->SetRelativeLocation(OriginData.CameraLocation);
Timeline.ReverseFromEnd();//Timeline 뒤집기
}
void UCSubAction_Bow::BeginPlay(ACharacter* InOwner, ACAttachment* InAttachment, UCDoAction* InDoAction)
{
Super::BeginPlay(InOwner, InAttachment, InDoAction);
SpringArm = CHelpers::GetComponent<USpringArmComponent>(InOwner);
Camera = CHelpers::GetComponent<UCameraComponent>(InOwner);
FOnTimelineVector timeline;
timeline.BindUFunction(this, "OnAiming");//OnAiming함수를 묶어서 콜한다.
Timeline.AddInterpVector(Curve, timeline);
Timeline.SetPlayRate(AimingSpeed);
ACAttachment_Bow* bow = Cast<ACAttachment_Bow>(InAttachment);//CAttachment_Bow의 멤버를 사용하기 위해 캐스팅한다.
if (!!bow)
Bend = bow->GetBend();//CSubAction_Bow에서 선언한 Bend 변수에 CAttachment_Bow의 Bend값을 GetBend()로 가져와서 넣어준다.
}
void UCSubAction_Bow::Tick_Implementation(float InDeltaTime)
{
Super::Tick_Implementation(InDeltaTime);
//TimelineComponent로 사용하는 경우 자기자신이 Tick이 있기 때문에 아래 작업을 안 해도 상관없으나 CSubAction_Bow의 경우 TimelineComponent가 없기 때문에 Tick을 반드시 넣어주어야 한다.
Timeline.TickTimeline(InDeltaTime);
}
void UCSubAction_Bow::onAiming(FVector Output)
{
Camera->FieldOfView = Output.X;//조준 활성화와 해제에 앞뒤 ZoomIn&Out에 Output.X값이 쓰인다.
if (!!Bend)
*Bend = Output.Y;//에디터의 Curve_Aiming에서 설정한 Y값. 0~100까지 나온다.
}

void UCSubAction_Bow::BeginPlay(ACharacter* InOwner, ACAttachment* InAttachment, UCDoAction* InDoAction)

  • if (!!bow)
    Bend = bow->GetBend();
    • CSubAction_Bow에서 선언한 Bend 변수에 CAttachment_Bow의 Bend값을 GetBend()로 가져와서 넣어준다.

 

void UCSubAction_Bow::onAiming(FVector Output)

  • Camera->FieldOfView = Output.X;//
    • 조준 활성화와 해제에 앞뒤 ZoomIn&Out에 Output.X값이 쓰인다.
  • if (!!Bend)
    *Bend = Output.Y;//에디터의 Curve_Aiming에서 설정한 Y값. 0~100까지 나온다.
    }

 

 


 

실행화면

 

 

 


 

 

 

'⭐ Unreal Engine > UE RPG Skill' 카테고리의 다른 글

[UE] 화살  (0) 2023.07.13
[UE] 활 시위에 손 맞추기  (0) 2023.07.10
[UE] 활 조준  (0) 2023.07.06
[UE] 활 구현하기  (0) 2023.07.05
[UE] Around 스킬 구현하기  (0) 2023.07.04