[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