[UE] 활 시위 당기기

지난 시간에는 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 |
댓글
이 글 공유하기
다른 글
-
[UE] 화살
[UE] 화살
2023.07.13 -
[UE] 활 시위에 손 맞추기
[UE] 활 시위에 손 맞추기
2023.07.10 -
[UE] 활 조준
[UE] 활 조준
2023.07.06 -
[UE] 활 구현하기
[UE] 활 구현하기
2023.07.05
댓글을 사용할 수 없습니다.