10. 적 캐릭터 - Elysia-ff/UE4-Custom_Stencil_Tutorial GitHub Wiki

적 캐릭터 추가

적 캐릭터를 만들 차례다.
AStealthCharacter를 확장해서 AEnemy를 생성하고 AAIController를 확장해서 AEnemyAIController를 생성한다.
그리고 AEnemyAIControllerAEnemy의 기본 컨트롤러로 등록한다.

public:
	AEnemy(const FObjectInitializer& ObjectInitializer);
AEnemy::AEnemy(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	PrimaryActorTick.bCanEverTick = false;
	AIControllerClass = AEnemyAIController::StaticClass();
}

AEnemy를 상속받는 BP_Enemy를 생성하고 BP_Hitman과 마찬가지로 기본 메시로 세팅한다.
Level에 끌어다 놓으면 잘 나온다.
image


캐릭터 숨기기

그런데 시야 밖에 있는 캐릭터도 보이는건 이상하니까 보이지 않게 수정하겠다.
새 마테리얼을 생성해서 BP_Enemy에 연결한다.
image

그다음 Material -> Blend Mode를 Translucent로 변경하고
image

다음 코드를 추가한다.
image
(Opacity를 스텐실값의 첫번째 비트가 켜져있으면 100%, 그렇지 않으면 0%로 설정한다.)

실행하면 시야 밖의 캐릭터는 보이지 않는다.
image


캐릭터 생성

다음은 게임 시작 시 자동으로 적이 생성되게 하겠다.
AActor를 확장해서 AEnemySpawnManager를 생성하고 아래 코드를 추가한다.

public:	
	// Sets default values for this actor's properties
	AEnemySpawnManager(const FObjectInitializer& ObjectInitializer);

	const TArray<AEnemy*>* GetEnemies() const;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

private:
	void SpawnEnemy(const FTransform& SpawnTransform);

public:
	UPROPERTY(EditAnywhere, Category = "Spawn Position")
	TArray<TWeakObjectPtr<AActor>> SpawnPoses;

private:
	UPROPERTY()
	UClass* EnemyBlueprint;

	UPROPERTY()
	TArray<AEnemy*> Enemies;
#include "Character/Enemy.h"

// Sets default values
AEnemySpawnManager::AEnemySpawnManager(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

	static ConstructorHelpers::FObjectFinder<UClass> EnemyObjectFinder(TEXT("Blueprint'/Game/Blueprint/Character/BP_Enemy.BP_Enemy_C'"));
	check(EnemyObjectFinder.Succeeded());
	EnemyBlueprint = EnemyObjectFinder.Object;
}

const TArray<AEnemy*>* AEnemySpawnManager::GetEnemies() const
{
	return &Enemies;
}

// Called when the game starts or when spawned
void AEnemySpawnManager::BeginPlay()
{
	Super::BeginPlay();
	
	Enemies.Reserve(SpawnPoses.Num());
	for (int32 i = 0; i < SpawnPoses.Num(); i++)
	{
		if (!SpawnPoses[i].IsValid())
		{
			UE_LOG(LogTemp, Warning, TEXT("Invalid spawn position : %d"), i);
			continue;
		}

		SpawnEnemy(SpawnPoses[i]->GetTransform());
	}
}

void AEnemySpawnManager::SpawnEnemy(const FTransform& SpawnTransform)
{
	check(EnemyBlueprint);
	
	FActorSpawnParameters Param;
	Param.Owner = this;
	Param.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;

	AEnemy* NewEnemy = GetWorld()->SpawnActor<AEnemy>(EnemyBlueprint, SpawnTransform, Param);
	check(NewEnemy);

	NewEnemy->SpawnDefaultController();
	Enemies.Add(NewEnemy);
}

이제 AEnemySpawnManager를 Level에 끌어다 놓고 빈액터를 임의의 위치에 생성한 후 AEnemySpawnManager에 연결한다.
플레이하면 액터들의 위치에 적이 스폰된다.
image


완성된 코드

/Character/Enemy.h
// Copyright 2021. Elysia-ff

#pragma once

#include "CoreMinimal.h"
#include "Character/StealthCharacter.h"
#include "Enemy.generated.h"

/**
 * 
 */
UCLASS()
class STEALTHTUTORIAL_API AEnemy : public AStealthCharacter
{
	GENERATED_BODY()

public:
	AEnemy(const FObjectInitializer& ObjectInitializer);
};
/Character/Enemy.cpp
// Copyright 2021. Elysia-ff


#include "Enemy.h"

#include "Character/Controller/EnemyAIController.h"

AEnemy::AEnemy(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	PrimaryActorTick.bCanEverTick = false;
	AIControllerClass = AEnemyAIController::StaticClass();
}
/Character/Controller/EnemyAIController.h
// Copyright 2021. Elysia-ff

#pragma once

#include "CoreMinimal.h"
#include "AIController.h"
#include "EnemyAIController.generated.h"

/**
 * 
 */
UCLASS()
class STEALTHTUTORIAL_API AEnemyAIController : public AAIController
{
	GENERATED_BODY()
	
};
/SpawnManager/EnemySpawnManager.h
// Copyright 2021. Elysia-ff

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "EnemySpawnManager.generated.h"

class AEnemy;

UCLASS()
class STEALTHTUTORIAL_API AEnemySpawnManager : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AEnemySpawnManager(const FObjectInitializer& ObjectInitializer);

	const TArray<AEnemy*>* GetEnemies() const;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

private:
	void SpawnEnemy(const FTransform& SpawnTransform);

public:
	UPROPERTY(EditAnywhere, Category = "Spawn Position")
	TArray<TWeakObjectPtr<AActor>> SpawnPoses;

private:
	UPROPERTY()
	UClass* EnemyBlueprint;

	UPROPERTY()
	TArray<AEnemy*> Enemies;
};
/SpawnManager/EnemySpawnManager.cpp
// Copyright 2021. Elysia-ff


#include "EnemySpawnManager.h"

#include "Character/Enemy.h"

// Sets default values
AEnemySpawnManager::AEnemySpawnManager(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

	static ConstructorHelpers::FObjectFinder<UClass> EnemyObjectFinder(TEXT("Blueprint'/Game/Blueprint/Character/BP_Enemy.BP_Enemy_C'"));
	check(EnemyObjectFinder.Succeeded());
	EnemyBlueprint = EnemyObjectFinder.Object;
}

const TArray<AEnemy*>* AEnemySpawnManager::GetEnemies() const
{
	return &Enemies;
}

// Called when the game starts or when spawned
void AEnemySpawnManager::BeginPlay()
{
	Super::BeginPlay();
	
	Enemies.Reserve(SpawnPoses.Num());
	for (int32 i = 0; i < SpawnPoses.Num(); i++)
	{
		if (!SpawnPoses[i].IsValid())
		{
			UE_LOG(LogTemp, Warning, TEXT("Invalid spawn position : %d"), i);
			continue;
		}

		SpawnEnemy(SpawnPoses[i]->GetTransform());
	}
}

void AEnemySpawnManager::SpawnEnemy(const FTransform& SpawnTransform)
{
	check(EnemyBlueprint);
	
	FActorSpawnParameters Param;
	Param.Owner = this;
	Param.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;

	AEnemy* NewEnemy = GetWorld()->SpawnActor<AEnemy>(EnemyBlueprint, SpawnTransform, Param);
	check(NewEnemy);

	NewEnemy->SpawnDefaultController();
	Enemies.Add(NewEnemy);
}
⚠️ **GitHub.com Fallback** ⚠️