C++과 Unreal Engine으로 3D 게임 개발 2

김여울·2025년 7월 1일
0

내일배움캠프

목록 보기
34/114

코드카타

📎정수 내림차순으로 배치하기

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

long long solution(long long n)
{
    string Numbers = to_string(n);  // 숫자 n을 문자열로 바꾸는 코드
    sort(Nummbers.begin(), Numbers.end(), greater<char>());  // 문자열을 내림차순으로 정렬하는 코드
    long long answer = stoll(Numbers);  // 정렬된 문자열을 다시 long long으로 변환하는 코드

    return answer;  // 결과를 반환하는 코드

}

형변환 함수

변환 함수 / 캐스트설명
✅ 기본 자료형 형변환
std::stoi("123")문자열 → int
std::stoll("12345678900")문자열 → long long
std::stof("3.14")문자열 → float
std::stod("3.1415")문자열 → double
std::to_string(42)숫자 → 문자열
static_cast<int>(3.14)doubleint (소수점 버림)
static_cast<float>(10)intfloat
📌 C++ 스타일 캐스팅 종류
static_cast기본적인 타입 변환 (intfloat, charint, 등)
dynamic_cast클래스 간 다운캐스팅 (RTTI 필요)
const_castconst 제거
reinterpret_cast포인터 타입 등 위험한 변환 (거의 안 씀)

정렬 함수

🔼 오름차순: 기본 std::sort(...)
🔽 내림차순: std::sort(..., std::greater<type>())

#include <algorithm>
#include <vector>

std::vector<int> Numbers { 5, 3, 8, 1 };

std::sort(Numbers.begin(), Numbers.end());	// 오름차순 정렬
std::sort(Numbers.begin(), Numbers.end(), std::greater<int>());	// 내림차순 정렬

컨테이너

컨테이너기본 반복자읽기/쓰기랜덤 접근
std::vectorbegin(), end()OO (빠름)
std::stringbegin(), end()OO
std::arraybegin(), end()OO
std::listbegin(), end()O✖ (느림)
std::dequebegin(), end()OO
std::setbegin(), end()읽기 전용
std::mapbegin(), end()읽기 전용
std::unordered_setbegin(), end()읽기 전용
std::unordered_mapbegin(), end()읽기 전용

✅ 읽기 / 쓰기

  • 읽기 : 값을 가져올 수 있음 → *it
  • 쓰기 : 값을 바꿀 수 있음 → *it = 100
std::vector<int> vec = {1, 2, 3};
auto it = vec.begin();

int a = *it;       // ✅ 읽기
*it = 10;          // ✅ 쓰기 (1 → 10)

✅ 랜덤 접근 (Random Access)
반복자가 임의 위치로 점프할 수 있는 기능

std::vector<int> vec = {10, 20, 30, 40};
auto it = vec.begin();

it += 2; // 점프해서 3번째 요소로 이동 (30)

반복자(Iterator)

  • 컨테이너(자료구조)의 처음부터 끝까지 하나씩 접근하게 해주는 도구

  • 포인터처럼 생김 / 리스트, 문자열, 벡터 같은 걸 순회할 때 사용
    💡 숫자 n은 그냥 한 덩어리 숫자라서 쪼갤 수 없고, 반복자도 없음
    → 문자열 string 으로 변경

    대상begin() 등 반복자 사용 가능?정렬 가능?
    vector✅ 가능✅ 가능
    string✅ 가능✅ 가능
    int, long long❌ 불가능❌ 직접 안 됨
    숫자를 문자열로 변환 후✅ 가능✅ 문자 단위 정렬 가능

📍 1주차 5강

Acotor의 라이프 사이클

UE_LOG

// Item.h
#pragma once

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

UCLASS()
class SPARTAPROJECT_API AItem : public AActor
{
	GENERATED_BODY()
	
public:	
	AItem();

protected:
	UPROPERTY()
	USceneComponent* SceneRoot;	// Root Component로 SceneComponent 생성 
	UPROPERTY()
	UStaticMeshComponent* StaticMeshComp;

	virtual void BeginPlay() override;	// Actor 생성 시점에 바로 호출되는 함수
};

//Item.cpp
void AItem::BeginPlay()
{
	Super::BeginPlay();
	UE_LOG(LogTemp, Warning, TEXT("My Log!"));
}

로그 출력 (로그 카테고리, 경고 메세지(노란색), TEXT("String"));


카테고리 만드는 방법 (매크로)

.h DECLARE_LOG_CATEGORY_EXTERN(카테고리 이름, 로그 레벨, All);
.cpp

// 1️⃣ 카테고리 선언 (클레스 정의 위에 위치)
// Item.h
DECLARE_LOG_CATEGORY_EXTERN(LogSparta, Warning, All);
// LogSparta 카데고리는 항상 Warning 이상의 메세지만 출력하겠다!

// 2️⃣ 카테고리 구현 
// Item.cpp
DEFINE_LOG_CATEGORY(LogSparta);

// 3️⃣ 로그 출력
// Item.cpp
void AItem::BeginPlay()
{
	Super::BeginPlay();
	UE_LOG(LogSparta, Error, TEXT("My Sparta!"));
}
  • Warning 로그 레벨 (Log Level)
    → 로그 찍을 때 기본으로 사용하는 수준
  • All 로그 필터 레벨 (Log Filter Level)
    → 어떤 레벨까지 출력할지 제한
    → 허용할 수 있는 최대 로그 레벨

Log Level (로그 레벨)

로그 레벨색상의미
Fatal🔴 진한 빨간색 (크래시 직전)치명적 오류 → 프로그램 강제 종료
Error🔴 밝은 빨간색일반 오류 → 프로그램은 계속 실행
Warning🟡 노란색경고 (주의는 필요하지만 실행됨)
Display흰색기본 정보 출력
Log흰색디버그용 일반 로그
Verbose🔵 파란색상세 로그 (많은 정보)
VeryVerbose🔵 연한 파란색매우 상세한 로그 (스팸급)
NoLogging출력 안 됨로그 비활성화

Log Filter Level (로그 필터 레벨)

필터 레벨설명
NoLogging로그 아예 안 나옴 ❌
ErrorError 이상만 허용
WarningWarning, Error, Fatal
All전부 허용 ✅

➡ 필터를 Error로 설정하면, Display나 Warning은 무시됨

❓ 로그 카테고리 여러 Actor/Class 에서 공유하고 싶으면
로그 카테고리를 선언해놓은 공용 유틸리티 헤더 파일 따로 만들어 따로 관리하는 방식으로 함
1️⃣ 공용 로그 헤더 하나 만든다 (예: SpartaLog.h)
2️⃣ 거기서 DECLARE_LOG_CATEGORY_EXTERN() 선언해두고
3️⃣ 소스에서 정의한다 (예: SpartaLog.cpp)
4️⃣ 필요한 곳에서 #include "SpartaLog.h"만 하면 됨!

LifeCycle

Actor가 spawn이 되고 destoryed 되는 과정

라이프사이클 함수 (Lifecycle Functions)

  • 액터가 생성되고 파괴되는 생명주기에 따라 엔진이 자동으로 호출하는 함수
    (예) Constructor, BeginPlay(), Tick(), EndPlay(), OnDestroyed()
    void AItem::BeginPlay()
    {
    	Super::BeginPlay();
    	UE_LOG(LogSparta, Warning, TEXT("게임 시작됨!"));
    }
    게임 시작 시 언리얼이 자동으로 호출해줌
    함수 이 안에 원하는 동작을 정의하면 됨

콜백 함수 (Callback Functions)

  • 특정 상황(충돌, 겹침 등)이 발생했을 때 엔진이 자동으로 호출하는 함수
  • 보통 컴포넌트 이벤트나 상호작용과 관련됨
    (예) OnComponentHit(), NotifyActorBeginOverlap(), NotifyActorEndOverlap()
함수명언제 호출됨?
✅ 라이프사이클 함수
Constructor (생성자)💡 객체가 생성될 때 / 메모리에 생성 / 딱 한 번 호출
월드 상에 Actor가 등장하지 않았을 가능성 큼 → 컴포넌트 생성해서 Actor에 붙여줌
PostInitializeComponents()💡 컴포넌트가 완성된 직후 호출, 컴포넌트끼리 데이터 주고 받기, 상호작용
OnConstruction()에디터에서 배치되거나 값 변경될 때
BeginPlay()💡 배치된 직후 (Spawn)
Tick(float DeltaTime)💡 매 프레임마다 호출됨 → 캐릭터 이동, 애니메이션, 물리계산 등 자연스러운 움직임 필요할 때
⚠️ 성능을 떨어뜨릴 수 있으므로 주의해서 사용
Destroyed()💡 Actor가 삭제(필요없음, 끝남)가 되기 직전에 호출됨 → resource 정리할 때 유용
EndPlay(EndPlayReason)게임 종료, 파괴 (Destroyed()), 레벨 전환
Destructor (소멸자)객체가 메모리에서 완전히 해제될 때 호출됨
✅ 콜백 함수
OnComponentHit()콜리전 충돌이 발생했을 때
NotifyActorBeginOverlap()Actor끼리 겹치기 시작했을 때
NotifyActorEndOverlap()Actor끼리 겹치기 끝났을 때

-----  생성
Constructor
PostInitializeComponents()
BeginPlay()
-----  활동
Tick(float DeltaTime)
----- 죽음
Destroyed()
EndPlay()
// .h 
virtual void PostInitializeComponents() override;
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
virtual void Destroyed() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;	
// 왜 Actor의 생명이 끝났는지 각각의 상황들이 enum 값으로 저장되어 있음

// .cpp
AItem::AItem()
{
	UE_LOG(LogSparta, Warning, TEXT("%s Constructor"), *GetName());
/.../
}

void AItem::BeginPlay()
{
	Super::BeginPlay();	// 부모 것도 호출
    // 동작하고 싶은 거 여기에
    UE_LOG(LogSparta, Warning, TEXT("%s BeginPlay"), *GetName());
}
void AItem::PostInitializeComponents()
{
    Super::PostInitializeComponents();
	// 여기에 필요한 초기화 코드 작성
	UE_LOG(LogSparta, Warning, TEXT("%s PostInitializeComponents"), *GetName());
}
void AItem::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}
// Destroyed(), EndPlay(): 부모 호출되면서 삭제될 수 있어서 그 전에 로그 출력
void AItem::Destroyed()
{
	UE_LOG(LogSparta, Warning, TEXT("%s Destroyed"), *GetName());
	Super::Destroyed();	
}
void AItem::EndPlay(const EEndPlayReason::Type EndPlayReason) 
{
	UE_LOG(LogSparta, Warning, TEXT("%s EndPlay"), *GetName());
	Super::EndPlay(EndPlayReason);
}

대부분 부모 클래스(AActor, UActorComponent) 에서 정의되어 있음 → override 필요


✅ Destroy() vs EndPlay()

함수역할언제 쓰임
Destroy()액터를 월드에서 제거내가 직접 "이제 필요 없어!" 할 때
EndPlay()액터 제거 직전에 호출엔진이 자동으로 항상 호출함 (Destroy()나 레벨 언로드 등)

🔄 흐름
Destroy() 호출
→ 언리얼이 EndPlay() 호출
→ 그 후 액터가 소멸됨 (소멸자 호출됨)


💭

강의를 따라하는데도 자꾸 에러가 났다.

오늘의 삽질... 흑흑

  • PostInitializeComponents()를 override만 해놓고 구현 안 해서 빌드 에러(LNK2001) 났음
    → 함수 선언만 하고 몸체 안 만들면 안 됨!
  • Super::Tick(DeltaTime); 호출할 때는 float 같은 타입 쓰면 안 됨!
    → 함수 호출 시엔 변수 이름만, 타입은 함수 선언/정의할 때만 씀

0개의 댓글