[ 몬스터 상태 정보 ]
- 몬스터 상태 정보 구조체 생성 -
(C++-Monster.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "SpawnPoint.h"
#include "GameFramework/Character.h"
#include "Monster.generated.h"
// 공격이 종료되었을때 호출될 함수를 등록할 델리게이트를 만들어준다.
DECLARE_MULTICAST_DELEGATE(FOnAttackEndDelegate)
USTRUCT(Atomic, BlueprintType)
struct FMonsterState
{
GENERATED_USTRUCT_BODY()
public:
FMonsterState()
{
}
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
float fAttack;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
float fArmor;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
int32 iHP;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
int32 iHPMax;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
int32 iMP;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
int32 iMPMax;
};
UCLASS()
class UE7PROJECT_API AMonster : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMonster();
~AMonster();
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
ASpawnPoint* SpawnPoint;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
float fTraceRange;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
float fAttackDist;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
TArray<APatrolPoint*> PatrolPointArray;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
FMonsterState MonsterState;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
FName MonsterName;
int32 iMovePoint;
int32 iMovePointDir;
bool bAttack;
FOnAttackEndDelegate OnAttackEnd;
TArray<FDelegateHandle> AttackEndHandle;
public:
void AddPatrolPoint(APatrolPoint* point);
int32 GetPatrolPointCount() const
{
return PatrolPointArray.Num();
}
APatrolPoint* GetPatrolPoint()
{
return PatrolPointArray[iMovePoint];
}
void NextPatrolPoint()
{
iMovePoint += iMovePointDir;
if (iMovePoint == PatrolPointArray.Num())
{
iMovePointDir = -1;
iMovePoint = PatrolPointArray.Num() - 2;
}
else if (iMovePoint == -1)
{
iMovePointDir = 1;
iMovePoint = 0;
}
}
public:
template <typename T>
void AddAttackEndDelegate(T* pObj, void(T::* pFunc)())
{
FDelegateHandle handle = OnAttackEnd.AddUObject(pObj, pFunc);
AttackEndHandle.Add(handle);
}
public:
float GetTraceRange() const
{
return fTraceRange;
}
float GetAttackDistance() const
{
return fAttackDist;
}
void Attack()
{
bAttack = true;
}
bool IsAttack() const
{
return bAttack;
}
public:
void SetSpawnPoint(ASpawnPoint* Point)
{
SpawnPoint = Point;
}
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
public:
virtual void ChangeAnim(EMonsterAnim eAnim);
public:
void AttackEnd();
};
- GameInstance 생성 -
(언리얼 에디터) C++클래스 -> 우클릭_새 C++클래스 -> 부모 클래스 : "GameInstance" 이름 : "UE7GameInstance"
(C++-GameInfo.h)
#pragma once
#include "EngineMinimal.h"
#include "EngineGlobals.h"
#include "DestructibleComponent.h"
#include "Engine.h"
#include "Engine/AssetManager.h"
#include "Runtime/Engine/Classes/Engine/GameEngine.h"
#include "Blueprint/AIBlueprintHelperLibrary.h"
#include "NavigationSystem/Public/NavigationPath.h"
#include "Engine/DataTable.h" // 추가.
...
(C++-UE7GameInstance.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameInfo.h"
#include "Engine/GameInstance.h"
#include "UE7GameInstance.generated.h"
USTRUCT(BlueprintType)
struct FMonsterInfo :
public FTableRowBase
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
float Attack;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
float Armor;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
int32 HP;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
int32 HPMax;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
int32 MP;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
int32 iMPMax;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
float TraceRange;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
float AttackRange;
};
UCLASS()
class UE7PROJECT_API UUE7GameInstance : public UGameInstance
{
GENERATED_BODY()
public:
UUE7GameInstance();
~UUE7GameInstance();
private:
UPROPERTY()
UDataTable* MonsterInfoTable;
protected:
virtual void Init();
public:
const FMonsterInfo* FindMonsterInfo(const FName& key) const;
};
(C++-UE7GameInstance.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "UE7GameInstance.h"
UUE7GameInstance::UUE7GameInstance()
{
static ConstructorHelpers::FObjectFinder<UDataTable> MonsterInfoAsset(TEXT("DataTable'/Game/Monster/MonsterInfo.MonsterInfo'"));
if (MonsterInfoAsset.Succeeded())
MonsterInfoTable = MonsterInfoAsset.Object;
}
UUE7GameInstance::~UUE7GameInstance()
{
}
void UUE7GameInstance::Init()
{
Super::Init();
}
const FMonsterInfo* UUE7GameInstance::FindMonsterInfo(const FName& key) const
{
if (!IsValid(MonsterInfoTable))
return nullptr;
return MonsterInfoTable->FindRow<FMonsterInfo>(key, TEXT(""));
}
(언리얼 에디터) 세팅-프로젝트 세팅 -> 프로젝트-맵&모드-게임 인스턴스 클래스 : "UE7GameInstance"
// 게임 인스턴스 클래스 : GameInstance : 프로젝트 세팅에 들어와있는 클래스로 프로젝트에서 한 개만 생성이 됨.
- 데이터 테이블 -
// 언리얼에서 데이터 테이블 생성.
(언리얼 에디터) Monster -> 우클릭_기타-데이터 테이블 -> 행 구조체 : "MonsterInfo" 이름 : "MonsterInfoTable"
(언리얼 에디터-MonsterInfoTable) 추가 -> 행이름 및 세부 정보 설정
// 설정된 정보는 구조체에 들어가게 됨.
// 엑셀 파일을 사용해서 생성.
(언리얼 에디터) MonsterInfoTable -> 우클릭_CSV로 익스포트 -> 원하는 위치에 생성
// 생성된 엑셀 파일을 수정해서 정보를 넣을 수 있음.
(언리얼 에디터) 생성한 엑셀 파일을 언리얼 에디터 Monster에 드래그
(언리얼 에디터) 임포트 대상 : Data Table
(언리얼 에디터) 데이터 테이블 행 유형 선택 : MonsterInfo
(C++-Monster.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "Monster.h"
#include "UE7GameInstance.h"
// Sets default values
AMonster::AMonster()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
SpawnPoint = nullptr;
bAttack = false;
GetCapsuleComponent()->SetCollisionProfileName(TEXT("Monster"));
GetMesh()->SetReceivesDecals(false);
fTraceRange = 1000.f;
fAttackDist = 200.f;
iMovePoint = 0;
iMovePointDir = 1;
}
AMonster::~AMonster()
{
if (SpawnPoint)
SpawnPoint->Respawn();
}
void AMonster::AddPatrolPoint(APatrolPoint* point)
{
PatrolPointArray.Add(point);
}
// Called when the game starts or when spawned
void AMonster::BeginPlay()
{
Super::BeginPlay();
UUE7GameInstance* GameInst = GetGameInstance<UUE7GameInstance>();
const FMonsterInfo* pMonsterInfo = GameInst->FindMonsterInfo(MonsterName);
if (pMonsterInfo)
{
/*
float fAttack;
float fArmor;
int32 iHP;
int32 iHPMax;
int32 iMP;
int32 iMPMax;
*/
MonsterState.fAttack = pMonsterInfo->Attack;
MonsterState.fArmor = pMonsterInfo->Armor;
MonsterState.iHP = pMonsterInfo->HP;
MonsterState.iHPMax = pMonsterInfo->HPMax;
MonsterState.iMP = pMonsterInfo->MP;
MonsterState.iMPMax = pMonsterInfo->iMPMax;
fTraceRange = pMonsterInfo->TraceRange;
fAttackDist = pMonsterInfo->AttackRange;
}
}
...
(C++-Minion.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "Minion.h"
#include "MinionAnim.h"
AMinion::AMinion()
{
PrimaryActorTick.bCanEverTick = true;
static ConstructorHelpers::FObjectFinder<USkeletalMesh> MeshAsset(TEXT("SkeletalMesh'/Game/ParagonMinions/Characters/Minions/Down_Minions/Meshes/Minion_Lane_Melee_Core_Dawn.Minion_Lane_Melee_Core_Dawn'"));
if (MeshAsset.Succeeded())
GetMesh()->SetSkeletalMesh(MeshAsset.Object);
// AnimInstance 설정
static ConstructorHelpers::FClassFinder<UMinionAnim> AnimAsset(TEXT("AnimBlueprint'/Game/Monster/BPMinionAnim.BPMinionAnim_C'"));
if (AnimAsset.Succeeded())
GetMesh()->SetAnimInstanceClass(AnimAsset.Class);
GetMesh()->SetRelativeLocation(FVector(0.f, 0.f, -70.f));
GetMesh()->SetRelativeRotation(FRotator(0.f, -90.f, 0.f));
fAttackDist = 200.f;
MonsterName = TEXT("Minion"); // 이름 설정.
}
...
(C++-MinionRanger.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "MinionRanger.h"
#include "MinionRangerAnim.h"
AMinionRanger::AMinionRanger()
{
PrimaryActorTick.bCanEverTick = true;
static ConstructorHelpers::FObjectFinder<USkeletalMesh> MeshAsset(TEXT("SkeletalMesh'/Game/ParagonMinions/Characters/Minions/Down_Minions/Meshes/Minion_Lane_Ranged_Core_Dawn.Minion_Lane_Ranged_Core_Dawn'"));
if (MeshAsset.Succeeded())
GetMesh()->SetSkeletalMesh(MeshAsset.Object);
// AnimInstance 설정
static ConstructorHelpers::FClassFinder<UMinionRangerAnim> AnimAsset(TEXT("AnimBlueprint'/Game/Monster/BPMinionRangerAnim.BPMinionRangerAnim_C'"));
if (AnimAsset.Succeeded())
GetMesh()->SetAnimInstanceClass(AnimAsset.Class);
GetMesh()->SetRelativeLocation(FVector(0.f, 0.f, -70.f));
GetMesh()->SetRelativeRotation(FRotator(0.f, -90.f, 0.f));
fAttackDist = 500.f;
MonsterName = TEXT("MinionRanger"); // 이름 설정.
}
...
- 플레이어 무기와 몬스터 충돌 처리 오류 해결 -
(언리얼 에디터-BPWukong) WeaponBox -> 디테일-콜리전-Collision Presets : "PlayerAttack"
(언리얼 에디터) 세팅-프로젝트 세팅 -> 엔진-콜리전 -> Preset-Monster : Player, Monster : "무시" PlayerAttack : "겹칩" 나머지 : "블록"
(언리얼 에디터) 세팅-프로젝트 세팅 -> 엔진-콜리전 -> Preset-PlayerAttack : Player, PlayerAttack : "무시" Monster : "겹침" 나머지 : "블록"
- 데미지 처리 -
(언리얼 에디터-BPMinionAnim) Death_A : 노티파이 추가 : "DeathEnd"
(C++-Monster.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "SpawnPoint.h"
#include "GameFramework/Character.h"
#include "Monster.generated.h"
...
UCLASS()
class UE7PROJECT_API AMonster : public ACharacter
{
GENERATED_BODY()
...
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser);
public:
virtual void ChangeAnim(EMonsterAnim eAnim);
public:
void AttackEnd();
void Death();
};
(C++-Monster.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "Monster.h"
#include "UE7GameInstance.h"
#include "MonsterAIController.h"
#include "BehaviorTree/BehaviorTreeComponent.h"
...
// Called to bind functionality to input
void AMonster::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
float AMonster::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float fDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
MonsterState.iHP -= (int32)fDamage;
if (MonsterState.iHP <= 0) // 죽었을 경우.
{
MonsterState.iHP = 0;
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
ChangeAnim(EMonsterAnim::Death);
AMonsterAIController* MonsterController = GetController<AMonsterAIController>();
if (IsValid(MonsterController))
{
UBehaviorTreeComponent* BT = Cast<UBehaviorTreeComponent>(MonsterController->GetBrainComponent());
if (IsValid(BT))
BT->StopTree();
}
}
return fDamage;
}
void AMonster::ChangeAnim(EMonsterAnim eAnim)
{
}
void AMonster::AttackEnd()
{
bAttack = false;
OnAttackEnd.Broadcast();
for (FDelegateHandle& handle : AttackEndHandle)
{
OnAttackEnd.Remove(handle);
}
}
void AMonster::Death()
{
if (IsValid(SpawnPoint))
SpawnPoint->Respawn();
Destroy();
}
(C++-MinionAnim.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameInfo.h"
#include "Animation/AnimInstance.h"
#include "MinionAnim.generated.h"
...
public:
UFUNCTION()
void AnimNotify_AttackEnd();
UFUNCTION()
void AnimNotify_DeathEnd();
};
(C++-MinionAnim.cpp)
...
void UMinionAnim::ChangeAnim(EMonsterAnim eAnim)
{
AnimType = (uint8)eAnim;
}
void UMinionAnim::AnimNotify_AttackEnd()
{
AMinion* pOwner = Cast<AMinion>(TryGetPawnOwner());
if (IsValid(pOwner))
pOwner->AttackEnd();
}
void UMinionAnim::AnimNotify_DeathEnd()
{
AMinion* pOwner = Cast<AMinion>(TryGetPawnOwner());
if (IsValid(pOwner))
pOwner->Death();
}
(C++-MinionRangerAnim.h)
...
public:
UFUNCTION()
void AnimNotify_AttackEnd();
UFUNCTION()
void AnimNotify_DeathEnd();
};
(C++-MinionRangerAnim.cpp)
...
void UMinionRangerAnim::ChangeAnim(EMonsterAnim eAnim)
{
AnimType = (uint8)eAnim;
}
void UMinionRangerAnim::AnimNotify_AttackEnd()
{
AMinionRanger* pOwner = Cast<AMinionRanger>(TryGetPawnOwner());
if (IsValid(pOwner))
pOwner->AttackEnd();
}
void UMinionRangerAnim::AnimNotify_DeathEnd()
{
AMinionRanger* pOwner = Cast<AMinionRanger>(TryGetPawnOwner());
if (IsValid(pOwner))
pOwner->Death();
}
(C++-SpawnPoint.cpp)
...
void ASpawnPoint::Respawn()
{
if (!IsValid(SpawnType))
return;
SpawnMonster = nullptr;
if (bInfinity)
return;
bSpawnEnable = true;
SpawnDuration = 0.f; // 시간 0으로.
}
...
'Study > Unreal' 카테고리의 다른 글
[Unreal/정리] 시작 화면 (0) | 2020.11.05 |
---|---|
[Unreal/정리] HPBar (0) | 2020.11.04 |
[Unreal/정리] Patrol (0) | 2020.11.02 |
[Unreal/정리] 행동트리 (0) | 2020.10.26 |
[Unreal/정리] 랜드 스케이프 레이어 (0) | 2020.10.23 |
댓글