| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
- C++
- 크리티컬섹션
- tweakobjectptr
- moreeffectiveC++
- 프로그래머스
- 데이터애셋
- 약참조
- C++최적화
- UE_LOG
- dataasset
- makeweakobjectptr
- 스마트포인터
- map
- 자료구조
- unorder_map
- 정렬알고리즘
- 구조적 바인딩
- 강참조
- 애셋로드
- 정렬
- 알고리즘
- 선택정렬
- 델리게이트
- BFS
- stl
- UML관련
- 람다
- enumasByue
- 언리얼가비지컬렉터
- 비동기호출방법
- Today
- Total
목록Note (439)
기억을 위한 기록들
#include static int GetRandomInt(const int Min, const int Max){ static std::random_device RD; static std::mt19937 Gen(RD()); std::uniform_int_distribution Dist(Min, Max); return Dist(Gen);} 게임 개발을 하다 보면 랜덤이라는 값에 대해 필요로 하는 경우가 있다.몬스터 스폰, 드롭 테이블, 크리티컬 판정, AI의 의사결정…등등랜덤이 개입하는 곳은 많고, 이 랜덤의 품질이 낮으면 게임 자체 전반의 결과가 단조롭고 예측 가능해진다는 문제가 생긴다. C++11부터는 이라는 새로운 랜덤 시스템이 도입되었고,그 중심에는 std::random_d..
FGCObject란 언리얼 엔진의 가비지 컬렉션(이하 GC) 시스템에게 "이 UObject는 내가 가지고 있으니 지우지 마"라고 알려주는 인터페이스이다.UPROPERTY()가 없이 보관해야 할 경우 GC가 모르게 들고 있다가 크래시나는 문제를 해결하는 안전한 방법이다. 언리얼엔진의 GC는 UObject를 자동으로 추적하지는 않는다.GC가 자동으로 추적하는 경우는 다음과 같다.리플렉션 시스템에 등록된 객체일 경우RootSet에 등록 된 경우 문제는 다음과 같은 경우들에서 발생한다.일반 C++ 클래스에서 UObject* 포인터를 저장할 경우TSharedPtr안에서 UObject 넣어야 할 경우커스텀으로 사용하는 UObjectPoolingManager 처럼 GC 외부에서 관리하는 경우 GC 입장에서는 이렇게..
enum에 값을 넣을때, 정수 값과 비트플래그(bitmask) 두 방식이 있다.두 방식은 쓰임새가 다르며, 목적이 달라지기에 상황에 따라 선택해야 한다. 정수 enum정수 enum은 일반적으로 단일 상태를 표현한다.ex) 캐릭터가 여러 상태 중 하나만 가질 수 있을 경우enum class ECharacterState : uint8{ Idle = 0, Run = 1, Jump = 2,};이 3개 중에 하나의 상태로 될 수 있다.ECharacterState State = ECharacterState::Run; 특징으로는 구조가 단순하다.비교와 switch가 직관적이다.상태가 오직 하나여야 할 때 적합하다. 비트 플래그 enum 비트 플래그 enum은 각 enum 값을 비트 단위로 분리하여 조..
1. 들어가며언리얼 엔진에서 멀티플레이 게임을 개발하려면 RPC(Remote Procedure Call)와 Replication의 정확한 이해가 필수적이다. 언리얼은 서버-클라이언트 구조를 기반으로 하고 있으며, 단순히 UFUNCTION()을 호출한다고 해서 클라이언트와 서버가 같은 결과를 얻는 것은 아닙니다. 이 글에서는 RPC의 종류, Replication의 원리, 그리고 클래스별 네트워크 특성을 정리해보려고한다. 참고 자료 : https://dev.epicgames.com/documentation/ko-kr/unreal-engine/remote-procedure-calls-in-unreal-engine 2. 왜 중요한가?멀티플레이 게임에서 가장 큰 문제는 데이터 불일치입니다.클라이언트에서만 ..
C++17에서 도입된 std::optional은 “값이 있을 수도 있고, 없을 수도 있는 상태”를 안전하게 표현하기 위한 도구이다.단순히 nullptr 체크나 특별한 값(-1, 0 등)으로 “없음”을 나타내는 것보다 훨씬 명확하고 타입 시스템 차원에서 안전하다. 왜 생겼을까?기존에는 “없음”을 표현하는 방법이 불완전했습니다.포인터 타입: nullptr 사용 가능 → 하지만 값 타입(int, float, struct 등)은 불가능특별한 값(-1, 0 등): 의도 전달이 불명확하고, 실제 유효 값과 충돌 가능예외(throw): 코드 복잡성 증가optional은 이러한 문제를 해결합니다. 반환값, 선택적 인자, 실패 가능 함수 등에서 “없음”을 타입으로 강제 표현하므로, 코드 가독성과 안정성이 높아집니다. ..
함수 객체란 함수처첨 동작하는 객체를 뜻하며, 클래스의 객체가 () 연산자를 오버로딩해서 함수 호출처럼 쓸 수 있게 만든 것이다. 객체로 존재하므로 멤버변수를 넣어, 상태값을 가질수도 있다는 장점이 있다. stl 사용 예시#include #include #include struct Multiply { int factor; // 곱할 값 // 생성자로 상태 저장 Multiply(int f) : factor(f) {} // 함수 호출 연산자 오버로딩 int operator()(int x) const { return x * factor; }};int main() { std::vector nums = {1, 2, 3, 4}; M..
함수 포인터와 람다 함수는 모두 "함수를 다른 코드에 전달" 할 수 있게 해주는 역할을 하고 있다.각각에 대해서 자세한 설명은 이 글에서 다루지 않고, 이 글에서는 각각의 특징 및 차이점에 대해 다룰 것이다.우선 사용 예를 먼저 보면, 함수포인터 예:#include void PrintMessage(const char* msg) { std::cout 람다 예 : #include int main() { int repeat = 3; auto lambdaFunc = [repeat](const char* msg) { for (int i = 0; i 정의 :함수 포인터의 정의로는 함수의 주소를 저장하고 호출할 수 있는 변수이며, C 시절부터 존재했다.람다 함수의 정의로는 코..
https://medium.com/devserum/5%EB%85%84%EC%9D%98-%EB%B0%A4-326eaf77f60e 5년의 밤‘518일동안 단 하루도 빠지지 않고 알고리즘을 풀었다.’의 후속글medium.com 아마 이 분의 글을 몇 년전에 어디선가 보고 인상깊게 남았던거같은데, 블로그 이주를 하신걸 보고 혹시나 나중에 못찾을까봐 기록해둔다.
C++에서 printf처럼 인자의 개수가 고정되지 않은 함수를 구현할 일이 있다면, va_start를 중심으로 한 헤더의 가변 인자 매크로들이 필요하다. 이 매크로들은 C 스타일에서 유래했으며, 여전히 시스템 프로그래밍이나 엔진 코드에서 종종 사용된다고 한다. va_start 매크로란?va_start는 가변 인자를 순차적으로 읽기 위한 준비를 하는 매크로이다. 함수에서 고정된 인자 이후에 몇 개의 인자가 더 들어올지 알 수 없기 때문에, 컴파일 타임이 아닌 런타임에 인자 목록을 읽어야 한다.이때 va_list라는 타입을 선언하고, va_start를 통해 이 목록의 시작 위치를 잡습니다. 이후 va_arg로 하나씩 꺼내쓰고, 마지막엔 va_end로 정리합니다. 예 : #include #include ..
언리얼엔진에서 월드 내의 특정 액터들을 효율적으로 찾고 순회하는 방법으로 TActorIterator 라는 템플릿 클래스가 있다. UWorld안에 존재하는 액터들을 타입 기반으로 자동 필터링하며 순회하는 템플릿 반복자로써, 액터들을 찾기 위한 함수 중에 하나로 GetAllActosOfClss() 라는 함수를 예전에 사용 했었지만, 결국 이 함수도 내부적으로 TActorIterator를 기반으로 TArray를 할당하고 복사를 발생시켜 비용이 크다. 예시) 월드안에 있는 AMyEnemy 기반 혹은 자식 클래스 액터 탐색하기for (TActorIterator It(GetWorld()); It; ++It){ AMyEnemy* Enemy = *It; if (Enemy->IsAlive()) ..
언리얼엔진에서 UObject 객체들에 참조하려고 할 때, 유효성 검사하더라도 포인터만 남아서 문제가 생길 때가 있다. UObject* CachedObject = GetSomeObject(); // 이 시점엔 유효// ...if (CachedObject) // 이게 true라도 실제 메모리는 이미 파괴되었을 수 있음{ CachedObject->DoSomething(); // 크래시 가능} 혹은 FTimerDelegate TimerDel;TimerDel.BindLambda([=](){ MyObject->DoSomething(); // MyObject는 이미 GC에 의해 삭제됐을 수 있음 });이럴때의 TWeakObjectPtr 템플릿으로 감싸서 IsValid 검사를 하며 사용할 수 있다. 객체가..
블루프린트에서 비동기방식을 다루고 싶다면 UBlueprintAsyncActionBase 클래스를 사용하자. 옛날에 블루프린트 상에서 다른 애셋에 대한 로딩을 하는 과정에서 기다리기 위해 임의로 delay 블루프린트 함수를 쓰는 걸 본 적이 있었다. 다른 좋은 방법은 그 당시에 생각나지 않았고, delay로 임의의 시간을 입력하고 그렇게 사용하는게 좋지 않다는 것만 인지하고 지나간 기억이 있다. 그러다가 최근에 알게된 클래스가 UBlueprintAsyncActionBase 이다. 예를 들어 서버 요청 응답, 외부 SDK 호출이나 다운로드, 내부 로직 처리 대기 등등 을 블루프린트에서 기다리고 싶을때 UBlueprintAsyncActionBase 클래스를 사용하면된다. 예로 살펴보면 해당 코드는 LyraS..