Character를 상속받아 C++클래스를 만듭니다. 이름은 Enemy로 합니다.
외관데이터 할당하기
ConstructorHelpers::FObjectFinder<>()를 사용해 하드코딩으로 메시를 불러옵니다.
Character를 상속받아 이미 스텔레탈메시컴포넌트가 있는데 GetMesh()로 접근합니다.
적에너미는 적마다 외형이 다르므로 하드코딩보다는 블루프린트를 만들어 지정하는게 유연합니다. 샘플스켈레탈메시도 삼인칭 메시를 사용하였습니다만 이또한 안하는게 편할수도 있습니다.
ThirdPersonTemplete의 SKM_Quinn을 Ctrl-C해서 붙여줍니다. 작은 따옴표 안에만 사용합니다.
책에서는 BP_Enemy 블루프린트 생성하여 외관을 붙여주고 있습니다.
블루프린트에서 메시를 붙여보면 위치가 위에 떠 있고 옆을 바로 보고 있어서 많은 적을 생성할때
GetMesh()->SetRelativeLocationAndRotation(FVector(0, 0, -88), FRotator(0, -90, 0));
로 미리 조정해주는게 편합니다.
ConstructorHelpers::FObjectFinder<USkeletalMesh> tempMesh(TEXT("/Game/Characters/Mannequins/Meshes/SKM_Quinn.SKM_Quinn"));
// 1-1. 데이터 로드 성공하면
if (tempMesh.Succeeded())
{
//UE_LOG(LogTemp, Warning, TEXT("Enemy Skeletal Mesh Loading"));
// 1-2. 데이터 할당
GetMesh()->SetSkeletalMesh(tempMesh.Object);
// 1-3. 메쉬 위치 및 회전 설정
GetMesh()->SetRelativeLocationAndRotation(FVector(0, 0, -88), FRotator(0, -90, 0));
// 1-4. 메쉬 크기 수정
GetMesh()->SetRelativeScale3D(FVector(0.84f));
GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
다음 코드는 아직 구현안한 EnemyFSM및 HPBar Widget이 포함되어 있어 이것만으로는 컴파일이 안됩니다. 하시고 싶은분은 Widget부분을 제거해야 합니다.
Enemy.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Enemy.generated.h"
UCLASS()
class TPSPROJECT_API AEnemy : public ACharacter
{
GENERATED_BODY()
UPROPERTY(EditAnywhere)
class USphereComponent* sphereComp;
public:
// Sets default values for this character's properties
AEnemy();
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:
// 적 AI 관리 컴포넌트 클래스
UPROPERTY(VisibleAnywhere, Category = FSM)
class ATPSPlayer* target;
// 소유액터
UPROPERTY()
class AEnemy* me;
// 적 AI 관리 컴포넌트 클래스
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = FSMComponent)
class UEnemyFSM* fsm;
UPROPERTY(EditAnywhere)
TSubclassOf<class UHPBar> widgetRef;
UPROPERTY()
class UHPBar* hpBar;
UPROPERTY()
class UWidgetComponent* widgetComp;
};
Enemy.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "Enemy.h"
#include "EnemyFSM.h"
#include "TPSPlayer.h"
#include <Components/CapsuleComponent.h>
#include <Components/SphereComponent.h>
#include <Components/WidgetComponent.h>
#include "Components/widget.h"
#include <Kismet/GameplayStatics.h>
#include <Kismet/KismetMathLibrary.h>
#include "HPBar.h"
// Sets default values
AEnemy::AEnemy()
{
// 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;
// 1. 스켈레탈메쉬 데이터 로드
//
ConstructorHelpers::FObjectFinder<USkeletalMesh> tempMesh(TEXT("/Game/Characters/Mannequins/Meshes/SKM_Quinn.SKM_Quinn"));
// 1-1. 데이터 로드 성공하면
if (tempMesh.Succeeded())
{
//UE_LOG(LogTemp, Warning, TEXT("Enemy Skeletal Mesh Loading"));
// 1-2. 데이터 할당
GetMesh()->SetSkeletalMesh(tempMesh.Object);
// 1-3. 메쉬 위치 및 회전 설정
GetMesh()->SetRelativeLocationAndRotation(FVector(0, 0, -88), FRotator(0, -90, 0));
// 1-4. 메쉬 크기 수정
GetMesh()->SetRelativeScale3D(FVector(0.84f));
GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
sphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("Collosion"));
sphereComp->SetRelativeScale3D(FVector(3, 3, 3));
sphereComp->SetCollisionProfileName(TEXT("EnemyHand"));
GetCapsuleComponent()->SetCollisionProfileName(TEXT("Enemy"));
GetMesh()->SetCollisionProfileName(TEXT("NoCollision"));
// EnemyFSM 컴포넌트 추가
fsm = CreateDefaultSubobject<UEnemyFSM>(TEXT("FSM"));
if (fsm) {
UE_LOG(LogTemp, Warning, TEXT("fsm"));
//GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf( TEXT("FSM: ") );// , fsm->GetFName()));
//GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("FSM:") );
// 애니메이션 블루프린트 할당하기
}
ConstructorHelpers::FClassFinder<UAnimInstance> tempClass(TEXT("/Game/Anim/ABP_Enemy.ABP_Enemy_C"));
if (tempClass.Succeeded())
{
//UE_LOG(LogTemp, Warning, TEXT("ABP_Enemy Loading"));
//GetMesh()->SetAnim
GetMesh()->SetAnimInstanceClass(tempClass.Class);
}
widgetComp = CreateDefaultSubobject<UWidgetComponent>(TEXT("HPWidget"));
widgetComp->SetupAttachment(GetMesh());
widgetComp->SetRelativeLocation(FVector(0, 0, 300.0f));
UClass* WidgetCompClass = LoadClass<UUserWidget>(NULL, TEXT("/Game/UI/WBP_HPEnemy.WBP_HPEnemy_C"));
if (WidgetCompClass) {
widgetComp->SetWidgetClass(WidgetCompClass);
widgetComp->SetWidgetSpace(EWidgetSpace::Screen);
}
AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
}
// Called when the game starts or when spawned
void AEnemy::BeginPlay()
{
Super::BeginPlay();
auto actor = UGameplayStatics::GetActorOfClass(GetWorld(), ATPSPlayer::StaticClass());
// ATPSPlayer 타입으로 캐스팅
target = Cast<ATPSPlayer>(actor);
// 소유객체 가져오기
//me = Cast<ANPC>(GetOwner());
me = this;
widgetComp->InitWidget();
hpBar = Cast<UHPBar>(widgetComp->GetUserWidgetObject());
if (IsValid(hpBar)) {
//FText idText = FText::FromString(FString::FromInt(12));
FVector _pos = target->GetActorLocation();
hpBar->ctextId = GetClass()->GetDisplayNameText();
hpBar->cInfo = FText::FromString(FString::Printf(TEXT("IDLE")));
//hpBar->ctextPos = FText::FromString(FString::Printf(TEXT("%f %f %f"), _pos.X, _pos.Y, _pos.Z));
hpBar->cHP = 10;
hpBar->cMaxHP = 10;
hpBar->cMP = 100;
hpBar->cMaxMP = 100;
/*widget->SetTextID(GetClass()->GetDisplayNameText());
FVector _pos = target->GetActorLocation();
widget->SetTextPosition(FText::FromString(FString::Printf(TEXT("%f %f %f"), _pos.X, _pos.Y, _pos.Z)));
*/
}
}
// Called every frame
void AEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void AEnemy::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
'인생언리얼TPS' 카테고리의 다른 글
3.2 알파타입버전 제작하기 - 애니메이션 FSM (1) | 2023.12.23 |
---|---|
3.1-9 적AI제어를 위한 FSM 제작하기 (0) | 2023.12.15 |
3.1-7 스나이퍼모드 C++ (0) | 2023.12.15 |
스나이퍼 모드 구현하기 (0) | 2023.12.13 |
3.1-6 총알발사하기 (0) | 2023.12.13 |