2026/4/9 TIL
오늘의 목표
- 아침 코드카타
- 6번 과제 도전 기능 구현
- <C++와 Unreal Engine으로 3D 게임 개발> 강의 2-1, 2-2 수강
6번 과제 도전 기능 구현
개념 공부
[게임플레이 타이머]
글로벌 (FTimerManager 유형인) Time Manger에서 관리.
Time Manager는 Game Instance와 각 World에 존재.
타이머 셋업 함수: SetTimer, SetTimerForNextTick
(각각 오버로드 다수 있음)
SetTimer는 직관적으로 정해진 시간 간격으로 타이머 설정
SetTimerForNextTick은 다음 프레임에 실행되도록 설정
접근
AActor의 함수 GetWorldTimerManager (UWorld의 GetTimerManager 함수도 호출)
글로벌 타이머 매니저 접근
UGameInstance의 함수 GetTimerManager
타이머의 설정 및 해제
타이머 설정
FTimerManager의 SetTimer함수는 딜레이 후 함수나 델리게이트를 호출하는 타이머를 설정하며, 그 함수 호출을 무한 반복하도록 설정할 수 있다.
이 함수는 (FTimerHandle 유형) TImerHandle을 채움.
이는 카운트다운 일시정지(및 재개), 남은 시간 확인 및 변경, 타이머 취소 등에 사용
타이머 해제 (clear)
SetTimer 도중 채워진 FTimerHandle을 ClearTImer라는 함수에 전달.
이후 타이머 핸들은 유효하지 않은 상태가 되며, 새로운 타이머 관리를 위해 재사용 가능
clearAllTimersForObject: 특정 오브젝트에 연관된 모든 타이머 해제
용례:
void AMyActor::BeginPlay()
{
Super::BeginPlay();
// RepeatingFunction 을 초당 1 회, 지금부터 2 초간 호출합니다.
GetWorldTimerManager().SetTimer(MemberTimerHandle, this, &AMyActor::RepeatingFunction, 1.0f, true, 2.0f);
}
void AMyActor::RepeatingFunction()
{
// 이 함수를 충분히 호출했으면, 타이머를 해제합니다.
if (--RepeatingCallsRemaining <= 0)
{
GetWorldTimerManager().ClearTimer(MemberTimerHandle);
// MemberTimerHandle 은 이제 다른 타이머에 재사용 가능합니다.
}
// 여기서 어떤 작업을 합니다...
}
출처: 언리얼 공식문서
https://dev.epicgames.com/documentation/unreal-engine/gameplay-timers-in-unreal-engine
Gameplay Timers in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community
Timer construct for performing delayed or repeated actions in Unreal Engine
dev.epicgames.com
타이머 시스템 활용
타이머 시스템을 활용하여 도전 기능 구현하기.
일정 기간 후 발판이 사라지거나, 주기적으로 다른 위치로 이동하는 로직 추가.
-발판이 일정 기간 후 사라졌다가 나타나는 기능
-주기적으로 다른 위치로 이동하는 기능
이것들을 기존에 만들었던 발판 Actor와 분리하여 따로 만들고자 한다.
처음 만들어보는 액터라 검색의 도움을 받아 구현했다.
c++ 클래스에서 StaticMesh 설정하는 방법
#include "Components/StaticMeshComponent.h"
AMyActor::AMyActor()
{
// 1. 컴포넌트 생성 및 루트 컴포넌트로 설정
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp"));
RootComponent = MeshComp;
// 2. 스태틱 메쉬 에셋 로드 및 설정 (ConstructorHelpers)
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("StaticMesh'/Game/Path/To/Mesh.Mesh'"));
if (MeshAsset.Succeeded())
{
MeshComp->SetStaticMesh(MeshAsset.Object);
}
}
클래스는 다 구현을 완료했는데, 스태틱 메쉬의 pivot (중심점)이 맞지 않아 회전 시 스스로 도는 것이 아니라 중심을 기준으로 원을 그리며 도는 것을 확인. pivot 위치를 변경해주도록 하겠다.
생성자에서 StaticMeshComponent 변수의 SetRelativeLocation함수를 사용한다.
StaticMeshComp->SetRelativeLocation(FVector(-200.0f, -200.0f, 25.0f));

모든 액터에 적용 완료.

SpawnActor 메소드
UWorld::SpawnActor를 통해 객체를 생성
넣을 수 있는 인자는 다음과 같다.
AActor* UWorld::SpawnActor
(
UClass* Class,
FName InName,
FVector const* Location,
FRotator const* Rotation,
AActor* Template,
bool bNoCollisionFail,
bool bRemoteOwned,
AActor* Owner,
APawn* Instigator,
bool bNoFail,
ULevel* OverrideLevel,
bool bDeferConstruction
)
출처: 언리얼 공식 문서
Spawning Actors in Unreal Engine | Unreal Engine 5.5 Documentation | Epic Developer Community
Methods of creating new instances of Actors in gameplay code.
dev.epicgames.com
이번에도 검색의 도움을 받아 랜덤 스폰 액터를 만들었다.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SpawnActor.generated.h"
UCLASS()
class CH3_ASSIGNMENT1_API ASpawnActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ASpawnActor();
// 스폰할 액터 종류들
UPROPERTY(EditAnywhere, Category = "Spawn")
TArray<TSubclassOf<AActor>> SpawnClasses;
// 스폰 범위
UPROPERTY(EditAnywhere, Category ="Spawn")
FVector SpawnRange = FVector(1000.0f, 1000.0f, 0.0f);
// 스폰 개수
UPROPERTY(EditAnywhere, Category="Spawn")
int32 SpawnCount = 5;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
private:
void SpawnPlatforms();
FVector GetRandomSpawnLocation();
};
스폰할 액터들을 TArray<TSubclassOf<AActor>> SpawnClasses에 저장한다.
TArray의 Add 함수 사용
UPROPERTY(EditAnywhere, Category = "Spawn")
TArray<TSubclassOf<AActor>> SpawnClasses;
// Fill out your copyright notice in the Description page of Project Settings.
#include "SpawnActor.h"
// Sets default values
ASpawnActor::ASpawnActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void ASpawnActor::BeginPlay()
{
Super::BeginPlay();
SpawnPlatforms();
}
void ASpawnActor::SpawnPlatforms()
{
for (int32 i = 0; i < SpawnCount; ++i)
{
if (SpawnClasses.IsEmpty()) return;
int32 RandIndex = FMath::RandRange(0, SpawnClasses.Num() - 1);
TSubclassOf<AActor> ChosenClass = SpawnClasses[RandIndex];
FActorSpawnParameters Params;
Params.SpawnCollisionHandlingOverride =
ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
GetWorld()->SpawnActor<AActor>(
ChosenClass,
GetRandomSpawnLocation(),
FRotator::ZeroRotator,
Params
);
}
}
FVector ASpawnActor::GetRandomSpawnLocation()
{
FVector Origin = GetActorLocation();
return FVector(
Origin.X + FMath::FRandRange(-SpawnRange.X, SpawnRange.X),
Origin.Y + FMath::FRandRange(-SpawnRange.Y, SpawnRange.Y),
Origin.Z
);
}