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

김여울·2025년 7월 6일
0

내일배움캠프

목록 보기
38/114
post-thumbnail

코드카타

문자열 내림차순으로 배치하기

#include <algorithm>
#include <string>

string solution(string s) 
{
    sort(s.begin(), s.end(), greater<char>());
    return s;
}

정렬 함수

  • sort(s.begin(), s.end(), greater<char>())
    • 문자열 s의 문자를 내림차순으로 정렬
    • 대문자는 소문자보다 작게 취급됨 (대문자 < 소문자)

함수와 ()

greater<char>() 의 ()

  • greater<char> 는 함수 객체(Functor) 타입
  • greater<char>() 는 그걸 실행 가능한 함수처럼 만든 것
  • ()는 "함수처럼 호출"한다는 의미

💡 greater<char>() 는 비교용 함수처럼 쓰기 위한 문법

s.begin() / s.end() 의 ()

  • s.begin() 은 문자열의 시작 위치(iterator) 를 알려주는 함수
  • s.end() 는 문자열의 끝+1 위치(iterator) 를 알려주는 함수
  • ()는 함수 호출을 의미하고, 없으면 함수 그 자체를 가리킴

💡 정렬 범위를 지정하기 위해 .begin().end() 를 꼭 호출해야 함

변수와 ()

int a = 10; // 변수는 () 없이 선언
  • 변수는 값을 저장하는 거라 괄호가 필요 없음
  • 함수는 실행이 필요하니까 ()가 붙는 거임

대문자와 소문자

📎ASCII Table

ASCII Table을 보면 대문자의 십진법 숫자가 더 적다
대문자 < 소문자

오름차순 정렬 : 대문자 - 소문자
내림차순 정렬 : 소문자 - 대문자

정리

개념예시의미
함수 호출Add(3, 4)실행하려고 () 붙임
함수 객체 실행greater<char>()비교 함수처럼 쓰기 위해 () 붙임
문자열 정렬 범위s.begin() / s.end()함수니까 () 필요
변수 선언int a = 10;그냥 값 저장 → 괄호 없음

📍 3주차 1강

5. 아이템 설계하기

5.1 인터페이스

  • 함수의 껍데기만 정의해둠
  • 나중에 이걸 구현하는 클래스가 실제 내용을 작성해야 함
    (약속)

a. 인터페이스 vs 상속

구분설명
상속부모 클래스의 기능을 물려받음
인터페이스특정 함수를 반드시 "구현하겠다"는 약속만 함

b. 사용 흐름

1️⃣ 인터페이스 정의

  • UInterface로 만들기
  • 함수 형태만 선언 (내용 없음 → 가상함수 형태)
    2️⃣ 클래스에서 인터페이스 구현
  • 해당 클래스는 인터페이스를 구현해야 함
  • 인터페이스에 선언된 함수 반드시 작성
    (예: OnItemOverlap())

c. 정리

인터페이스를 구현한 클래스는 해당 함수들을 반드시 구현해야 한다
덕분에 여러 클래스가 같은 함수 이름을 공유하며 서로 다른 동작을 할 수 있음
(예) 여러 아이템들이 캐릭터와 겹칠 때, 인터페이스를 통해 “겹쳤을 때의 반응”을 각자 알아서 정의하게 만들면 깔끔하다

5.2 만들기

a. ItemInterface

1️⃣ C++ Class로 Unreal Interface 생성

ItemInterface.h

2️⃣ ItemInterface.h에 순수가상함수 쓰기

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ItemInterface.generated.h"

// This class does not need to be modified.
UINTERFACE(MinimalAPI)	// 현재 모듈 내에서만 접근 가능하도록 제한함
class UItemInterface : public UInterface  // 리플렉션을 위한 인터페이스 클래스
{
	GENERATED_BODY()
};

/**
 * 
 */
class SPARTAPROJECT_API IItemInterface
{
	GENERATED_BODY()


public:	// 자식들 무조건 구현 -> 순수가상함수들은 여기에
	virtual void OnItemOverlap(AActor* OtherActor) = 0;	// 아이템과 겹쳤을 때 호출되는 함수
	virtual void OnItemEndOverlap(AActor* OtherActor) = 0;	// 아이템과 겹침이 끝났을 때 호출되는 함수
	virtual void ActivateItem(AActor* Activator) = 0;	// 아이템을 활성화할 때 호출되는 함수
	virtual FName GetItemType() const = 0;	// 아이템의 타입을 반환하는 함수 -> return만 하기 때문에 const
	// String 말고 빠른 FName을 사용
};

b. BaseItem

3️⃣ 이 인터페이스를 구현한 Actor class 만들기
클래스 계층 구조

IItemInterface      ←  (인터페이스)
       ▲
       │
     BaseItem            ←  (부모 클래스)
  ┌────┼────────────┬────────────┐
  │    │           │           │
CoinItem       BombItem     HealItem
  ▲
 ┌┴────────────┐
SmallCoin  BigCoin

BaseItem : Actor를 상속 받음

BaseItem.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ItemInterface.h"  // 아이템 인터페이스를 포함시켜야 함
#include "BaseItem.generated.h"

UCLASS()
class SPARTAPROJECT_API ABaseItem : public AActor, public IItemInterface  // IItemInterface를 상속받아야 함
{
	GENERATED_BODY()
	
public:	
	ABaseItem();

public:	
	// 인터페이스에 있는 순수가상함수들을 구현해야 함
	virtual void OnItemOverlap(AActor* OtherActor) override;
	virtual void OnItemEndOverlap(AActor* OtherActor) override;
	virtual void ActivateItem(AActor* Activator) override;
	virtual FName GetItemType() const override;

	virtual void DestroyItem();

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item") // 리플렉션으로 에디터에 노출
	FName ItemType;  // 아이템의 타입을 저장하는 변수
};

BaseItem.cpp

#include "BaseItem.h"

ABaseItem::ABaseItem()
{
	PrimaryActorTick.bCanEverTick = false;

}

void ABaseItem::OnItemOverlap(AActor* OtherActor)
{
}

void ABaseItem::OnItemEndOverlap(AActor* OtherActor)
{
}

void ABaseItem::ActivateItem(AActor* Activator)
{
}

FName ABaseItem::GetItemType() const
{
	return ItemType;
}

void ABaseItem::DestroyItem()
{
	Destroy();
}

c. CoinItem

CoinItem : BaseItem을 상속 받음

CoinItem.h

#pragma once

#include "CoreMinimal.h"
#include "BaseItem.h"
#include "CoinItem.generated.h"

UCLASS()
class SPARTAPROJECT_API ACoinItem : public ABaseItem

{
	GENERATED_BODY()

public:
	ACoinItem();	// 생성자

protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	int32 PointValue;
};

CoinItem.cpp

#include "CoinItem.h"

ACoinItem::ACoinItem()  // 생성자
{

}

d. BigCoinItem, SmallCoinItem

이제 CoinItem을 상속받는 BigCoin, SmallCoin 만들기

BigCoinItem.h

#pragma once

#include "CoreMinimal.h"
#include "CoinItem.h"
#include "BigCoinItem.generated.h"

UCLASS()
class SPARTAPROJECT_API ABigCoinItem : public ACoinItem
{
	GENERATED_BODY()
	
public:
	ABigCoinItem();	// 생성자

	virtual void ActivateItem(AActor* Activator) override;
};

BigCoinItem.cpp

#include "BigCoinItem.h"

ABigCoinItem::ABigCoinItem()
{
	PointValue = 50;
	ItemType = "BigCoin";
}

void ABigCoinItem::ActivateItem(AActor* Activator)
{
	DestroyItem();
}

SmallCoinItem.h

#pragma once

#include "CoreMinimal.h"
#include "CoinItem.h"
#include "SmallCoinItem.generated.h"

UCLASS()
class SPARTAPROJECT_API ASmallCoinItem : public ACoinItem
{
	GENERATED_BODY()

public:
	ASmallCoinItem();	// 생성자

	virtual void ActivateItem(AActor* Activator) override;

};

SmallCoinItem.cpp

#include "SmallCoinItem.h"

ASmallCoinItem::ASmallCoinItem()
{
	PointValue = 10;
	ItemType = "SmallCoin";
}

void ASmallCoinItem::ActivateItem(AActor* Activator)
{
	DestroyItem();
}

e. HealingItem

BaseItem 상속 받음

HealingItem.h

#pragma once

#include "CoreMinimal.h"
#include "BaseItem.h"
#include "HealingItem.generated.h"

UCLASS()
class SPARTAPROJECT_API AHealingItem : public ABaseItem
{
	GENERATED_BODY()

public:
	AHealingItem();	// 생성자
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	float HealAmount;	// 회복량	
	

	virtual void ActivateItem(AActor* Activator) override;

};

HealingItem.cpp

#include "HealingItem.h"

AHealingItem::AHealingItem()
{
	HealAmount = 20.0f; // 기본 회복량 설정
	ItemType = "Healing";
}

void AHealingItem::ActivateItem(AActor* Activator)
{
	DestroyItem();
}

f. MineItem

똑같이 BaseItem 상속 받음

MineItem.h

#pragma once

#include "CoreMinimal.h"
#include "BaseItem.h"
#include "MineItem.generated.h"

UCLASS()
class SPARTAPROJECT_API AMineItem : public ABaseItem
{
	GENERATED_BODY()

public:
	AMineItem();	// 생성자

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	float ExplosionDelay;	// 폭발 지연 시간
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	float ExplosionRadius;	// 폭발 범위
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	float ExplosionDamage;	// 폭발 피해
	
	virtual void ActivateItem(AActor* Activator) override;
};

MineItem.cpp

#include "MineItem.h"

AMineItem::AMineItem()
{
	ExplosionDelay = 5.0f; // 기본 폭발 지연 시간 설정
	ExplosionRadius = 300.0f; // 기본 폭발 범위 설정
	ExplosionDamage = 30.0f; // 기본 폭발 피해 설정
	ItemType = "Mine"; // 아이템 타입 설정

}

void AMineItem::ActivateItem(AActor* Activator)
{
	DestroyItem();
}

아이템들 모두 완성 ~


💭

아이템 만들 때 하나하나 따로 구현하는 것보다

1️⃣ 공통된 건 인터페이스로 빼고
2️⃣ 동작은 추상 클래스로 순수 가상 함수 만들어서
3️⃣ 자식 클래스에서 오버라이드하는
이 방식이 훨씬 편한 것 같다.

구조도 눈에 잘 들어오고 리플렉션으로 블루프린트에서도 수정할 수 있어서 C++이랑 블루프린트를 같이 쓰는 일이 생각보다 많은 것 같다.
나중에 강의 한 번 더 들어서 익숙해져야겠다!

0개의 댓글