필요한 개념
<무기 선택에 따라 캐릭터 Material 색 바꿔놓기>
플레이어와 적에게도 모두 색 변경을 할것임 -> 인터페이스(Unreal Interface)로 만드는 것이 좋다.
* UnrealInterface를 상속받는 ICharacter만듬
// 이 함수로 순수가상함수로 해서 정의 및 구현하도록 강제함
virtual void ChangeColor(FLinearColor InColor) = 0;
* CEquipment의 데이터를 관리하는 것이 UDataAsset 상속받는 CActionData여서 CActionData에 색 변수를 추가한다.
UPROPERTY(BlueprintReadOnly, EditAnywhere)
FLinearColor EquipmentColor;
// CEquipment.cpp
void ACEquipment::Equip_Implementation()
{
// IICharacter로 캐스팅 가능하다면 색이 있다는 얘기
IICharacter* character = Cast<IICharacter>(OwnerCharacter);
CheckNull(character);
character->ChangeColor(Color);
}
// CActionData.cpp
Equipment->SetColor(EquipmentColor);
<Unarmed때는 원래의 색으로 돌아올 수 있게 만듬>
* DA_Unarmed 생성
Unarmed는 무기가 따로 없어서, 결국 Unarmed도 DataAsset을 만들어서
Attachment를 None으로 하고 EquipmentClass는 기본 클래스로 둔다.
// CActionComponent.cpp
void UCActionComponent::SetUnarmedMode()
{
// 이미 무기가 장착되어 있다면 해제하고
if (!!Datas[(int32)Type])
{
ACEquipment* equipment = Datas[(int32)Type]->GetEquipment();
if (!!equipment)
equipment->Unequip();
}
// 이제 UnamedMode도 장비가 있는 것으로 처리된다.
ACEquipment* equipment = Datas[(int32)EActionType::Unarmed]->GetEquipment();
CheckNull(equipment);
// 색바꾸기 위해(Unarmed도 장비가 있는 것으로 바꿈)
equipment->Equip();
ChangeType(EActionType::Unarmed);
}
* BP_CPlayer ActionComponent 변수에 DA_Unarmed 세팅해준다.
* Attachment Spawn해줄때 AttachmentClass, EquipmentClass, DoActionClass Null체크 해줌
Why?)
Unarmed의 경우에는 따로 Attachment가 없기 때문에, None으로 들어올 것이고, 이에 대해 Null 체크가 필요함
// CActionData.cpp
ex) if (!!AttachmentClass) // 있을 경우만 실행
Tip)
언리얼도 BreakPoint 거는거 기존 하던거랑 똑같다.
BreakPoint걸고 F5누르면 됨
그 상태에서 새로운 창이 뜨게 되고 게임 플레이누르고 플레이하면 BreakPoint에 걸린다.
새로뜬 창에서 값 수정하면 기존값 수정하면 안됨, 기존꺼에 영향미침
값만 확인 후에 Shift+F5로 디버깅모드 중지해야함
만약 디버깅모드에서 BreakPoint가 걸리지 않는다면
언리얼엔진과 VisualStudio 모두 끄고, 다시 열면 정상 작동함
* 이제 UnamedMode도 무기가 됨, CPlayer에서 시작때 UnamedMode로 세팅해준다.
이전 까지는 Unarmed로 세팅하면 에러가 있었음, 그런데 이제는 Unarmed도 무기가 되어서 상관이 없다.
// CPlayer.cpp
void ACPlayer::BeginPlay()
{
...
Action->SetUnarmedMode();
}
CPlayer.h 추가된 내용
#pragma once
...
#include "Characters/ICharacter.h"
UCLASS()
class UONLINE_04_ACTION_API ACPlayer : public ACharacter, public IICharacter
{
GENERATED_BODY()
...
public:
virtual void ChangeColor(FLinearColor InColor) override;
private:
class UMaterialInstanceDynamic* BodyMaterial;
class UMaterialInstanceDynamic* LogoMaterial;
};
CPlayer.cpp 추가된 내용
...
#include "Materials/MaterialInstanceConstant.h"
#include "Materials/MaterialInstanceDynamic.h"
void ACPlayer::BeginPlay()
{
Super::BeginPlay();
...
UMaterialInstanceConstant* body;
UMaterialInstanceConstant* logo;
CHelpers::GetAssetDynamic(&body, "MaterialInstanceConstant'/Game/Materials/M_UE4Man_Body_Inst.M_UE4Man_Body_Inst'");
CHelpers::GetAssetDynamic(&logo, "MaterialInstanceConstant'/Game/Materials/M_UE4Man_ChestLogo_Inst.M_UE4Man_ChestLogo_Inst'");
BodyMaterial = UMaterialInstanceDynamic::Create(body, this);
LogoMaterial = UMaterialInstanceDynamic::Create(logo, this);
GetMesh()->SetMaterial(0, BodyMaterial);
GetMesh()->SetMaterial(1, LogoMaterial);
Action->SetUnarmedMode();
}
void ACPlayer::ChangeColor(FLinearColor InColor)
{
BodyMaterial->SetVectorParameterValue("BodyColor", InColor);
LogoMaterial->SetVectorParameterValue("BodyColor", InColor);
}
ICharacter.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ICharacter.generated.h"
UINTERFACE(MinimalAPI)
class UICharacter : public UInterface
{
GENERATED_BODY()
};
class UONLINE_04_ACTION_API IICharacter
{
GENERATED_BODY()
public:
virtual void ChangeColor(FLinearColor InColor) = 0;
};
CActionData.h 추가된 내용
UCLASS()
class UONLINE_04_ACTION_API UCActionData : public UDataAsset
{
GENERATED_BODY()
public:
...
FORCEINLINE FLinearColor GetEquipmentColor() { return EquipmentColor; }
public:
UPROPERTY(BlueprintReadOnly, EditAnywhere)
FLinearColor EquipmentColor;
private:
// 이름 출력해 줄 애
FString GetLableName(class ACharacter* InOwnerCharacter, FString InName);
};
CActionData.cpp 수정된 내용
...
void UCActionData::BeginPlay(class ACharacter* InOwnerCharacter)
{
FTransform transform;
if (!!AttachmentClass)
{
// 등장만 시켜놈
Attachment = InOwnerCharacter->GetWorld()->SpawnActorDeferred<ACAttachment>(AttachmentClass, transform, InOwnerCharacter);
Attachment->SetActorLabel(GetLableName(InOwnerCharacter, "Attachment"));
// 어디에 붙일지는 CAttachment의 OnEquip()때 결정
// Attachment->AttachToComponent(InOwnerCharacter->GetMesh(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, true));
UGameplayStatics::FinishSpawningActor(Attachment, transform);
}
if (!!EquipmentClass)
{
// 객체 생성만 완료됨, 등장은 안 시킴
// 여기서 transform은 확정시키지 않으면 BeginPlay()가 끝나면 확정이 됨, 그때 등장할 위치
Equipment = InOwnerCharacter->GetWorld()->SpawnActorDeferred<ACEquipment>(EquipmentClass, transform, InOwnerCharacter);
// mesh에다가 붙여넣음
Equipment->AttachToComponent(InOwnerCharacter->GetMesh(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, true));
// 할당 받은 데이터를 Equipment로 넘겨줌
Equipment->SetActorLabel(GetLableName(InOwnerCharacter, "Equipment"));
Equipment->SetData(EquipmentData);
Equipment->SetColor(EquipmentColor);
// FinishSpawningActor() : 확정해 등장시킬 액터와 Transform을 입력
// transform : 확정되서 등장시킬 위치
UGameplayStatics::FinishSpawningActor(Equipment, transform);
if (!!Attachment)
{
// 연결해줌
Equipment->OnEquipmentDelegate.AddDynamic(Attachment, &ACAttachment::OnEquip);
Equipment->OnUnequipmentDelegate.AddDynamic(Attachment, &ACAttachment::OnUnequip);
}
}
if(!!DoActionClass)
{
DoAction = InOwnerCharacter->GetWorld()->SpawnActorDeferred<ACDoAction>(DoActionClass, transform, InOwnerCharacter);
DoAction->AttachToComponent(InOwnerCharacter->GetMesh(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, true));
DoAction->SetActorLabel(GetLableName(InOwnerCharacter, "DoAction"));
DoAction->SetDatas(DoActionDatas);
UGameplayStatics::FinishSpawningActor(DoAction, transform);
}
}
FString UCActionData::GetLableName(class ACharacter* InOwnerCharacter, FString InName)
{
FString str;
str.Append(InOwnerCharacter->GetActorLabel());
str.Append("_");
str.Append(InName);
str.Append("_");
// DataAsset은 DA로 world에 나타나는데 DA_를 없앰
str.Append(GetName().Replace(L"DA_", L""));
return str;
}
CEquipment.h 추가된 내용
#pragma once
...
UCLASS()
class UONLINE_04_ACTION_API ACEquipment : public AActor
{
GENERATED_BODY()
public:
...
FORCEINLINE void SetColor(FLinearColor InColor) { Color = InColor; }
private:
// 무기에 따른 캐릭터 색
FLinearColor Color;
};
CEquipment.cpp 추가된 내용
...
void ACEquipment::Equip_Implementation()
{
...
// IICharacter로 캐스팅 가능하다면 색이 있다는 얘기
IICharacter* character = Cast<IICharacter>(OwnerCharacter);
CheckNull(character);
character->ChangeColor(Color);
}
CActionComponent.cpp 수정된 내용
void UCActionComponent::SetUnarmedMode()
{
// 이미 무기가 장착되어 있다면 해제하고
if (!!Datas[(int32)Type])
{
ACEquipment* equipment = Datas[(int32)Type]->GetEquipment();
if (!!equipment)
equipment->Unequip();
}
// 이제 UnamedMode도 장비가 있는 것으로 처리된다.
ACEquipment* equipment = Datas[(int32)EActionType::Unarmed]->GetEquipment();
CheckNull(equipment);
// 색바꾸기 위해(Unarmed도 장비가 있는 것으로 바꿈)
equipment->Equip();
ChangeType(EActionType::Unarmed);
}
결과
'Unreal Engine 4 > C++' 카테고리의 다른 글
<Unreal C++> 50 - Action RPG (Enemy UI) (0) | 2022.05.16 |
---|---|
<Unreal C++> 48 - Action RPG (Create Enemy & Collision) (0) | 2022.05.16 |
<Unreal C++> 46 - Action RPG (Melee Attack Combo) (0) | 2022.05.16 |
<Unreal C++> 44 - Action RPG(CAction & Melee Attack) (0) | 2022.05.09 |
<Unreal C++> 43 - Action RPG(Weapon Attachment) (0) | 2022.05.09 |