4월, 2026의 게시물 표시

내일배움캠프 48일차 - 언리얼 C++에서 배우고 싶은 내용 : Tick그룹?

언리얼 C++ 과제를 하면서 특정 상태를 틱 단위로 확인해야 하는 변수 를 만들었는데, Tick함수가 끝나는 직후 변수를 초기화 를 해야하는데, 틱이 처리되는 범위 밖에서 실행되는 바인딩 함수 등 에서 해당 변수의 상태를 체크할 경우 이미 초기화가 되어서 실제로 확인된 상태와 전혀 다르게 작동하는 문제 가 있었다. 이걸 해결하는 방법에 대해 찾아보다, 유니티에서는 Update()와 LateUpdate()를 구분해서 사용 하는 것을 떠올리고 이곳 언리얼에서도 같은 기능이 있나 찾아보다 Tick그룹 이란 것을 발견했다. 이것은 기존 Tick과는 다르게 렌더링 전에 미리 실행되거나, 모든 처리가 끝난 후에 실행되게 끔 시점을 변경할 수 있다 고 하는데, 구글을 찾아봐도 잘 이해가 되지 않는 부분이 많아 우선 변수를 두 개 사용하여 상태를 처리하고 다음에 강사님에게 여쭤봐야할 것 같다는 생각이 들었다.

내일배움캠프 47일차 - 자료구조 & 알고리즘 7주차 : 재귀

이미지
 재귀  - 함수가 자기 자신을 호출하는 것을 일컫는다. 예) 팩토리얼(Factorial) 재귀가 동작하기 위해서는 두 가지 조건이 필요하다. 1) 재귀호출: 자기 자신을 호출하되, 종료지점에 가깝게 문제가 작아진다. 2) 종료조건(Base case): 더이상 호출하지 않는 지점 내려가면서 호출하고, base case(돌아오는 값)을 만나면 거슬러 올라오면서 계산한다. 재귀 함수는 우리가 직접 스택을 만들지 않아도 자동으로 콜 스택을 사용 한다.  - 재귀 로 풀 수 있는 것 = 스택 + 반복문 으로도 풀 수 있다.  - 재귀 가 더 깔끔할 때 가 있고, 반복문 이 더 효율적일 때 가 있다. 종료 조건이 없으면 발생하는 문제 - 무한 호출 위 사진처럼 재귀호출을 하지않는 시점이 없으면 무한호출이 발생 한다. 호출이 지나치게 잦으면(약 1만번 초과)  콜 스택 메모리(보통 1~8MB) 가 가득하게 되어 프로그램 크래시 가 발생 한다. 이를 스택 오버플로우(Stack Overflow) 라고 한다. 무한 호출을 방지하기 위해 재귀 전 종료 조건(base case) 를 작성해야 한다. 재귀 사용 예시  - 피보나치 수열 (재귀의 함정)  - 배열의 합 (재귀적 분해)  - 거듭제곱 (분할 정복 재귀)

내일배움캠프 46일차 - 언리얼 C++: Pawn을 이용해 비행체를 만들어보자

이미지
Pawn클래스를 이용한 비행체 만들기 Pawn클래스에 EnhancedInput을 사용해 입력에 따라 정해진 행동을 취할 수 있는 비행체를 만들어보도록 하자. 향상된 입력(Enhanced Input) 과거 UE4시절에는 프로젝트세팅에 들어가 필요한 입력키를 일일이 할당했으나 UE5에서는 향상된 입력(EnhancedInput)이란 기능이 도입되면서 파일 단위로 입력을 관리할 수 있게 되었다. 해당 기능을 사용하기 위해서는 아래에 두 데이터 에셋을 추가하도록 한다. 입력 매핑 컨텍스트(IMC, InputMappingContext)  : 컨트롤러가 사용할 입력들을 한데 모아 놓은 에셋  : 가져온 IA에 키를 할당하고 작동 방식을 정의할 수 있다. 입력 액션(IA, InputAction)  : 특정 행동을 나타내는 액션, 주로 입력받을 값의 타입을 정의한다. (bool, float, Vector2D 등...) 캐릭터에는 일반적으로 이동(WASD키), 카메라회전(마우스 XY이동)을 사용하므로 두 기능을 넣은 IMC를 만들어보자. IA (카메라회전, 캐릭터이동), IMC (비행체의 조작그룹)

내일배움캠프 45일차 - 언리얼 C++: 장애물을 만들어 플랫포머 구현하기 3

이미지
움직이는 장애물을 만들어 플랫포머 구현하기 1 움직이는 장애물을 만들어 플랫포머 구현하기 2 움직이는 장애물을 무작위 배치하기 이전에 경로를 따라 움직이는 장애물, 회전하는 장애물을 만들어봤다. 이제 이것을 월드 상에 무작위로 배치하는 로직을 구현해보자. 플레이어가 움직일 수 있는 영역 내에 장애물을 배치하기 위해 적당한 플랫폼 영역을 배치해준다. 장애물 배치영역이 될 플랫폼 파티션(좌) 이들을 합친 맵 전체 영역(우) 이 프로젝트에서는 일자형태의 커다란 맵에 갖가지 장애물을 무작위로 배치하여 이들을 뚫고 완주지점에 도착하는 것을 게임목표로 삼을 것이다. 이를 위해 맵의 구성요소인 도로를 위의 장애물들을 생성하는 액터로 만들어 일정간격으로 배치하도록 한다. 장애물 생성액터(ARoad) 빨간 영역이 장애물 생성 영역(UBoxComponent)이다. ARoad 액터에는 루트가 될 USceneComponent , 실체를 이루는 UStaticMeshComponent , 그리고 장애물 생성영역을 나타내는 UBoxComponent 로 구성되어있다. ARoad위에 월드 상 장애물을 생성하는 방법 은 다음과 같다. 1) 스폰지점 FVector를 정의한다. 장애물 생성영역 UBoxComponent 의 위치 와 Extent 를 설정하고 UKismetMathLibrary::RandomPointInBoundingBox() 를 사용해 영역 내 스폰될 위치(FVector)을 지정 한다. 또한 회전, 스케일링 등으로 실제 위치가 다를 수 있음을 고려해 UBoxComponent 의 GetComponentTransform().TransformPosition() 을 사용해 위치를 컴포넌트 기준으로 재계산 해준다. 2) 스폰지점이 정의되면 그 지점이 정말로 생성하기 적합한지를 테스트한다. 장애물이 무작위로 스폰되다보면 스폰지점이 겹치는 부분도 있을 것이다. 겹치게 되면 시각적으로 부자연스러워지고 퀄리티가 떨어진다. 때문에 겹쳐지는 것을 막기 위해 장애물에 USphereComponennt 등...

내일배움캠프 44일차 - 언리얼 엔진 C++ 심화 3 : 콜리전과 트레이스

이미지
콜리전(Collision) 두 물체간의 충돌 판정에 대한 옵션. 혹은 충돌 그 자체에 대한 용어를 가리킨다. 오브젝트 A,B에 대한 상태 별 충돌판정 Ignore: 무시 Overlap : 겹치면 판정발생 Block: 부딪히면 물리적충돌 발생 프로젝트 세팅 - 엔진 - 콜리전에서의 옵션 오브젝트채널: 내가 이러한 이름의 오브젝트임을 나타내는 채널 트레이스채널: 내가 이러한 이름의 트레이스임을 나타내는 채널 ex1) Visibility: 조준선 등에 사용하는 트레이스 ex2) Camera: 카메라 스프링 암 등에 사용하는 트레이스 프리셋: 내가 이런 채널속성이며 다른 오브젝트/트레이스 타입에 대한 이러한 충돌옵션을 가졌음을 정한다. 트레이스(Trace) 트레이스 는 한 방향으로 선을 쬐어 경로상 오브젝트의 충돌을 판정하는 기술이다. 트레이스에는 크게 세가지 종류가 있다. 싱글 트레이스(SingleTrace)  : 하나만 인식하는 충돌검사. 가장 먼저 충돌한 물체 하나만 반환한다.  : Block에만 영향을 끼친다. 멀티 트레이스(MultiTrace)  : 여럿을 인식하는 다중 충돌검사. 경로상 충돌판정을 일으킨 모든 물체를 반환한다.  : Overlap에 관통하면서 영향을 끼치며, Block에도 영향을 끼친다. 비동기 트레이스(AsyncTrace)  : 트레이스를 스레드로 실행 시켜 결과를 나중에 받는 트레이스방법. 수많은 물체를 트레이스할때 사용한다.  : 트레이스 종료 시 Delegate에 할당된 함수를 실행 해 결과물을 받는다. Simple And Complex: Object채널은 단순콜리전으로, Trace채널은 복합콜리전으로 충돌을 계산한다. bCauseByWorld: 죽은 원인을 월드에서 가져오기 DamageImpuse: 피격 시 밀려나는 량 DestructibleVelChange: 파괴 시의 밀려나는 량

내일배움캠프 43일차 - 아직은 모르는 부분이 많은 언리얼 C++

그동안 여럿 과제들을 하면서 여러 난관에 부딪혔으나, 대부분 강의 외의 내용을 활용해 과제를 구성하는 과정에서 주로 기본적이 사용법을 모르는 상태라 '이 상황에서 사용해야할 함수' , '여기서는 쓰면 안되는 함수' 등 단순한 검색만으로는 찾기 어려운 문제 위주 로 곤란을 겪어 문제를 정리하는 데 큰 난항을 겪고있다. 이에 대해 강사님들에게 질문을 구해보았으나 대부분 내가 찾는 문제들은 관련강의가 근시일내로 준비되어있다는 답변을 받았기에 문제해결은 다음을 기약하기로 했다. 지금은 모르는 내용보다는 밀린과제들을 해결하는데에 중점을 두고있기에 오늘은 새로운 지식이나 해결과정을 정리한 TIL은 쓰기 어려울 것 같다. 좀 더 언리얼에 대한 지식을 쌓고 쉽게 문제에 막히지 않는 바탕지식을 갖추어졌으면 하는 바람이다.

내일배움캠프 42일차 - 자료구조 & 알고리즘 7주차 : 정렬 알고리즘

이미지
느린 정렬들 - O(n^2) 버블 정렬 - "옆 사람과 비교" 인접한 두 원소를 비교해서, 순서가 잘못되었으면 교환한다. 한 바퀴 돌면 가장 큰 값 이 맨 뒤로 떠오른다. ※ 거품이 수면 위로 떠오르듯, 큰 값이 뒤로 밀려나서 버블정렬 이다. 예시) 53 814 → 3 58 14 → 35 81 4 → 351 84 →3514 8   → 35 14 8 → 3 51 4 8 → 31 54 8 → 314 5 8 → 31 4 58 → 1 34 58 → 13 458 → 13 458 → 13458  : 사이클 마다 n → n-1 → n-2 → ... → 총 n(n-1)/2 번 비교  → O(n^2) 선택정렬 - "가장 작은 걸 찾아서 앞에" 전체에서 가장 작은 값 을 찾아 첫 번째 위치 에 놓고, 나머지는 가장 작은 값 을 찾아 두 번째 위치 에 놓는 것을 반복. ※ 사람이 눈으로 훑어서 "이게 제일 작네!" 하고 고르는 가장 인간적인 방법 이다. 예시) 5 38 1 4 → 1 38 5 4 → 1 3854 → 1 3 854 → 13 854 → 13 8 5 4 → 13 4 5 8  → 134 58 → 134 5 8  → 13458  : 버블교환에 비해 한 사이클 당 교환횟수는 적지만, 값을 전부 비교 해서 최솟값을 찾는다.  → O(n^2) 삽입 정렬 - "카드를 한장씩 끼워넣기" 두 번째 원소부터 시작 해서, 이미 정렬된 앞부분 에 적절한 위치에 삽입한다. ※ 사람이 카드를 정렬할 대 가장 자연스럽게 하는 방법. 예시) 5 3 814 → 35 814 → 35 8 14 → 358 14  → 358 1 4 → 135 8 4 → 1358 4 → 13458  : 앞 부분은 이미 정렬된 것 으로 간주하고 두번째 원소 부터 시작, 정렬된 부분의 맨 뒤 부터 역순으로 비교 해서 적절한 위치에 삽입 한다  : 앞 부분 의 맨 앞 에 삽입 되면 모든 원소...

내일배움캠프 41일차 - 액터 내 오브젝트/컴포넌트의 올바른 생성방법

언리얼 C++ 강의와 과제를 진행하면서 겪었던 문제나 어려움은 대부분 내가 사용한 변수타입이나 함수의 사용법이 잘못됨에서 비롯된 것들이었다. 이번에 내가 잘못 사용했던 변수/함수의 제대로 된 사용법 과 특정상황에서 사용해야하는 것 들을 정리해보도록 하자. 1) 액터 내에서 오브젝트를 생성할 때 액터 내에서 오브젝트를 생성할 때 사용하는 함수는 크게 세가지가 있다. 1. CreateDefaultSubObject < ObjectType >(FName SubobjectFName ) 생성자에서 컴포넌트를 생성 할때 사용하는 함수이다. 이 함수는 오직 생성자내에서만 사용 이 가능 하며, 다른 함수에서 사용하면 크래시가 발생한다. 2. AddComponentByClass ( 클래스 타입 , 수동어태치 여부 , Transform 초기값 , DeferredFinish=false) 런타임중에서 컴포넌트를 생성 하고 싶을 때 사용하는 함수이다. 이 함수는 생성자 외 다른 함수에서 사용 할 수 있으며, 자동 어태치일때 root컴포넌트에 자동적으로 붙는다. 최종적으로 컴포넌트를 완성시키려면 Component->FinishAddComponent( ) 를 사용해야한다. 3. NewObject < ObjectType >() 런타임중에서 오브젝트를 생성 하고 싶을 때 사용한다. 컴포넌트 아닌 오브젝트 는 이것으로 만들 수 있으며 , 컴포넌트를 생성할 수도 있지만 권장되지 않는다. ※ SpawnActor < ObjectType >( UClass* class ); 사용 시 주의사항 SpawnActor를 사용할 때 class타입을 동적으로 추가하고 싶을 때 명시된 대로 UClass*로 넣는 것이 좋다. TSubClassOf등을 대신 넣어버리면 클래스타입이 제대로 반영되지 않아 nullptr로 인식 되기도 한다.

내일배움캠프 40일차 - 언리얼 C++: 장애물을 만들어 플랫포머 구현하기 2

이미지
  움직이는 장애물을 만들어 플랫포머 구현하기 1 "회전하는 장애물"을 활용한 플랫포머 구현 이전에 지정한 스플라인을 따라 움직이는 장애물을 만들어보았다. 그렇다면 이번엔 회전하는 장애물을 만들어보도록 하자. 회전하는 장애물 은 배치된 지점을 중심으로 회전 하므로, 움직이는 장애물과 달리 움직이지 않아 Spline곡선으로 움직일 필요가 없어 SetRelativeRotation() 으로 움직이기만 하면 될 일이다. 따라서 난수가 적용된 회전장애물에서 필요한 변수는 다음과 같다. 회전 장애물에 배치할 스태틱메시 는 회전을 할 때 유의미한 장애물이 될 정도로 모양이 변해야 한다. 따라서 그 모습을 구현하기 위해 아래처럼 여러 개의 메시를 뭉친 형태 가 될 것인데. 이를 구현하려면 분명 많은 수의 컴포넌트가 필요 할 것이다. 구현하고자 하는 회전장애물의 형태 하지만 이를 구현하기 위해 여러 개의 변수를 만들어둘 필요는 없다 . 언리얼 C++에서는 여러개의 컴포넌트를 저장한 TArray 또한 UPROPERTY에 의해 일괄적으로 적용을 받을 수 있기 때문 이다. 따라서 여러개의 컴포넌트를 정의하기 위해 아래와 같이 선언을 한다.

내일배움캠프 39일차 - 언리얼 엔진 C++ 심화 2 : 컨테이너와 포인터

이미지
TObjectPtr  - TObjectPtr은 UE5 에서 도입된 템플릿 스마트 포인터 이다.  - UE4 의 원시포인터 UObject* 를 대체 하기 위해 사용되었다. 에디터 환경 전용으로 설계되어 두 가지 핵심 기능 을 제공한다. 1. 지연로딩: 변수가 실제로 접근될 때만 리소스가 로드 되어 시작 시 메모리 과부하를 방지 2. 액세스 트래킹: UPROPERTY 변수가 어디서 참조되고 있는지 정밀하게 식별, 지원 한다. TObjectPtr 사용 규칙과 성능 TObjectPtr 권장 사용: 헤더 파일의 UPROPERTY 변수  : UE5에서 권장하는 표준방식으로, 지연 로딩 과 액세스 트래킹 을 완전히 지원한다. ex) TObjectPtr<UObject> ptr; ※ TObjectPtr을 사용해도 게임성능은 향상되지 않습니다.  : 패키징(출시) 배포 후의 TObjectPtr 은 원시포인터 로 자동변환 된다. 원시 포인터 사용: 지역 변수 , 함수 매개변수  : 이 경우 참조 대상 객체가 이미 메모리에 존재 하므로 로딩 로직이 필요없어 원시 포인터 가 더 직접적이고 효율적 이다. ex) UObject* ptr; 언리얼 컨테이너 언리얼의 컨테이너는 크게 세가지로, TArray, TSet, TMap 이 있다. 각각 vector, set, map의 기능을 한다. TObjectPtr 컨테이너 순회방법 TObjectPtr 컨테이너를 순회할 때 반복자 타입 선택은 중요하다. auto * 로 순회: 비권장. 매 반복마다 내부 로드 검사를 실행하여 성능저하가 발생 한다. auto* 순회는 비권장. auto & 로 순회: 권장. 컨테이너 내 TObjectPtr 자체를 직접 참조 하여 내부 로드, 주소 계산 과정을 생략 하여 최적의 성능 을 발휘한다. auto& 순회를 권장 TSubclassOf - 클래스 레퍼런스 컨테이너 인스턴스가 아닌 타입을 저장 - '어떤 클래스를 사용할지 엔진에 ...