목록Categories (1104)
KoreanFoodie's Study

멀티플레이어 서버의 유형 peer - to peer 각각의 플레이어가 세션을 가지고, 움직임이나 게임 데이터의 변경이 있을 경우 연결된 다른 세션의 사용자에게 이를 전파한다. A 에서 플레이어가 캐릭터를 움직였다고 했을 때, 움직인 좌표를 다른 컴퓨터에게 전달하기 전까지 다른 컴퓨터에서는 A의 데이터 변경이 조회되지 않는다. Client - Server Model Client - Server Model 에서는, 각 클라이언트들이 어떤 동작을 하게 되면, 데이터의 변경을 Server 로 request 한다. Server 에서는 정합성이 있는 상태를 갖고 있으며, 이를 다른 클라이언트들에게 전파하는식으로 위치나 상태 등을 업데이트 한다. Client - Server Model 은 크게 Listen-Serve..

UPoseableMeshComponent 언리얼에서 GhostTrail 등을 구현할 때, UPoseableMeshComponent 를 사용하는 것을 볼 수 있다. UPosebleMeshComponent 는 무엇일까? 먼저 정의로 넘어가보면, /** *UPoseableMeshComponent that allows bone transforms to be driven by blueprint. */ UCLASS(ClassGroup=Rendering, hidecategories=(Object,Physics), config=Engine, editinlinenew, meta=(BlueprintSpawnableComponent)) class ENGINE_API UPoseableMeshComponent : public ..

모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! ThreadPool 간단 요약 ThreadPool 에 우리가 원하는 작업을 추가하면, 쓰레드풀에 있는 쓰레드가 이를 맡아 작업하게 된다. 이 글에서는 쓰레드에 새로운 작업을 추가하는 일을 queue 를 통해 처리한다. 이곳의 구현을 기초로 하여 작성했다. 모든 쓰레드가 작업중이어도 새로운 작업을 추가해도 상관없다! 클래스 설계하기 먼저 쓰레드들을 보관할 컨테이너가 필요하다. // 총 Worker 쓰레드의 개수. size_t num_threads_; // Worker 쓰레드를 보관하는 벡터. std::vector worker_threads_; 편의상, 쓰레드풀에서 돌아가는 쓰레드들을 ..

모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! 동기와 비동기 C++ 코드는 순차적으로 실행된다. 예를 들어, 파일을 읽고, 읽은 파일로 어떤 작업을 하고, 마지막으로 파일과 관계없는 작업을 수행하는 코드가 있다고 가정해 보자. 이 경우, 파일과 관계없는 작업을 하기 위해 파일을 읽기까지 기다려야 하는 지연 시간이 존재한다. 이전에 배운 쓰레드를 이용하면 이 작업을 비동기적으로 바꾸어 줄 수도 있다. void file_read(string* result) { string txt = read("a.txt"); *result = do_something_with_txt(txt); } int main() { string result; t..

AttachedActors vs ChildActors 만약 다음과 같이 부모 액터에 부착된 액터들을 삭제하려고 하면 어떻게 해야 할까? 만약 현재 액터에 자식으로 설정된 ActorComponent 들의 경우, 다음과 같은 코드로 조회할 수 있다. TArray tempChildActors; AActor* owner = GetOwner(); // SomeChildActor->SetOwner(this); 가 어디선가 실행되었다고 가정 owner->GetAllChildActors( tempChildActors, true ); uint32 count = tempChildActors.Num(); 하지만 위와 같은 경우나, 무기를 캐릭터의 소켓에 부착 (AttachToComponent) 하는 경우..

오브젝트 생성 및 애셋 불러오기 언리얼에서 오브젝트를 생성하고 애셋을 불러올 때는 보통 CreateDefaultSubobject 로 CDO 를 만들어 준 다음, ConstructorHelpers::FObjectFinder 로 애셋을 연결시켜 준다. 이 과정을 단축시켜주는 Helper Function 을 만들어 사용해 보자. CHelpers.h #pragma once #include "CoreMinimal.h" #include "Components/SkeletalMeshComponent.h" #include "Kismet/GameplayStatics.h" #include "Particles/ParticleSystem.h" #include "NiagaraSystem.h" #include "NiagaraFun..

화면에 출력하는 로깅시스템 콘솔에 출력했던 것과 비슷하게, 이번에는 UE_LOG 가 아닌 AddOnScreenDebugMessage 함수를 활용해 화면에 값을 출력해보자. 출처는 여기! CLog.h class UE_PROJECT_NAME_API CLog { public: static void Print(int32 InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue); static void Print(float InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue); static void Print(const FString& I..

언리얼 로그 언리얼은 UE_LOG 함수를 이용하여 로그를 출력한다. 먼저, .h 파일에 카테고리를 선언하고, 그에 맞는 정의를 .cpp 파일에서 Define 해주면 된다. MyGame.h //General Log DECLARE_LOG_CATEGORY_EXTERN(LogMyGame, Log, All); //Logging during game startup DECLARE_LOG_CATEGORY_EXTERN(LogMyGameInit, Log, All); MyGame.cpp #include "MyGame.h" //General Log DEFINE_LOG_CATEGORY(LogMyGame); //Logging during game startup DEFINE_LOG_CATEGORY(LogMyGameInit); 헤더..

모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! 파이프라이닝 다음과 같은 코드가 있다고 하자. int a = 0; int b = a + 1; a = 1; 직관적으로는 b = a + 1 이 a = 1 보다 먼저 실행될 것 같지만, 컴파일러가 어셈블리 언어로 번역한 것을 보면 a = 1 이 더 먼저 실행되기도 한다. 물론 b 와 a 에는 각각 1이라는 값이 제대로 들어가지만, 컴파일러는 작업의 효율성을 위해 코드의 실행순서를 변경한다. 이를 파이프라이닝이라고 부른다. 이는 최적화를 위해 어셈블리 명령어를 효율적으로 배치하는 과정을 의미한다. 수정 순서(Modification Order) 명령어를 뒤죽박죽으로 실행하는데도 어떻게 제대로..

모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요! Race Condition 서로 다른 쓰레드에서 같은 메모리를 공유할 때 발생하는 문제를 경쟁 상태(race condition) 이라고 부른다. 다음 코드를 보자. #include #include #include void worker(int& counter) { for (int i = 0; i < 10000; i++) { counter += 1; } } int main() { int counter = 0; std::vector workers; for (int i = 0; i < 4; i++) { // 레퍼런스로 전달하려면 ref 함수로 감싸야 한다 (지난 강좌 bind 함수 참조) ..