[UE] 활 시위에 손 맞추기

지난 시간에는 활 시위를 구부러뜨리는것을 구현하였다. 오늘은 활 시위를 플레이어 손에 붙였다가 화살 발사 시 손에 떨어뜨리는 것을 구현할 것이다. CDo_Action_Bow를 만들어 발사 시점과 끝난 시점을 구분지어 줄 것이다. CAnimNotifyState_BowString 만들어 손에서 떨어진 활 시위를 다시 붙여주는 시점에 몽타주에 삽입할 것이다.
목차
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 CAnimNotifyState_BowString.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_Bow.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 | ||
활 시위에 손 맞추기
CAttachment_Bow - 캡처를 삭제하고 Do_Action_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; };
변경사항 없음
CAttachment_Bow.h
#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> animInstance; CHelpers::GetClass<UCAnimInstance_Bow>(&animInstance, "AnimBlueprint'/Game/Weapons/Bow/ABP_ElvenBow.ABP_ElvenBow_C'");//ABP_ElvenBow 레퍼런스 복사하여 생성. SkeletalMesh->SetAnimInstanceClass(animInstance); } 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); //캡처를 Do_Action_Bow쪽으로 옮긴다. //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값을 사용한다. }
void ACAttachment_Bow::Tick(float DeltaTime)
- PoseableMesh->CopyPoseFromSkeletalComponent(SkeletalMesh);
- 캡처를 삭제(위의 코드 삭제)하고 Do_Action_Bow쪽으로 옮긴다.
CDoAction - OnBegineEquip(), OnUnequip() 함수 추가
CDoAction.h
#pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Weapons/CWeaponStructures.h" #include "CDoAction.generated.h" UCLASS(Abstract)//DoAction 그 자체로는 객체화되면 안 되기 때문에 Abstract을 붙여준다. class U2212_06_API UCDoAction : public UObject { GENERATED_BODY() public: UCDoAction(); virtual void BeginPlay //재정의 할 수 있도록 virtual로 만든다. ( class ACAttachment* InAttachment, class UCEquipment* InEquipment, class ACharacter* InOwner, const TArray<FDoActionData>& InDoActionDatas,//CWeaponStucture내의 FDoActionData const TArray<FHitData>& InHitDatas //CWeaponStucture내의 FHitData ); virtual void Tick(float InDeltaTime) { } public: //재정의 할 수 있도록 virtual로 만든다. virtual void DoAction(); virtual void Begin_DoAction(); virtual void End_DoAction(); public: //BeginEquip될 때와 Unequip될 때 충돌체를 제거해줘야 한다. //CDoAction_Bow에서 재정의 시키기위해 virtual로 만든다. UFUNCTION() virtual void OnBeginEquip() { } UFUNCTION() virtual void OnUnequip() { } public: UFUNCTION() virtual void OnAttachmentBeginCollision() {} UFUNCTION() virtual void OnAttachmentEndCollision() {} UFUNCTION() virtual void OnAttachmentBeginOverlap(class ACharacter* InAttacker, AActor* InAttackCauser, class ACharacter* InOther) { } UFUNCTION() virtual void OnAttachmentEndOverlap(class ACharacter* InAttacker, class ACharacter* InOther) { } protected: bool bInAction; bool bBeginAction; class ACharacter* OwnerCharacter; class UWorld* World; class UCMovementComponent* Movement; class UCStateComponent* State; TArray<FDoActionData> DoActionDatas; TArray<FHitData> HitDatas; };
자식 클래스인 CDo_Action_Bow에서 재정의할 함수 추가
- UFUNCTION()
virtual void OnBeginEquip() { } - UFUNCTION()
virtual void OnUnequip() { }
CDoAction_Bow에서 재정의 시키기위해 virtual로 만든다. BeginEquip될 때와 Unequip될 때 충돌체를 제거해줘야 한다. 따라서 CDoAction_Bow에서 재정의할 때 OnBeginEquip()에 충돌을 꺼주고 OnUnequip() 시 충돌을 켜준다.
CDoAction.cpp
#include "Weapons/CDoAction.h" #include "Global.h" #include "CAttachment.h" #include "CEquipment.h" #include "GameFramework/Character.h" #include "Components/CStateComponent.h" #include "Components/CMovementComponent.h" UCDoAction::UCDoAction() { } void UCDoAction::BeginPlay(ACAttachment* InAttachment, UCEquipment* InEquipment, ACharacter* InOwner, const TArray<FDoActionData>& InDoActionDatas, const TArray<FHitData>& InHitDatas) { OwnerCharacter = InOwner; World = OwnerCharacter->GetWorld(); State = CHelpers::GetComponent<UCStateComponent>(OwnerCharacter); Movement = CHelpers::GetComponent<UCMovementComponent>(OwnerCharacter); DoActionDatas = InDoActionDatas; HitDatas = InHitDatas; } void UCDoAction::DoAction() { bInAction = true; State->SetActionMode(); } void UCDoAction::Begin_DoAction() { bBeginAction = true; } void UCDoAction::End_DoAction() { bInAction = false; bBeginAction = false; State->SetIdleMode(); Movement->Move(); Movement->DisableFixedCamera(); }
변경사항 없음.
CDoAction_Bow 생성
새 C++ 클래스 - CDoAction - CDoAction_Bow 생성


CDoAction_Bow.h
#pragma once #include "CoreMinimal.h" #include "Weapons/CDoAction.h" #include "CDoAction_Bow.generated.h" UCLASS(Blueprintable) class U2212_06_API UCDoAction_Bow : public UCDoAction { GENERATED_BODY() public: UCDoAction_Bow(); void BeginPlay ( class ACAttachment* InAttachment, class UCEquipment* InEquipment, class ACharacter* InOwner, const TArray<FDoActionData>& InDoActionData, const TArray<FHitData>& InHitData ) override; void DoAction() override; void Begin_DoAction() override; void End_DoAction() override; void OnBeginEquip() override; void OnUnequip() override; void Tick(float InDeltaTime) override; public: void End_BowString();//AnimNotify_BowString의 Notify에서 콜하여 사용한다. private: class USkeletalMeshComponent* SkeletalMesh; class UPoseableMeshComponent* PoseableMesh; private: float* Bending; private: FVector OriginLocation;//처음 위치 bool bAttachedString = true;//true면 활 시위가 손에 붙는다. private: const bool* bEquipped; };
CDoAction_Bow.cpp
#include "Weapons/DoActions/CDoAction_Bow.h" #include "Global.h" #include "Weapons/CEquipment.h" #include "Weapons/Attachments/CAttachment_Bow.h" #include "GameFramework/Character.h" #include "Components/PoseableMeshComponent.h" #include "Components/CStateComponent.h" #include "Components/CMovementComponent.h" UCDoAction_Bow::UCDoAction_Bow() { } void UCDoAction_Bow::BeginPlay(ACAttachment* InAttachment, UCEquipment* InEquipment, ACharacter* InOwner, const TArray<FDoActionData>& InDoActionData, const TArray<FHitData>& InHitData) { Super::BeginPlay(InAttachment, InEquipment, InOwner, InDoActionData, InHitData); SkeletalMesh = CHelpers::GetComponent<USkeletalMeshComponent>(InAttachment); PoseableMesh = CHelpers::GetComponent<UPoseableMeshComponent>(InAttachment); //CAnimInstance.h의 Bend변수를 CAttachment_Bow의 GetBend()함수를 거쳐 여기로 가져와서 사용한다. ACAttachment_Bow* bow = Cast<ACAttachment_Bow>(InAttachment); Bending = bow->GetBend(); OriginLocation = PoseableMesh->GetBoneLocationByName("bow_string_mid", EBoneSpaces::ComponentSpace); bEquipped = InEquipment->GetEquipped();//헤더에 만든 bEquipped변수에 장착 상태를 받아와서 넣어준다. } void UCDoAction_Bow::DoAction() { CheckFalse(State->IsIdleMode()); CheckFalse(State->IsSubActionMode()); Super::DoAction(); DoActionDatas[0].DoAction(OwnerCharacter); } void UCDoAction_Bow::Begin_DoAction()//활 발사 { Super::Begin_DoAction(); bAttachedString = false;//발사하면 활 시위가 손에서 떨어지도록 false로 만들어준다. *Bending = 0;//활 구부림 0으로 만들어준다. PoseableMesh->SetBoneLocationByName("bow_string_mid", OriginLocation, EBoneSpaces::ComponentSpace);//활 시위를 처음 위치로 돌아가게 만들어준다. } void UCDoAction_Bow::End_DoAction() { Super::End_DoAction(); } void UCDoAction_Bow::OnBeginEquip() { Super::OnBeginEquip(); OwnerCharacter->GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);//충돌을 꺼준다. } void UCDoAction_Bow::OnUnequip() { Super::OnUnequip(); *Bending = 0;//활 시위 휘어지는 Bending을 0으로 만든다. OwnerCharacter->GetMesh()->SetCollisionEnabled(ECollisionEnabled::QueryOnly);//충돌을 켜준다. PoseableMesh->SetBoneLocationByName("bow_string_mid", OriginLocation, EBoneSpaces::ComponentSpace);//활 시위를 처음 상태로 돌려준다. } void UCDoAction_Bow::Tick(float InDeltaTime) { Super::Tick(InDeltaTime); PoseableMesh->CopyPoseFromSkeletalComponent(SkeletalMesh); bool bCheck = true; bCheck &= (*bEquipped == true);//장착 상태여야 한다. bCheck &= (bBeginAction == false);//BeginAction이면(활 발사) 활 시위가 붙으면 안되므로 false여야 한다. bCheck &= (bAttachedString == true);//활 시위 붙는게 true여야 한다. CheckFalse(bCheck); FVector handLocation = OwnerCharacter->GetMesh()->GetSocketLocation("Hand_Bow_Right"); PoseableMesh->SetBoneLocationByName("bow_string_mid", handLocation, EBoneSpaces::WorldSpace); } void UCDoAction_Bow::End_BowString() { *Bending = 100;//활 시위를 땡겨 다시 휘어지게 만들어진다. bAttachedString = true;//활 시위가 손에 붙는다. }
AR_ShootAndDraw_Montage 생성
AR_ShootAndDraw

AR_ShootAndDraw_Montage

Begin DoAction: 활 발사
End_DoAction: 활 시위가 안 휘어지게 Bend를 0으로 만든다. 활 시위와 손이 떨어지게 만든다.
End_BowString: 활 시위가 휘어지게 Bend를 100으로 만든다. 활 시위를 손에 붙인다.
ABP_Character

기존에 만든부분을 Bose Pose로 저장한다.
BowBody 슬롯을 만든다.
- '본마다 레이어로 블랜딩합니다'으로 구분한다.
DA_Bow에 DoAction Class와 DoAction Data 할당

CEquipment - 델리게이트 추가
CEquipment.h
#pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Weapons/CWeaponStructures.h" #include "CEquipment.generated.h" //직렬화하여 BP에서 사용가능하도록 DYNAMIC, 여러함수를 받을 수 있도록 MULTICAST 사용. DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentEquip); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentBeginEquip); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentUnequip); UCLASS() class U2212_06_API UCEquipment : public UObject { GENERATED_BODY() public: //실시간으로 bEquipped로 가져온다. 주소로 가져온다. FORCEINLINE const bool* GetEquipped() { return &bEquipped; } public: void BeginPlay(class ACharacter* InOwner, const FEquipmentData& InData); public: UFUNCTION(BlueprintNativeEvent)//필요시 BP에서 재정의하기 위해 BlueprintNativeEvent사용. void Equip(); void Equip_Implementation(); UFUNCTION(BlueprintNativeEvent) void Begin_Equip(); void Begin_Equip_Implementation(); UFUNCTION(BlueprintNativeEvent) void End_Equip(); void End_Equip_Implementation(); UFUNCTION(BlueprintNativeEvent) void Unequip(); void Unequip_Implementation(); public: FEquipmentEquip OnEquipmentEquip;//DECLARE_DYNAMIC_MULTICAST_DELEGATE 하였다. FEquipmentBeginEquip OnEquipmentBeginEquip;//DECLARE_DYNAMIC_MULTICAST_DELEGATE 하였다. FEquipmentUnequip OnEquipmentUnequip;//DECLARE_DYNAMIC_MULTICAST_DELEGATE 하였다. private: class ACharacter* OwnerCharacter; FEquipmentData Data; private: class UCMovementComponent* Movement; class UCStateComponent* State; private: bool bBeginEquip;//Equip이 시작되었는가 확인 bool bEquipped; //Equip이 완료되었는지 확인 };
델리게이트 추가
- DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentEquip);
- 직렬화하여 BP에서 사용가능하도록 DYNAMIC, 여러함수를 받을 수 있도록 MULTICAST 사용.
변수 추가
- FEquipmentEquip OnEquipmentEquip;
- 위에 추가한 DECLARE_DYNAMIC_MULTICAST_DELEGATE에 변수로 사용하였다.
인라인 함수 추가
- FORCEINLINE const bool* GetEquipped() { return &bEquipped; }
- 실시간으로 bEquipped로 가져온다. 주소로 가져온다.
CEquipment.cpp
#include "Weapons/CEquipment.h" #include "Global.h" #include "GameFramework/Character.h" #include "Components/CMovementComponent.h" #include "Components/CStateComponent.h" #include "CEquipment.h" void UCEquipment::BeginPlay(ACharacter* InOwner, const FEquipmentData& InData) { OwnerCharacter = InOwner; Data = InData; Movement = CHelpers::GetComponent<UCMovementComponent>(InOwner); State = CHelpers::GetComponent<UCStateComponent>(InOwner); } void UCEquipment::Equip_Implementation() { State->SetEquipMode(); if (OnEquipmentEquip.IsBound())//활 장착 확인? OnEquipmentEquip.Broadcast(); if (Data.bCanMove == false) Movement->Stop(); if (Data.bUseControlRotation) Movement->EnableControlRotation(); if (!!Data.Montage) { OwnerCharacter->PlayAnimMontage(Data.Montage, Data.PlayRate); } else { Begin_Equip(); End_Equip(); } } void UCEquipment::Begin_Equip_Implementation() { bBeginEquip = true; if (OnEquipmentBeginEquip.IsBound()) OnEquipmentBeginEquip.Broadcast(); } void UCEquipment::End_Equip_Implementation() { bBeginEquip = false; bEquipped = true; Movement->Move(); State->SetIdleMode(); } void UCEquipment::Unequip_Implementation() { bEquipped = false; Movement->DisableControlRotation(); if (OnEquipmentUnequip.IsBound()) OnEquipmentUnequip.Broadcast(); }
void UCEquipment::Equip_Implementation()
- if (OnEquipmentEquip.IsBound())
OnEquipmentEquip.Broadcast();- isBound() 함수는 delegate가 현재 bind되어 있는지 확인하는 함수이고, broadcast() 함수는 delegate를 호출하는 함수다.
CWeaponAsset
CWeaponAsset.h
#pragma once #include "CoreMinimal.h" #include "Engine/DataAsset.h" #include "Weapons/CWeaponStructures.h" #include "CWeaponAsset.generated.h" UCLASS() class U2212_06_API UCWeaponAsset : public UDataAsset { GENERATED_BODY() private: UPROPERTY(EditAnywhere) TSubclassOf<class ACAttachment> AttachmentClass; UPROPERTY(EditAnywhere) FEquipmentData EquipmentData; UPROPERTY(EditAnywhere) TSubclassOf<class UCEquipment> EquipmentClass; UPROPERTY(EditAnywhere) TSubclassOf<class UCDoAction> DoActionClass; UPROPERTY(EditAnywhere) TArray<FDoActionData> DoActionDatas; //CWeaopnStructure내의 FDoActionData UPROPERTY(EditAnywhere) TArray<FHitData> HitDatas; //CWeaopnStructure내의 FHitData UPROPERTY(EditAnywhere) TSubclassOf<class UCSubAction> SubActionClass; public: FORCEINLINE class ACAttachment* GetAttachment() { return Attachment; }//외부에 생성된 것을 리턴해줌. FORCEINLINE class UCEquipment* GetEquipment() { return Equipment; }//외부에 생성된 것을 리턴해줌. FORCEINLINE class UCDoAction* GetDoAction() { return DoAction; }//외부에 생성된 것을 리턴해줌. FORCEINLINE class UCSubAction* GetSubAction() { return SubAction; }//외부에 생성된 것을 리턴해줌. public: UCWeaponAsset(); void BeginPlay(class ACharacter* InOwner); private: //UPROPERTY를 붙여 가비지 콜렉터가 제거하기 전까지 물고 있게 만든다. //UWeaponAsset은 UObject로부터 상속받아 Actor의 생성주기에 영향을 받지 않아 가비지 콜렉터에 영향을 받는다. UPROPERTY() class ACAttachment* Attachment; UPROPERTY() class UCEquipment* Equipment; UPROPERTY() class UCDoAction* DoAction; UPROPERTY() class UCSubAction* SubAction; #if WITH_EDITOR //Editor 내에서만 수행 void PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent) override; #endif };
변경사항 없음
CWeaponAsset.cpp
#include "Weapons/CWeaponAsset.h" #include "Global.h" #include "CAttachment.h" #include "CEquipment.h" #include "CDoAction.h" #include "CSubAction.h" #include "GameFramework/Character.h" UCWeaponAsset::UCWeaponAsset() { AttachmentClass = ACAttachment::StaticClass();//기본값 EquipmentClass = UCEquipment::StaticClass();//기본값 } void UCWeaponAsset::BeginPlay(ACharacter* InOwner) { if (!!AttachmentClass)//AttachmentClass가 선택되어 있다면 { FActorSpawnParameters params; params.Owner = InOwner; Attachment = InOwner->GetWorld()->SpawnActor<ACAttachment>(AttachmentClass, params); } if (!!EquipmentClass)//EquipmentClass가 선택되어 있다면 { Equipment = NewObject<UCEquipment>(this, EquipmentClass); Equipment->BeginPlay(InOwner, EquipmentData); if (!!Attachment)//Attachment가 있다면 { Equipment->OnEquipmentBeginEquip.AddDynamic(Attachment, &ACAttachment::OnBeginEquip); Equipment->OnEquipmentUnequip.AddDynamic(Attachment, &ACAttachment::OnUnequip); } } if(!!DoActionClass) { DoAction = NewObject<UCDoAction>(this, DoActionClass); DoAction->BeginPlay(Attachment, Equipment, InOwner, DoActionDatas, HitDatas); if (!!Attachment) { Attachment->OnAttachmentBeginCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginCollision); Attachment->OnAttachmentEndCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndCollision); Attachment->OnAttachmentBeginOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginOverlap); Attachment->OnAttachmentEndOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndOverlap); } if (!!Equipment)//Bow_String 작업 { Equipment->OnEquipmentBeginEquip.AddDynamic(DoAction, &UCDoAction::OnBeginEquip); Equipment->OnEquipmentUnequip.AddDynamic(DoAction, &UCDoAction::OnUnequip); } } if(!!SubActionClass) { SubAction = NewObject<UCSubAction>(this, SubActionClass); SubAction->BeginPlay(InOwner, Attachment, DoAction); } } #if WITH_EDITOR //Editor 내에서만 수행 void UCWeaponAsset::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) { Super::PostEditChangeChainProperty(PropertyChangedEvent); CheckTrue(FApp::IsGame());//게임이 실행중이면 실행하면 안 되기 때문에 체크 bool bRefresh = false; bRefresh |= PropertyChangedEvent.GetPropertyName().Compare("DoActionDatas") == 0; bRefresh |= PropertyChangedEvent.GetPropertyName().Compare("HitDatas") == 0;//수정하려는 변수명 == 0 이면 이름이 동일하다는 의미. if (bRefresh) { bool bCheck = false; bCheck |= PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayAdd; bCheck |= PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayRemove; bCheck |= PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayClear; bCheck |= PropertyChangedEvent.ChangeType == EPropertyChangeType::Duplicate; if (bCheck) { FPropertyEditorModule& prop = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");//WITH_EDITOR로 Editor 내에서 수행하기 때문에 사용 가능. TSharedPtr<IDetailsView> detailsView = prop.FindDetailView("WeaponAssetEditorDetailsView");//WeaponAssetEditor.cpp에서 설정한 arg.ViewIdentifier이름 WeaponAssetEditorDetailsView 사용. WeaponAssetEditorDetailsView를 찾는다. if (detailsView.IsValid())//detailsView 창이 그려졌다면 detailsView->ForceRefresh();//새로고침 } } } #endif
함수 내용 추가
void UCWeaponAsset::BeginPlay(ACharacter* InOwner)
- if(!!DoActionClass) //DoAction 클래스가 있다면
- if (!!Equipment) //Equipment가 true라면
- Equipment->OnEquipmentBeginEquip.AddDynamic(DoAction, &UCDoAction::OnBeginEquip);
- Equipment->OnEquipmentUnequip.AddDynamic(DoAction, &UCDoAction::OnUnequip);
- OnBegineEquip과 OnUnequip함수를 델리게이트 연결처리해준다.
- if (!!Equipment) //Equipment가 true라면
CAnimNotify_BowString 생성
새 C++ 클래스- AnimNotify - CAnimNotify_BowString 생성


CAnimNotify_BowString.h
#pragma once #include "CoreMinimal.h" #include "Animation/AnimNotifies/AnimNotify.h" #include "CAnimNotify_BowString.generated.h" UCLASS() class U2212_06_API UCAnimNotify_BowString : public UAnimNotify { GENERATED_BODY() public: FString GetNotifyName_Implementation() const override; void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override; };
CAnimNotify_BowString.cpp
#include "Notifies/CAnimNotify_BowString.h" #include "Global.h" #include "Components/CWeaponComponent.h" #include "Weapons/DoActions/CDoAction_Bow.h" FString UCAnimNotify_BowString::GetNotifyName_Implementation() const { return "End_BowString"; } void UCAnimNotify_BowString::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) { Super::Notify(MeshComp, Animation); CheckNull(MeshComp); CheckNull(MeshComp->GetOwner()); UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(MeshComp->GetOwner()); CheckNull(weapon); CheckNull(weapon->GetDoAction()); UCDoAction_Bow* bow = Cast<UCDoAction_Bow>(weapon->GetDoAction()); CheckNull(bow); bow->End_BowString();//CDoAction_Bow의 End_BowString을 콜하여 활 시위를 휘게 만들고 손에 붙인다. }
실행화면


'⭐ Unreal Engine > UE RPG Skill' 카테고리의 다른 글
[UE] 파쿠르 구현하기 (0) | 2023.07.18 |
---|---|
[UE] 화살 (0) | 2023.07.13 |
[UE] 활 시위 당기기 (0) | 2023.07.07 |
[UE] 활 조준 (0) | 2023.07.06 |
[UE] 활 구현하기 (0) | 2023.07.05 |
댓글
이 글 공유하기
다른 글
-
[UE] 파쿠르 구현하기
[UE] 파쿠르 구현하기
2023.07.18 -
[UE] 화살
[UE] 화살
2023.07.13 -
[UE] 활 시위 당기기
[UE] 활 시위 당기기
2023.07.07 -
[UE] 활 조준
[UE] 활 조준
2023.07.06
댓글을 사용할 수 없습니다.