Unreal 개발 본 캠프 3일차

HappyCircle·2025년 12월 1일

Unreal 개발

목록 보기
20/163

오늘 학습 진행 내용
언리얼 강의
라이브 세션
DAY 3 블루프린트를 이용한 비주얼 스크립팅
블루 프린트가 무엇인지 배우고, 변수,이벤트 함수에 대해 배워본다.
Branch,Sequence, 함수에 대해 배워보고 이를 이용하여 간단한 과제 진행
While, For, Array, ForEach, 열거형 구조체, Switch에 대해 배워보고 간단한 과제 진행

언리얼 블루프린트
프로젝트 환경설정
프로젝트 생성 후 언리얼 에디터 최상단 Edit 클릭 -> Editor Preferencs에서 언어 설정 변경 가능

Winodws 메뉴에서 Load Layout 기능 활용해서 자기만의 레이아웃 설정 가능

블루프린트
언리얼 엔진에서 제공하는 비주얼 스크립팅 시스템
복잡한 코드 작성 없이, 노드 기반의 블럭 연결해서 프로그래밍 가능하게 하는 시스템

변수와 연산
이벤트 함수와 PrintString() 함수
이벤트 함수 : 어떤 Event 발생하면 호출되는 함수

  • BeginPlay : 게임 플레이 시작이라는 사건이 발생하면 발생하는 함수
  • Tick : 매 게임 프레임마다 호출되는 함수

블루 프린트 변수

  • 변수 : 상수를 저장할 수 있는 그릇, 언리얼에서 멤버 변수를 속성(Property)라고 많이 부름
    블루 프린트 내 생성한 변수 Get으로 불러오고 Set으로 값 설정 가능

블루 프린트 연산 노드

  • 비교 연산 노드(==, !=, >, <, <=, >=)를 사용해서 두 값 비교하여 참 또는 거짓 반환

  • 논리 연산 노드 (AND,OR,NOT,XOR)을 사용해서 여러 조건을 조합하거나 반전하여 복잡한 논리적 흐름 처리할 때 사용

흐름 제어
Brach와 Sequence 조건 만족 시 실행 혹은 순서에 따라서 실행하게 제어 가능

실습
텍스트 슈팅 게임

  • 텍스트 슈팅 게임 기획
    지금까지 배운 블루프린트의 기능을 이용하여 간단한 텍스트 슈팅 게임을 만들어보자.
    텍스트 슈팅 게임의 주요 기능은 총알을 발사하고, 재장전하는 것.
    기본적으로 해당 기능들은 아래 조건을 만족한다고 가정해보자.
    • 총알은 기본적으로 30발.
    • 마우스 좌클릭을 할 때마다 총알이 1발씩 소모됨.
    • 키보드 R을 누르면 재장전되어 총알 30발로 충전됨.

Bullets 변수로 총알 카운트 처리하고 각각 마우스 좌클릭에 Subtrect, R 버튼에 Set활용해서 발사 및 재장전 기능 구현

** 텍스트 슈팅 게임 버그 고치기** 지금까지 구현한 텍스트 슈팅 게임에는 버그들이 존재함. 그 중 가장 중요한 버그 두 가지를 고쳐보자.
  • 1) 30발 이상 격발 할 수 있는 버그**
    현재 총알의 개수가 0보다 작은 경우에는 발사할 수 없게끔 로직을 수정해보세요.
    ”Out of ammo…”라는 문구가 출력되면 더 좋습니다.

  • 2) 총알이 가득차 있는 경우에도 재장전 되는 버그**
    현재 총알의 개수가 30발 만발인 경우에는 재정전 되지 않게끔 수정해보세요.
    ”Already full…”이라는 문구가 출력되면 더 좋습니다.

    발사와 재장전 실행 되기 전에 Branch로 조건으로 각각 버그 발생 원인(현재 총알 갯수) 조건 검사하게 해서 버그 수정

텍스트 슈팅 게임 기능 추가하기
총알을 발사하고 장전만 할 수 있는 게임은 너무 지루함.
두 가지 추가 기능을 구현해보자.

  • 1) 과열 상태 추가
    여러 발을 격발할 경우, 총기가 과열될 수 있습니다.
    CurrentTemperature라는 속성을 추가하고 한 발당 1씩 증가하게끔 로직을 짜봅시다.
    그리고 CurrentHeatState라는 속성을 추가하고,
    CurrentTemperature가 0~30까지는 CurrentHeatState가 ”Normal”
    CurrentTemperature가 31~70까지는 CurrentHeatState가 ”High”
    CurrentTemperature가 71이상은 CurrentHeatState가 ”Over”로 설정되게끔 합니다.

  • 2) 쿨다운 기능
    특정 키를 누를때마다 총기의 온도가 내려가게끔 구현해봅시다.
    T키를 누르면 CurrentTemperature를 1씩 감소하게끔 로직을 작성해보세요.
    CurrentTemperature가 변하면 CurrentHeatState도 그에따라 변해야합니다.

CurrentTemperature 속성 추가 후 발사 시 Add 처리해서 올라가게 하고 TempToHeatState 함수 제작해서 온도에 따른 State 정해지게 함수로 반영 마우스 좌클릭으로 발사 시 온도에 따른 State 결정

함수
코드 재사용이 빈번한 것들 함수로 처리해서 하나의 코드로 처리

흐름 제어
While Loop, For Loop
While은 조건 기반, For은 인덱스 기반

Array와 ForEach Loop
다양한 타입의 변수를 하나의 객체로 관리 가능

열거형과 구조체 그리고 Switch

  • 열거형 : 정수형 상쉐 이름 부여해서 모아둔 것
  • 구조체 : 사전에 정의된 형태 외에도 필요에 따라 구현이 가능
  • Switch : 흐름 분기 관리로 처리해서 코드 반복 줄임

실습
텍스트 슈팅 게임 무기 추가하기
라이플, 샷건, 피스톨 무기를 추가하고 무기교체를 구현해봅시다.

  • 1) 무기 추가하기
    0번을 누르면 라이플, 1번을 누르면 샷건, 2번을 누르면 피스톨로 교체됩니다. 격발하면 현재 무기의 총알만 소모하고, 과열 상태도 현재 무기만 과열됩니다.

    무기 별 Staete, 온도, 탄 수 관리를 위해 열거형으로 추가하고 무기 별 탄환 수 다르게 하기 위해 최대 탄환 변수 추가

    기존 코드에 발사와 재장전, 온도 관련 부분에 Set Weapon Value 함수 만들어서 추가, 그리고 무기 교체 이벤트 시 해당 무기의 정보 가져오는 Get Weapon Value 함수 만들어서 추가

GetWeaponValue 함수는 무기 정보 들어있는 열거형 변수에서 가져와서 할당하는 함수

SetWeaponValue는 현재 정보값 열거형 변수에 할당하는 함수(Max Bullet은 불변값으로 계속 열거형 변수에 할당되어 있던 값 가져오는 형태)


실습 과제 추가 구현 해보기
실습 과제에 추가적으로 실제로 로직 상 발사 시 캐릭터가 애니메이션 동작 이어서 할 수 있게 2번 키 누르면 피스톨 장착하고 우클릭 시 조준, 좌클릭 시 발사 동작되게 구현 (애니메이션은 기본 템플릿 캐릭터에서 제공하는 애니메이션 활용)

캐릭터 애니메이션 블루프린트에 조준중(bIsAiming) 변수 캐릭터 블루프린트의 변수 받아와서 설정하게 구성

가져온 조준중 변수에 따라서 서있는 상태에서 변수 Boolean 값에 따라서 조준 액션 취하게 Staete Machine 구성

캐릭터 스켈레탈 메시의 HanGrip_L에 총 자연스럽게 할당되게 배치 및 조정 후 2번 키 누를 시 총 엑터가 캐릭터 HandGrip_L에 소환되게 Attached되게 구성, 총 안든 상태에서 발사 모션 취하는 것 방지하기 위해 총은 CurrentWeapon에 할당되게 추가

총구에 발사 이펙트 보이게 하기 위해 총기 Static Mesh에 소켓 추가 후 발사 동작 시 발사 모션 몽타주 실행하고 해당 소켓 자리에 이펙트 효과 생성되게 블루프린트 구성

구현 결과


C++ 프로그래머스 연습
수열과 구간 쿼리 4
문제 설명
정수 배열 arr와 2차원 정수 배열 queries이 주어집니다. queries의 원소는 각각 하나의 query를 나타내며, [s, e, k] 꼴입니다.

각 query마다 순서대로 s ≤ i ≤ e인 모든 i에 대해 i가 k의 배수이면 arr[i]에 1을 더합니다.

위 규칙에 따라 queries를 처리한 이후의 arr를 return 하는 solution 함수를 완성해 주세요.

제한사항
1 ≤ arr의 길이 ≤ 1,000
0 ≤ arr의 원소 ≤ 1,000,000
1 ≤ queries의 길이 ≤ 1,000
0 ≤ s ≤ e < arr의 길이
0 ≤ k ≤ 5

통과 답안

#include <string>
#include <vector>
using namespace std;

vector<int> solution(vector<int> arr, vector<vector<int>> queries) {
    vector<int> answer;
    for(int i=0; i<queries.size(); i++){
        int s  = queries[i][0];
        int e = queries[i][1];
        int k = queries[i][2];
            for(s; s<=e; s++){
                 if(s%k==0){
                arr[s] +=1;
            }
        }   
    }
    answer = arr;
    return answer;
}

다른 사람 풀이

#include <string>
#include <vector>

using namespace std;

vector<int> solution(vector<int> arr, vector<vector<int>> queries) {
    vector<int> answer;
    for(auto q:queries){
        for(int i = q[0]; i<=q[1]; i++){
            if(i%q[2] == 0){
                arr[i]++;
            }
        }
    }
    return arr;
}

배열 만들기 2
문제 설명
정수 l과 r이 주어졌을 때, l 이상 r이하의 정수 중에서 숫자 "0"과 "5"로만 이루어진 모든 정수를 오름차순으로 저장한 배열을 return 하는 solution 함수를 완성해 주세요.

만약 그러한 정수가 없다면, -1이 담긴 배열을 return 합니다.

제한사항
1 ≤ l ≤ r ≤ 1,000,000

통과 답안(모르는 부분 존재해서 검색 이용)

🔎 find 계열 함수 요약

함수설명찾는 기준반환값찾지 못했을 때
find부분 문자열을 앞에서부터 검색문자열 or 문자첫 번째 발견 위치npos
rfind부분 문자열을 뒤에서부터 검색문자열 or 문자마지막 발견 위치npos
find_first_of문자 집합 중 하나라도 처음 등장하는 위치문자들 집합위치npos
find_last_of문자 집합 중 하나를 뒤에서부터 찾기문자들 집합위치npos
find_first_not_of특정 문자 집합에 없는 문자 첫 등장 위치제외할 문자들위치npos
find_last_not_of특정 문자 집합에 없는 문자를 뒤에서부터 찾기제외할 문자들위치npos
#include <string>
#include <vector>
#include <string>
using namespace std;

vector<int> solution(int l, int r) {
    vector<int> answer;
    int min_count = 0;
    int max_count = 0;
    min_count = l/5;
    max_count = r/5;
    if(l%5!=0){
        min_count+=1;
    }
    for (int i=min_count; i<=max_count; i++){
        if(to_string(i*5).find_first_not_of("05") == string::npos){
           answer.push_back(i*5); 
        }
    };
    if(answer.size()==0){
        answer.push_back(-1);
    }
    return answer;
}

다른 사람 풀이

#include <string>
#include <vector>
#include <queue>

using namespace std;

vector<int> solution(int l, int r) {
    vector<int> answer;  // 조건을 만족하는 숫자들을 담을 벡터
    queue<int> q;        // 숫자를 생성하기 위해 사용할 큐 (BFS 용도)

    // 시작 숫자: 5만으로 이루어진 가장 작은 수
    q.push(5);

    // 큐가 빌 때까지 반복 (BFS 방식으로 숫자 생성)
    while (!q.empty()) {
        int n = q.front(); // 현재 숫자
        q.pop();

        // 현재 숫자가 r보다 크면, 이 숫자에서 더 큰 숫자를 만들어도
        // 모두 r을 넘게 되므로, 더 이상 확장하지 않고 건너뜀
        if (n > r) continue;

        // 구간 [l, r] 안에 들어가면 정답 벡터에 추가
        if (n >= l) {
            answer.push_back(n);
        }

        // 현재 숫자 n 뒤에 0과 5를 붙여서
        // "0과 5로만 이루어진 숫자"를 계속 만들어나감
        // 예: n = 5 → 50, 55
        q.push(n * 10);      // 끝에 0을 붙인 숫자 (예: 5 → 50)
        q.push(n * 10 + 5);  // 끝에 5를 붙인 숫자 (예: 5 → 55)
    }

    // [l, r] 구간 안에 조건을 만족하는 숫자가 하나도 없으면 -1 추가
    if (answer.empty()) {
        answer.push_back(-1);
    }

    return answer;
}

카운트 업
문제 설명
정수 start_num와 end_num가 주어질 때, start_num부터 end_num까지의 숫자를 차례로 담은 리스트를 return하도록 solution 함수를 완성해주세요.

제한사항
0 ≤ start_num ≤ end_num ≤ 50

통과 답안

#include <string>
#include <vector>

using namespace std;

vector<int> solution(int start_num, int end_num) {
    vector<int> answer;
    for (start_num; start_num<=end_num; start_num++){
        answer.push_back(start_num);
    }
    return answer;
}

콜라츠 수열 만들기
문제 설명
모든 자연수 x에 대해서 현재 값이 x이면 x가 짝수일 때는 2로 나누고, x가 홀수일 때는 3 * x + 1로 바꾸는 계산을 계속해서 반복하면 언젠가는 반드시 x가 1이 되는지 묻는 문제를 콜라츠 문제라고 부릅니다.

그리고 위 과정에서 거쳐간 모든 수를 기록한 수열을 콜라츠 수열이라고 부릅니다.

계산 결과 1,000 보다 작거나 같은 수에 대해서는 전부 언젠가 1에 도달한다는 것이 알려져 있습니다.

임의의 1,000 보다 작거나 같은 양의 정수 n이 주어질 때 초기값이 n인 콜라츠 수열을 return 하는 solution 함수를 완성해 주세요.

제한사항
1 ≤ n ≤ 1,000

통과 답안

#include <string>
#include <vector>

using namespace std;

vector<int> solution(int n) {
    vector<int> answer;
    while(n!=1){
        answer.push_back(n);
        if(n%2==0){
            n/=2;
        }
        else if(n%2==1){
            n = 3*n + 1;
        }

    }
    answer.push_back(1);
    return answer;
}

다른 사람 풀이

#include <vector>
using namespace std;

vector<int> solution(int n){
    vector<int> a;          // 콜라츠(?) 수열을 저장할 벡터

    for(;;) {               // 조건 없는 무한루프. 내부에서 return으로 빠져나옴.
        a.push_back(n);     // 현재 n 값을 수열에 추가

        // n이 1이면 수열이 끝났다고 보고 지금까지의 벡터를 그대로 반환
        if (n == 1) return a;

        // n이 홀수인지 짝수인지에 따라 다음 n을 계산
        // (n & 1) : n의 최하위 비트가 1이면 홀수, 0이면 짝수
        //  - 홀수면 true, 짝수면 false
        //
        // 홀수일 때  : n = 3 * n + 1
        //    n + (n << 1) + 1
        //      = n + (n * 2) + 1
        //      = 3n + 1
        //
        // 짝수일 때  : n = n / 2  (오른쪽 시프트 1비트 == 2로 나누기)
        n = (n & 1) ? (n + (n << 1) + 1) : (n >> 1);
    }
}

배열 만들기4
문제 설명
정수 배열 arr가 주어집니다. arr를 이용해 새로운 배열 stk를 만드려고 합니다.

변수 i를 만들어 초기값을 0으로 설정한 후 i가 arr의 길이보다 작으면 다음 작업을 반복합니다.

만약 stk가 빈 배열이라면 arr[i]를 stk에 추가하고 i에 1을 더합니다.
stk에 원소가 있고, stk의 마지막 원소가 arr[i]보다 작으면 arr[i]를 stk의 뒤에 추가하고 i에 1을 더합니다.
stk에 원소가 있는데 stk의 마지막 원소가 arr[i]보다 크거나 같으면 stk의 마지막 원소를 stk에서 제거합니다.
위 작업을 마친 후 만들어진 stk를 return 하는 solution 함수를 완성해 주세요.

제한사항
1 ≤ arr의 길이 ≤ 100,000
1 ≤ arr의 원소 ≤ 100,000

통과 답안

#include <string>
#include <vector>
using namespace std;

vector<int> solution(vector<int> arr) {
    vector<int> stk;
    int i=0;
    while(i<arr.size()){
        if(stk.size()!=0 && stk.back()<arr[i]){
            stk.push_back(arr[i]);
            i+=1;
        }
        else if(stk.size()!=0 && stk.back()>=arr[i]){
            stk.pop_back();
        }
        else{
            stk.push_back(arr[i]);
            i+=1; 
        }

    }
    return stk;
}

다른 사람 풀이

#include <string>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> solution(vector<int> arr) {
    vector<int> stk;   // 조건을 만족하는 원소들을 담아갈 "스택 역할"의 벡터
    int i = 0;         // arr를 순회하기 위한 인덱스

    // i가 arr의 크기보다 작을 동안 계속 반복
    while (i < arr.size()) {
        // 1️⃣ stk가 비어있으면 무조건 현재 원소를 넣는다.
        if (stk.empty()) {
            stk.push_back(arr[i]);  // 현재 arr[i]를 스택에 넣고
            i++;                    // 다음 원소로 이동
        }
        // 2️⃣ stk가 비어있지 않고,
        //     스택의 맨 뒤 값(stk.back)이 현재 arr[i]보다 작으면
        //     → "증가하는 흐름 유지" 가능하므로 현재 값을 추가.
        else if (stk.back() < arr[i]) {
            stk.push_back(arr[i]);  // 현재 값을 스택에 추가
            i++;                    // 다음 원소로 이동
        }
        // 3️⃣ 그 외의 경우 (stk.back() >= arr[i]):
        //     → 스택의 마지막 값이 현재 값보다 크거나 같으므로
        //       "마지막 값을 제거"해서 더 나은(작은 값으로 시작되는) 증가 수열을 만들려는 의도
        else {
            // stk의 마지막 원소를 제거 (pop_back과 같은 효과)
            stk.erase(stk.end() - 1);
        }
    }
    return stk;  // 최종적으로 조건을 만족하며 남은 값들 반환
}
profile
개발합시다!

0개의 댓글