Unreal Engine - Game Loop

2025. 2. 9. 15:51·Unreal Engine

아이템 구현에 대한 내용과 연결되는 내용입니다.

  • 아이템 만들기
  • 아이템 스폰 및 캐릭터와 연동

1. Game Loop


게임이 진행되는 흐름을 말한다. (Game Flow라고도 한다)

언리얼 엔진에서는 게임 루프나 전역 상태를 위해 GameState나 GameMode를 사용한다.

  • 주의할 점
    • GameState나 GameMode 모두 Base가 뒤에 붙은 클래스가 존재한다.
    • GameMode와 GameState는 둘 간의 호환성이 중요하기 때문에, 
    • 둘 다 Base로 만들던지, 아니면 둘 다 Base가 아닌 것으로 만들지 맞춰주어야 한다.
  • GameMode
    • 게임 규칙(승패 조건, 플레이어 스폰 등)을 서버에서 제어하는데 사용
    • 서버 전용 로직을 담는 곳이다. (멀티 플레이 게임)
    • 클라이언트가 알아야 하는 정보의 경우 GameMode에 두지 않는다.
    • 우리의 구현에 있어서는, default pawn이나 player controller를 설정할 때 사용했다.
  • GameState
    • 게임 전반에 걸쳐 모든 플레이어가 공유해야 하는 상태를 담은 클래스이다.
    • 전역 상태가 필요한 경우 활용한다.
    • 게임이 시작되면, 서버에서 GameState가 생성되고 클라이언트는 이것을 복제해서 사용
    • GameMode에서 말한 게임 규칙들을 싱글플레이 게임의 경우 GameState에 구현한다.
  • GameInstance
    • 모든 레벨에 걸쳐 유지하는 정보
    • 애플리케이션이 종료될 때 까지 유일하게 살아있음, 맵이 전환되어도 파괴되지 않음
    • 주로 싱글 게임에서 사용

 

 

2. 게임 루프 설계


  • 게임 시작
    • GameInstance 생성, GameState, GameMode 생성
  • BeginPlay
    • 아이템 스폰 
    • 맵에 스폰된 아이템의 정보 받아오기
    • 타이머 시작
  • 다음 레벨 이동
    • 맵에 있는 동전을 특정 갯수만큼 먹은 경우
    • 30초가 지난 경우
    • 주의)
      • GameState, GameMode 및 대부분의 객체는 새로 생성된다!
      • GameInstance로 데이터 유지하는 것 필요하다.
  • 게임 오버
    • 마지막 레벨(레벨3) 에서 "다음 레벨 이동" 로직이 실행된 경우
    • 캐릭터의 체력이 0이 된 경우

수정할 내용

  • 기존 구현에서는 SpawnVolume에서 SpawnItem이라는 함수를 통해서 랜덤한 아이템을 소환하였다.
  • 수정) 게임 시작 시,
    • GameState에서 소환할 아이템의 갯수를 지정하고 스폰하며,
    • 스폰한 아이템 중 동전 아이템의 갯수를 알고 있어야 함
    • OnCoinCollected() 라는 함수로 현재 모은 동전 아이템의 갯수가 생성된 동전 갯수보다 많아지면, 다음 레벨로 이동할 수 있는 로직 추가
      • 해당 함수는 Coin 클래스에서 이전에 구현한 GameState를 통해 call 하게 된다.

 

 

3. GameState 설계

3 - 1. 수정된 Spawn Volume 클래스

  • 아래 두 함수의 return 값을 AActor* 로 만들어서, GameState에서 spawn 한 아이템의 정보를 받아올 수 있도록 구현하였다.
  • 기억할 점) GetWorld()->SpawnActor<>() 를 AActor* 로 리턴값을 받아서 저장할 수 있다.
//SpawnVolume.cpp

AActor* ASpawnVolume::SpawnItem(TSubclassOf<AActor> ItemClass)
{
	if (!ItemClass)
		return nullptr;

	AActor* SpawnedActor = GetWorld()->SpawnActor<AActor>(
		ItemClass
		, GetRandomPointInVolume()
		, FRotator::ZeroRotator
	);

	return SpawnedActor;
}

AActor* ASpawnVolume::SpawnRandomItem()
{
	if (FItemSpawnRow* SelectedRow = GetRandomItem())
	{
		if (UClass* ActualClass = SelectedRow->ItemClass.Get())
		{
			return SpawnItem(ActualClass);
		}
	}
	return nullptr;
}

 

3 - 2. GameInstance

  • 레벨 전환 시 GameState와 GameMode는 새로 생성된다. 그러나 점수나 현재 레벨의 정보 등은 게임이 끝나기 전까지 사라지면 안되기 때문에, GameInstance에 구현해야 한다. 
  • GameInstance에는 게임 전체 누적 점수(점수 획득 함수) 및, 현재 레벨 인덱스에 대한 정보를 저장하였다.
#include "SpartaGameInstance.h"

USpartaGameInstance::USpartaGameInstance()
	:TotalScore(0)
	,CurrentLevelIndex(0)
{
}

void USpartaGameInstance::AddToScore(int32 Amount)
{
	TotalScore += Amount;
	UE_LOG(LogTemp, Warning, TEXT("Total Score: %d"), TotalScore);
}

 

3 - 3. GameState 구현

  • BeginPlay에서 StartLevel 함수를 수행
    • StartLevel 함수 
      • GameInstance를 통해 전역 데이터를 저장 (레벨 인덱스)
      • SpawnVolume을 가져와서 아이템 스폰
      • 타이머 시작
    •  기억할 것)
      • IsA() 함수를 통해 유효성 체크를 수행할 수 있다.
void ASpartaGameState::StartLevel()
{
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		USpartaGameInstance* SpartaGameInstance = Cast<USpartaGameInstance>(GameInstance);
		if (SpartaGameInstance)
		{
                        //현재 레벨 인덱스 저장
			CurrentLevelIndex = SpartaGameInstance->CurrentLevelIndex;
		}
	}

	SpawnedCoinCount = 0;
	CollectedCoinCount = 0;

	TArray<AActor*> FoundVolumes;
	UGameplayStatics::GetAllActorsOfClass(
		GetWorld()
		, ASpawnVolume::StaticClass()
		, FoundVolumes);

	const int32 ItemToSpawn = 40;

	for (int32 i = 0; i < ItemToSpawn; ++i)
	{
		if (FoundVolumes.Num() > 0)
		{
			ASpawnVolume* SpawnVolume = Cast<ASpawnVolume>(FoundVolumes[0]);
			if (SpawnVolume)
			{
				AActor* SpawnedActor = SpawnVolume->SpawnRandomItem();
				//스폰된 동전 갯수 측정
				if (SpawnedActor && SpawnedActor->IsA(ACoinItem::StaticClass()))
				{
					SpawnedCoinCount++;
				}
			}
		}
	}

	GetWorldTimerManager().SetTimer(
		LevelTimerHandle
		, this
		, &ASpartaGameState::OnLevelTimeUp
		, LevelDuration
		, false);

	UE_LOG(LogTemp, Warning, TEXT("Level %d start spawned %d coins"),
		CurrentLevelIndex + 1
		, SpawnedCoinCount);
}
  • 모든 동전을 모았거나, 시간이 지났거나 캐릭터의 체력이 0 일때 EndLevel 함수 실행
    • EndLevel 함수
      • 타이머 리셋
      • 레벨 인덱스 로직 수행
        • 레벨 인덱스 올려주기
        • 유효하다면, 다음 레벨 열기 
        • 유효하지 않다면, 게임 오버
    • 기억할 것)
      • UGameplayStatics::OpenLevel 을 통해 다음 레벨을 열어주는 로직 수행 가능
      • 이때 TArray<FName> 타입의 레벨을 저장하는 Array를 사용 (BP에서 세팅함)

void ASpartaGameState::EndLevel()
{
	GetWorldTimerManager().ClearTimer(LevelTimerHandle);
	CurrentLevelIndex++;

	if (UGameInstance* GameInstance = GetGameInstance())
	{
		USpartaGameInstance* SpartaGameInstance = Cast<USpartaGameInstance>(GameInstance);
		if (SpartaGameInstance)
		{			
			AddScore(Score);
			SpartaGameInstance->CurrentLevelIndex = CurrentLevelIndex;
		}
	}

	if (CurrentLevelIndex >= MaxLevelIndex)
	{
		OnGameOver();
		return;
	}
	
	if (LevelMapNames.IsValidIndex(CurrentLevelIndex))
	{
		UGameplayStatics::OpenLevel(GetWorld(), LevelMapNames[CurrentLevelIndex]);
	}
	else
	{
		OnGameOver();
	}
}
  • 실행 모습 1
    • level 1시작
    • 아이템 획득 체크
    • Total Score 

  • 실행 모습2
    • 시간이 지나서 자동으로 Level 2수행
    • Total Score는 유지
    • Coin 수는 Reset

'Unreal Engine' 카테고리의 다른 글

UE5 Issues : Complex Collision  (0) 2025.02.11
UE5 Issues : Look Action (bUsePawnControlRotation)  (0) 2025.02.11
Unreal Engine - 아이템 스폰 및 캐릭터와 연동  (0) 2025.02.07
Unreal Engine - 아이템 만들기 (+충돌 처리)  (1) 2025.02.06
Unreal Engine - Simple Niagara (with cpp)  (0) 2025.02.04
'Unreal Engine' 카테고리의 다른 글
  • UE5 Issues : Complex Collision
  • UE5 Issues : Look Action (bUsePawnControlRotation)
  • Unreal Engine - 아이템 스폰 및 캐릭터와 연동
  • Unreal Engine - 아이템 만들기 (+충돌 처리)
gbleem
gbleem
gbleem 님의 블로그 입니다.
  • gbleem
    gbleem 님의 블로그
    gbleem
  • 전체
    오늘
    어제
    • 분류 전체보기 (176)
      • Unreal Engine (66)
      • C++ (19)
      • 알고리즘(코딩테스트) (26)
      • TIL (60)
      • CS (4)
      • 툴 (1)
  • 블로그 메뉴

    • 홈
    • 카테고리
  • 링크

    • 과제용 깃허브
    • 깃허브
    • velog
  • 공지사항

  • 인기 글

  • 태그

    매크로 지정자
    addonscreendebugmessage
    actor 클래스
    싱글턴
    템플릿
    map을 vector로 복사
    DP
    enhanced input system
    blend pose
    motion matching
    applydamage
    C++
    cin함수
    상속
    additive animation
    const
    character animation
    Vector
    gamestate
    BFS
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
gbleem
Unreal Engine - Game Loop
상단으로

티스토리툴바