2026-02-25 TIL (3일차)
Unreal 강의 내용
Unreal 흐름 제어 노드 종류
구분 반복 여부 특징 For Loop O 정해진 횟수만큼 반복 While Loop O 조건이 맞을 때까지 반복 For Each Loop O 배열의 크기가 만큼 반복 Switch (on Enum/Int) X 값에 따라 준비된 여러 길 중 하나로 분기 Branch X 조건에 따라 한 번만 실행 Sequence X 여러 일을 순서대로 실행 Set Array Elem 기본 변수 노드의 Set과 동일한 개념으로 배열안에 있는 값들을 Set 할 때 사용합니다.
과제 트러블 슈팅 과제 목록
1번 과제: 30발 이상 격발 할 수 있는 버그, 총알이 가득차 있는 경우에도 재장전 되는 버그
2번 과제: 과열 상태 추가, 쿨다운 기능
(속성을 추가하고 한 발당 1씩 총기 온도가 증가하게끔 로직, 특정 키를 누를때마다 총기의 온도가 내려가게끔 구현)
3번 과제: 무기 추가하기
(0번을 누르면 라이플, 1번을 누르면 샷건, 2번을 누르면 피스톨로 교체됩니다.격발하면 현재 무기의 총알만 소모하고, 과열 상태도 현재 무기만 과열됩니다.)이렇게 과제를 진행하던 도중 3번 과제를 하면서 무기마다 할당한 총알 수가 다른데 현재 내가 작성한 코드는 30발로 고정되어 있었습니다.
그래서 50발로 선언한 무기도 30발을 기준으로 장전하고 30발만 장전하는 문제가 발생했습니다.
할당된 bullet 기준으로 비교하자니 상호작용 일어날 때마다 값이 달라지므로 문제가 생깁니다.
저는 선언한 구조체에서 MaxBullet값을 추가해 총의 기본 최대 총알 수를 기억하게합니다. 이 MaxBullet를 통해 최대 총알 수로 장전하고 값을 비교하여 문제를 해결했습니다.
C++ 공부하기
변수의 범위
변수 종류 이름 유효 범위 사용법 수명 전역 변수 프로젝트 전체(다른 파일에도 사용가능) 함수 외부에서 선언, 다른파일에서는 extern으로 사용 프로그램 종료 시까지 정적 전역 변수 해당 파일 내부 (자기 파일만) 함수 외부에서 static으로 선언 프로그램 종료 시까지 정적 지역 변수 {} 블록 내부만 static 프로그램 종료 시까지 지역 변수 {} 블록 내부만 기본 선언 함수 종료 시 즉시 소멸 배열 과거의 공부하기 어려워했던 부분을 정리를 다시 한번 해보겠습니다.
int arr[3] = {10, 20, 30};이라는 배열이 있을 때, arr이라는 이름은 메모리상에서 &arr[0]과 완전히 같은 값을 가집니다.
즉 arr 이름 자체가 배열의 전체를 나타내는 주소(시작주소)가 됩니다. (시작주소의 의미- 배열의 첫번째 주소)
그렇기 때문에 이미 &기능이 있어 이름 앞에 &를 안붙혀도 됩니다.
팁1: arr[0] == *arr, arr[1] == *(arr+1) 같은 의미라서 배열의 표현인 []는 *로도 표현 가능하다!
팁2: &arr[0] == arr, &arr[1] == arr+1 같은 의미라서 주소는 배열 이름으로도 표현 가능하다!1 2 3 4 5 6
int arr[3] = {10, 20, 30}; int* p = arr; // arr이 &arr[0]으로 변환되어 전달 std::cout << *p; // 10 (A[0]) std::cout << *(p + 1); // 20 (A[1]) std::cout << *p + 1; // 11 (A[0]에 1 더함) //계층구조: 주소(ptr,int*) -> 값 (*ptr,int)
※주의) 그럼 변수 하나를 만들어서 주소값+1에 값을 만들어서 배열 선언 안하고 배열 만들수 있는거 아니야?
절대 안된다!!
int A;라고 선언하면, 정수 한 칸(4바이트)만큼만 내어줍니다.
int* p = &A;: p는 그 한 칸의 주소를 가리킵니다.
*(p + 1): A의 바로 옆 칸(4바이트 뒤)으로 찾아가서 그 내용을 열어보겠다는 뜻입니다.
문제는 그 ‘옆 칸’이 누구의 땅인지 모른다는 겁니다.
만약 int B가 있으면 대참사입니다.
그러므로 배열은 이미 여기는 우리가 사용하는 주소라고 미리 말해줬기 때문에 가능합니다!포인터 배열 vs 배열 포인터
Right-Left Rule- 제일 먼저 선언된 식별자 찾고 식별자(identifier, 변수명 또는 함수명)을 기준으로 시작합니다.
- 더이상 읽을게 없거나, 읽어 가는 방향 기준으로 닫는 괄호가 나온다면 반대쪽(left)으로 읽습니다. -> (),[]의 마지막이 닫는 괄호이다.
- 기호 해석: 아래 기호들을 만날 때마다 다음과 같이 해석합니다. (관사는 일단 생략)
기호 해석(직역) * Var is pointer to ~ (~를 가리키는 포인터) [] Var is array of ~ (~의 배열) () Var is function expecting ~ and returning ~ (~를 인자로 받고 ~를 반환하는 함수) 포인트 배열
int* ptr[3];- ptr is ~
- ptr is array of 3 ~
- ptr is array of 3 pointers to ~
- ptr is array of 3 pointers to int
ptr은 배열이다 3개의 포인터를 나타내는 int형
즉 ptr은 3개의 포인터를 담는 int형 배열이다.
1 2 3 4 5 6 7 8 9 10
int x = 10, y = 20, z = 30; int* ptr[3]; ptr[0] = &x; // A[0]에 x의 주소를 저장 ptr[1] = &y; // A[1]에 y의 주소를 저장 ptr[2] = &z; // A[2]에 z의 주소를 저장 std::cout << ptr << std::endl; // 배열 자체의 주소값(시작주소) 출력 std::cout << *ptr << std::endl; // x의 주소값 출력 - A[0] 같은 의미 std::cout << **ptr << std::endl; // x의 실제 값인 10 출력- *A[0] 같은 의미
배열 포인터
int (*ptr)[3] = A;- ptr is ~
- ptr 바로 오른쪽에 닫는 괄호가 있습니다.규칙에 따라 더 읽을 게 없거나 닫는 괄호가 나오면 왼쪽으로 방향을 바꿉니다
- ptr is pointer to ~
- 여는 괄호 (를 만났으므로 다시 오른쪽(Right)으로 읽기
- ptr is pointer to array of 3 ~
- ptr is pointer to array of 3 int
ptr은 포인터이다 3개의 배열을 나타내는 int형
즉 ptr은 3개짜리 배열을 가리키는 포인터이다
1 2 3 4 5 6 7 8 9 10 11 12 13 14
int B[2][3] = { {1,2,3} ,{4,5,6} }; int(*ptr)[3] = B; std::cout << ptr << std::endl; //1행 전체의 시작점 std::cout << *ptr << std::endl;//1행 1열의 주소 == ptr[0] std::cout << **ptr << std::endl;//1행 1열의 값 == ptr[0][0] std::cout << ptr+1 << std::endl;//2행 전체의 시작점 == &ptr[1] std::cout << *(ptr + 1) << std::endl;//2행 1열의 주소 == ptr[1] std::cout << *ptr + 1 << std::endl;//1행 2열의 주소 == &ptr[0][1] std::cout << **(ptr + 1) << std::endl;//2행 1열의 값 == ptr[1][0] std::cout << *(*ptr + 1) << std::endl;//1행 2열의 값 == ptr[0][1] //계층구조: 행 주소(ptr, int (*)[3]) -> 열 주소(*ptr, int*) -> 값(**ptr,int) //ptr[1],&ptr[1] 값은 같지만 보는 관점이 다르다 //&ptr[1]은 행의 전체 [0]~[2]까지 전체를 나타내는것(보는것) //ptr[1]은 행에 열 하나(한 칸)만 나타내는것이다.
3차원 배열도 2차원 배열이랑 개념이 비슷하다.
계층구조: 2차원 행열의 시작 주소-> 행 전체의 시작주소 -> 열 주소-> 값배열 포인터와 포인터 배열를 함수의 매개변수를 사용 하는 경우
배열 포인터: 다차원 배열에 한단계 낮은 배열의 시작 주소를 제공해야한다. 그래야 접근이 가능하기 때문에
포인터 배열: 포인터 배열의 이름은 3칸짜리 배열이 어디에 있는지 가리키는 주소를 나타낸다. 그래서 그대로 자기 자신형태를 제공해주면 됩니다.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#include <iostream> void TestArrayPointer(int (*ptr)[3]) { std::cout << "배열 포인터 출력: " << ptr[0][1] << std::endl; } void TestPointerArray(int* ptr[]) // { std::cout << "포인터 배열 출력: " << *ptr[1] << std::endl; } int main() { // 1. 배열 포인터 상황 int A[2][3] = { {1, 2, 3}, {4, 5, 6} }; TestArrayPointer(A); // 2. 포인터 배열 상황 int x = 10, y = 20; int* B[2] = { &x, &y }; TestPointerArray(B); // B(int* [2])라서 int**와 같은 말이라서 int**매개변수로 사용해도 상관없음 return 0; }