브루트포스 기법
1. 부르트포스브루트포스(Brute Force)란?가능한 모든 경우의 수를 전부 시도해보는 "무식한" 문제 해결 방법.최적화된 알고리즘을 떠올리기 어려울 때나 검증 과정에서 자주 활용됩니다.브루트포스의 시간 복잡도부분집합 탐색: 2^n순열 탐색: n!중첩 반복문을 통한 조합 탐색n이 작다면 충분히 시도할 만하지만, 지수적 증가로 인해 크기에 주의 필요.예: n=10  → 부분집합: 2^10=1024, 순열: 10! =3,628,800 2. 비트마스킹비트마스킹(Bitmasking)이란?이진수(0과 1)로 이루어진 비트를 활용하여 데이터를 표현하고 조작하는 기법보통 정수형 변수의 각 비트를 ON(1) 또는 OFF(0)로 설정하여 특정 상태를 관리할 때 사용.💡 왜 사용할까?배열을 사용하지 않고도 빠르게 여..
2025.03.11
C++
no image
네트워킹 및 멀티 플레이어 개요
1. 네트워킹 개요1.리플리케이션(Replication) 개념 UE에서 클라이언트와 서버 간 데이터 및 절차 호출을 동기화하는 프로세스 ⮕ 같은 게임 상태 유지멀티플레이 프로젝트에서 다양한 상황을 처리하기 위한 하이 레벨 추상성과 로우 레벨 커스터마이징 제공하이 레벨 추상성(High-Level Abstraction)쉽게 사용할 수 있도록 미리 만들어진 기능복잡한 네트워크 처리 없이 기본적인 멀티플레이 기능을 구현 가능예: bReplicates(액터의 리플리케이션 활성화), ReplicatedUsing(값이 변경될 때 호출할 함수 지정) 같은 기본 옵션로우 레벨 커스터마이징(Low-Level Customization)개발자가 직접 네트워크 통신 방식을 세밀하게 제어할 수 있는 기능기본 제공 기능으로 해결되..
2025.03.10
no image
언리얼 엔진 5 기반 슈터 게임 프로젝트 KPT 회고
개인 회고1. Keep분업분업이 확실했습니다. 캐릭터, 게임 인스턴스 및 맵, 아이템, Enemy AI, 애니메이션 각각 역할 분담이 처음부터 잘 되었고, 서로 부족한 부분은 보완해주었습니다.  진행 과정 공유                                                                                                                                                                매일 서로 맡은 역할의 진행 과정을 공유하는 시간을 가졌기 때문에 전체 진행도 그리고 게임 개발 흐름을 파악하는 과정이 자연스러웠습니다.2. Problem개발 목표 설정제한된 시간내에 목적 달성 가능한 목표를 세우지 ..
2025.03.07
작성중
2025.02.26
no image
머티리얼 조작
목차1. 개요2. Material Graph 작업3. Blueprint Event Graph 작업4. 프로젝트 기능 시연1. 개요 오늘도 다름없이 몬스터를 구현에 몰두했습니다. 몬스터 중 은신 스킬을 사용하는 친구를 만들어보자는 계획이 있었는데 잘 다뤄본적이 없는 머티리얼을 조작해야되기 때문에 조금 미루고 있었습니다만.. 오늘 마주하게 됐습니다. 먼저 C++로 작성한 은신 스킬을 담당 컴포넌트를 보겠습니다.StealthSkillComponent.h#pragma once#include "CoreMinimal.h"#include "Monster/Component/BaseSkillComponent.h"#include "StealthModeSkillComponent.generated.h"UCLASS(Bluepr..
2025.02.25
no image
Enemy(Monster) 클래스
목차1.개요2. Enemy(Monster) 클래스 구조3. Monster 기능 컴포넌트4. Monster 클래스별 컴포넌트 구성5. 몬스터 컴포넌트 활용1. 개요프로젝트에서 적(몬스터) 구현 역할을 맡았고 특히 AI 구현은 복잡합니다. AI Controller, Behavior Tree, 그리고 Black Board에서는 각 몬스터의 기능을 활용하기 때문에 몬스터 클래스 구조부터 정리하고자 합니다.  2. Enemy(Monster) 클래스 구조몬스터 타입(일반, 보스) 별 각 기능을 구상하며 위와 같이 클래스를 설계하였습니다.3. 몬스터 컴포넌트공격 관련MonsterAttackComponent (일반 공격)상태 관련MonsterStatComponent (스탯 관리)HitReactionComponent (..
2025.02.24
STL 기본 구조
STL이란?STL(Standard Template Library)은 C++의 내장 템플릿 라이브러리로, 컨테이너, 반복자(Iterator), 알고리즘 세 가지 요소로 구성됨.컨테이너(Container): 데이터를 저장·관리하는 자료구조반복자(Iterator): 컨테이너 내 데이터를 순회하는 포인터 역할알고리즘(Algorithm): 정렬, 탐색, 삽입, 삭제 등 다양한 기능 제공STL을 잘 활용하면 코딩 테스트에서 시간을 크게 절약할 수 있음. 직접 자료구조를 구현하는 것보다 훨씬 효율적.STL의 3가지 요소이 세 가지 요소는 서로 연동되어 강력한 기능을 제공함.컨테이너 → 데이터를 담는 창고반복자 → 창고 정리하는 도우미알고리즘 → 문제 해결을 돕는 용병1. 컨테이너 (Container)데이터를 저장하는..
2025.02.18
C++
no image
언리얼 엔진 AI 행동 제어 시스템
목차1. Behavior Tree(비헤이비어 트리)2. Black Board(블랙보드)3. AI Controller4. NavMesh1. Behavior Tree (비헤이비어 트리)비헤이비어 트리는 AI의 행동을 결정하는 계층적 구조를 가진 트리. 각 노드(Node)에는 특정 역할이 있으며, AI는 루트(Root) 노드에서 시작하여 조건에 따라 적절한 행동을 수행.1-1. 비헤이비어 트리의 주요 노드 유형Root 노드: 트리의 시작점Composite 노드 (합성 노드): 여러 개의 하위 노드를 가질 수 있음Selector (선택자): 왼쪽부터 실행하며, 성공하는 노드를 찾으면 중단Sequence (시퀀스): 왼쪽부터 순서대로 실행하며, 하나라도 실패하면 중단Decorator 노드 (데코레이터 노드): 특..
2025.02.17

브루트포스 기법

언리얼 거토
|2025. 3. 11. 15:41

1. 부르트포스

브루트포스(Brute Force)란?

  • 가능한 모든 경우의 수를 전부 시도해보는 "무식한" 문제 해결 방법.
  • 최적화된 알고리즘을 떠올리기 어려울 때나 검증 과정에서 자주 활용됩니다.

브루트포스의 시간 복잡도

  • 부분집합 탐색: 2^n
  • 순열 탐색: n!
  • 중첩 반복문을 통한 조합 탐색

n이 작다면 충분히 시도할 만하지만, 지수적 증가로 인해 크기에 주의 필요.
예: n=10  → 부분집합: 2^10=1024, 순열: 10! =3,628,800

 

2. 비트마스킹

비트마스킹(Bitmasking)이란?

  • 이진수(0과 1)로 이루어진 비트를 활용하여 데이터를 표현하고 조작하는 기법
  • 보통 정수형 변수의 각 비트를 ON(1) 또는 OFF(0)로 설정하여 특정 상태를 관리할 때 사용.

💡 왜 사용할까?

  • 배열을 사용하지 않고도 빠르게 여러 상태를 저장할 수 있음
  • 비트 연산을 활용하면 탐색, 계산 속도가 빠름
  • 메모리를 절약할 수 있음

비트마스킹의 핵심 개념

  1. 각 비트는 특정 의미를 가질 수 있음
    예를 들어, 101이라는 이진수를 보자.
    • 첫 번째(맨 오른쪽) 비트: 1 → 켜짐 (ON)
    • 두 번째 비트: 0 → 꺼짐 (OFF)
    • 세 번째 비트: 1 → 켜짐 (ON)
  2. 비트 연산을 이용한 조작 방법
    연산 설명 예시
    AND & 특정 비트가 켜져 있는지 확인 101 & 001 = 001 (세 번째 비트가 켜져 있음)
    OR | 특정 비트를 켜기 100 | 010 = 110
    XOR ^ 특정 비트 토글(0 → 1, 1 → 0) 110 ^ 010 = 100
    SHIFT <<, >> 비트 위치 이동 001 << 2 = 100

 

3. 브루트포스 구현 방법

3-1. 중첩 반복문

  • 직관적이지만 범위가 크면 비효율적
  • 예제: 1~3까지의 숫자 3개를 중복 선택하여 나열
for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 3; j++) {
        for (int k = 1; k <= 3; k++) {
            cout << i << " " << j << " " << k << "\n";
        }
    }
}

 

3-2. 비트마스킹을 활용한 부분집합 탐색

  • 집합 {1,2,3}의 경우 총 2^3=개의 부분집합 존재
  • 이진수 표현을 활용하여 부분집합을 탐색 가능
0 -> 000 -> 공집합
1 -> 001 -> {3}
2 -> 010 -> {2}
3 -> 011 -> {2,3}
4 -> 100 -> {1}
5 -> 101 -> {1,3}
6 -> 110 -> {1,2}
7 -> 111 -> {1,2,3}

 

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

int main() {
    vector<int> arr = {1, 2, 3};
    int n = arr.size();

 	// 0부터 2^n - 1까지 부분집합의 모든 경우 탐색
    for (int i = 0; i < (1 << n); i++) {
        cout << "{ ";
        for (int j = 0; j < n; j++) {
            if (i & (1 << j)) { 
            // i번째 원소가 포함되었는지 확인
            // bit는 정수지만, 2진수로 보면 비트의 집합
            // (1 << j)의 역할: 특정 비트만 체크
            // i & (1 << j) != 0 이면 True 이기 때문에 해당 자리 원소 출력
                cout << arr[j] << " "; 
            }
        }
        cout << "}\n";
    }
}

 

정수 n(1 ≤ n ≤ 100)이 주어질 때, 다음 식을 만족하는 (a, b, c)의 개수를 구하는 문제를 불필요한 중복 제거를 하여 풀어보세요. (제출 + 발표)

a + b^2 + c^3 = n
#include <iostream>
using namespace std;

int main() {
    int n = 10000;  // 입력값
    int count = 0;

    for (int b = 1; b * b <= n; b++) {  // b^2가 n을 초과하지 않는 범위까지만 탐색
        for (int c = 1; b * b + c * c * c <= n; c++) {  // b^2 + c^3이 n을 초과하지 않는 범위까지만 탐색
            int a = n - (b * b + c * c * c);
            if (a >= 1 && a <= 100) {  // a가 자연수(1~100) 범위 내에 있어야 유효한 해
                count++;
            }
        }
    }

    cout << count;
}

'C++' 카테고리의 다른 글

클린코딩  (0) 2025.03.27
STL 기본 구조  (0) 2025.02.18

1. 네트워킹 개요

1.리플리케이션(Replication) 개념

 

  • UE에서 클라이언트와 서버 간 데이터 및 절차 호출을 동기화하는 프로세스 ⮕ 같은 게임 상태 유지
  • 멀티플레이 프로젝트에서 다양한 상황을 처리하기 위한 하이 레벨 추상성과 로우 레벨 커스터마이징 제공
    • 하이 레벨 추상성(High-Level Abstraction)
      1. 쉽게 사용할 수 있도록 미리 만들어진 기능
      2. 복잡한 네트워크 처리 없이 기본적인 멀티플레이 기능을 구현 가능
      3. 예: bReplicates(액터의 리플리케이션 활성화), ReplicatedUsing(값이 변경될 때 호출할 함수 지정) 같은 기본 옵션
    • 로우 레벨 커스터마이징(Low-Level Customization)
      1. 개발자가 직접 네트워크 통신 방식을 세밀하게 제어할 수 있는 기능
      2. 기본 제공 기능으로 해결되지 않는 고급 네트워크 처리 가능
      3. 예: RPC(Remote Procedure Call)를 사용한 서버-클라이언트 간 직접적인 데이터 전송, 네트워크 대역폭 최적화 등

 

2. 멀티플레이어 vs. 싱글 플레이어

  • 싱글 플레이어: 모든 정보가 하나의 컴퓨터에 저장됨
  • 멀티플레이어: 게임 스테이트 정보가 네트워크를 통해 여러 컴퓨터 간에 전달됨 → 더 복잡한 프로그래밍 요구됨
  • 플레이어 간 정보 공유는 추가적인 단계와 세심한 주의 필요

 

3. 멀티플레이 기능을 고려한 개발

  • 멀티플레이 가능성이 있다면 처음부터 이를 염두에 두고 개발
  • 초반부터 멀티플레이 지원을 고려하면 개발 과정에서 큰 추가 부담 없이 진행 가능
  • 사전 고려 없이 개발하면 네트워크 환경을 반영한 코드 리팩토링이 필요하며, 기술적 한계로 인해 기존 디자인을 변경해야 할 수도 있음

 

2. 클라이언트-서버 모델

  • 하나의 컴퓨터가 서버가 되어 멀티플레이 세션을 호스팅
  • 서버는 클라이언트와 게임 스테이트 정보를 공유하고 통신 지원

 

 

  • 서버의 역할
    • 서버는 하나의 진정한 오소리티(authority) 있는 게임 스테이트를 보유
    • 멀티플레이어 게임의 실제 실행이 이루어지는 곳
  • 클라이언트의 역할
    • 서버가 소유한 폰(Pawns)을 원격 제어하며, 게임 내 액션을 수행하도록 프로시저 호출 전송
    • 서버는 클라이언트에 직접 영상을 스트리밍하지 않음
  • 리플리케이션 과정
    • 서버는 게임 스테이트 정보를 각 클라이언트에 리플리케이트
    • 존재해야 하는 액터, 액터의 행동 방식, 보유해야 할 변수 값을 클라이언트에 전달
    • 클라이언트는 이를 바탕으로 서버의 게임 상태를 최대한 유사하게 시뮬레이션

 

3. 클라이언트-서버 게임플레이 예시

- 플레이어 1(Player 1) 과 플레이어 2(Player 2)가 서로에게 발사체를 발사하는 프로세스 -

 

  • 무기 발사 프로세스
    • 플레이어 1이 입력하여 무기 발사
    • 로컬 폰 → 서버 폰에 무기 발사 명령 전달
    • 서버에서 발사체 스폰 및 각 클라이언트에 사본 생성 지시
    • 서버가 무기 발사 사운드 및 비주얼 이펙트 재생 지시
  • 발사체 이동 및 충돌
    • 서버에서 발사체 이동 → 각 클라이언트에 이동 정보 리플리케이트
    • 서버에서 발사체가 플레이어 2와 충돌
    • 서버가 발사체 소멸 및 충돌 이펙트 재생 지시
    • 서버에서 플레이어 2의 폰이 대미지 받고, 클라이언트에 반응 이펙트 재생 지시
  • 네트워크 환경에서의 처리
    • 서로 다른 컴퓨터(서버 + 클라이언트)의 월드에서 동일한 이벤트가 발생하는 것처럼 보이게 처리
    • 서버가 클라이언트에 선별적으로 정보 전송하여 시각적 표현 유지
  • 리플리케이션 고려 사항
    • 필수 게임플레이 요소(콜리전, 무브먼트, 대미지)
    • 장식성 이펙트(비주얼, 사운드)
    • 개인 정보(HUD 업데이트)
    • 리플리케이트할 정보를 명확히 지정해야 하며, 네트워크 대역폭 최소화가 중요

 

4. 언리얼 엔진 네트워크 모드(Network Modes)

네트워크 모드는 게임 세션에서 각 기기의 역할을 정의.

네트워크 모드 ENetMode 설명
Standalone NM_Standalone 네트워크 기능 없이 로컬 플레이어만 존재하는 모드. 싱글 플레이 및 로컬 멀티플레이에 사용됨. 서버 기능을 포함하지만 클라이언트 연결은 받지 않음.
Dedicated
Server
NM_DedicatedServer 로컬 플레이어 없이 원격 클라이언트만 연결할 수 있는 서버. 그래픽, 사운드, 입력을 처리하지 않아 성능이 뛰어남. 대규모 멀티플레이어 게임에서 사용됨.
Listen
Server
NM_ListenServer 로컬 플레이어가 있는 서버로, 네트워크의 다른 플레이어가 참여 가능. 설정이 간단하지만 호스트 플레이어가 유리할 수 있음.
Client NM_Client 원격 서버에 연결된 클라이언트. 서버의 명령을 따르며, 자체적인 서버 기능을 수행하지 않음.

네트워크 모드를 확인하려면 GetNetMode() 함수를 사용.

5. 서버 유형(Server Types)

5.1 리슨 서버(Listen Server)

  • 사용자가 직접 서버를 호스팅할 수 있어 설정이 간단함.
  • UI를 통해 서버를 생성하거나 기존 서버를 검색할 수 있음.
  • 단점: 호스트가 서버 역할을 하면서 직접 플레이하기 때문에 다른 클라이언트보다 유리할 수 있으며, 성능 부담이 커질 수 있음.

5.2 전용 서버(Dedicated Server)

  • 서버 전용 기기에서 실행되며, 모든 플레이어가 네트워크를 통해 연결함.
  • 공정한 환경을 보장하고 성능이 뛰어나지만 설정이 복잡하고 비용이 발생할 수 있음.
  • 대규모 멀티플레이어 게임(MMO, MOBA, FPS 등)에 적합함.

'TIL > C++와 UE' 카테고리의 다른 글

Object Pooling  (0) 2025.03.28
언리얼 엔진 레플리케이션(Replication)  (0) 2025.03.11
작성중  (0) 2025.02.26
머티리얼 조작  (0) 2025.02.25
Enemy(Monster) 클래스  (0) 2025.02.24

 

개인 회고

1. Keep

  • 분업
    분업이 확실했습니다. 캐릭터, 게임 인스턴스 및 맵, 아이템, Enemy AI, 애니메이션 각각 역할 분담이 처음부터 잘 되었고, 서로 부족한 부분은 보완해주었습니다. 
  • 진행 과정 공유                                                                                                                                                                매일 서로 맡은 역할의 진행 과정을 공유하는 시간을 가졌기 때문에 전체 진행도 그리고 게임 개발 흐름을 파악하는 과정이 자연스러웠습니다.

2. Problem

  • 개발 목표 설정
    제한된 시간내에 목적 달성 가능한 목표를 세우지 못했습니다. 아직 조금 미완성된 부분들이 있고 발표 준비전 시간적 여유를 갖지 못하였습니다. 그리고 비록 확장성을 고려해야되긴 하지만 개발 스케일에 맞는 구조를 구성했는지가 의문입니다.

    2. Git
    Git에 대한 지식이 스스로 얕아서 적극적인 Commit 또는 Pull을 못하였습니다.

 

3. Try

  • 포트폴리오 자료(발표 자료) 준비
    틈틈이 개발 진행에 관련된 수기를 작성하고 시각화 가능한 요소로 표현해보자.

  • Git
    Crash를 두려워 하지말고 직접 해결해보는 과정도 많이 경험해보자

  • 목표 설정
    모든일이 예상대로 흘러가진 않는다. 달성가능한 목표를 세워보자. 목표 달성이 어려울 시 적절한 목표로 전환하자. 적절한 목표를 설정하고 이를 성취하면 스스로에 대한 동기부여도 얻을 수 있다.

 

팀원 전체 회고

 

회고 총 정리

Keep - 현재 만족하고 있는 부분

  • Git 정리, 코드 컨밴션등 처음에 많은 부분을 잘 맞춰두고 가서 협업하는데 불편함이 없었습니다.
  • 진행과정이 잘 공유되고, 서로서로 도움을 주고 받고 하면서 많이 도움이 되었습니다.
  • 기능 분리가 잘 되어 있어서 협업하기 편리하였습니다.

Problem - 불편하게 느끼는 부분

  • 기능 개발중에 신규 개발요청이 와서 조금 힘들었습니다.
  • 개인적으로 아쉬운 부분은 좀더 깊게 고민하고 개발을 못하고 급하게 처리한 부분도 있어서 아쉬웠습니다.
  • Git에 대한 지식이 스스로 얕아서 적극적인 Commit 또는 Pull을 못하였습니다.
  • 제한된 시간내에 목적 달성 가능한 목표를 세우지 못했습니다. 아직 조금 미완성된 부분들이 있고 발표 준비전 시간적 여유를 갖지 못하였습니다. 그리고 비록 확장성을 고려해야되긴 하지만 개발 스케일에 맞는 구조를 구성했는지가 의문입니다.
  • 초기 기획단계에서 변경한 부분에있어서 전 팀원들이 숙지가 미숙했던거 같습니다. 또한 이로인해서 방향성이 계속 틀어져서 게임의 재미요소가 사라진게 아쉽습니다.

Try - Problem에 대한 해결책, 당장 실행 가능한 것

  • 깊은 고민의 빠른 아웃풋은 지식의 양이다. 공부할것!
  • 기획과정에서의 변화는 모두와 상의 할 것 (리마인딩 필요)
  • 시간 분배를 잘하고 약속한 시간을 지켜서 뒤의 작업들이 딜레이 되지 않도록할것!
  • Crash를 두려워 하지말고 직접 해결해보는 과정도 많이 경험해보자
  • 목표를 낮게 잡는거 보다 일단 목표는 크게 잡되 중간회의를 거쳐서 일정에 맞게 과감하게 수정을 하는게 좋아보입니다.

작성중

언리얼 거토
|2025. 2. 26. 21:13

'TIL > C++와 UE' 카테고리의 다른 글

언리얼 엔진 레플리케이션(Replication)  (0) 2025.03.11
네트워킹 및 멀티 플레이어 개요  (0) 2025.03.10
머티리얼 조작  (0) 2025.02.25
Enemy(Monster) 클래스  (0) 2025.02.24
언리얼 엔진 AI 행동 제어 시스템  (0) 2025.02.17

머티리얼 조작

언리얼 거토
|2025. 2. 25. 22:57

목차

1. 개요

2. Material Graph 작업

3. Blueprint Event Graph 작업

4. 프로젝트 기능 시연


1. 개요 

오늘도 다름없이 몬스터를 구현에 몰두했습니다. 몬스터 중 은신 스킬을 사용하는 친구를 만들어보자는 계획이 있었는데 잘 다뤄본적이 없는 머티리얼을 조작해야되기 때문에 조금 미루고 있었습니다만.. 오늘 마주하게 됐습니다. 먼저 C++로 작성한 은신 스킬을 담당 컴포넌트를 보겠습니다.

StealthSkillComponent.h
#pragma once

#include "CoreMinimal.h"
#include "Monster/Component/BaseSkillComponent.h"
#include "StealthModeSkillComponent.generated.h"

UCLASS(Blueprintable)
class PEPCCINE_API UStealthModeSkillComponent : public UBaseSkillComponent
{
	GENERATED_BODY()

public:
	UStealthModeSkillComponent();
	virtual void ActivateSkill() override;

protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skill|Stealth")
	float StealthTime = 8.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skill|Stealth")
	float SpeedMultiplier = 1.2f;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Skill|Stealth")
	bool bIsStealthMode = false;

	// 블루프린트에서 머티리얼 Dissolve 및 복원 처리
	UFUNCTION(BlueprintImplementableEvent, Category = "Skill|Stealth")
	void OnStealthActivated();

	UFUNCTION(BlueprintImplementableEvent, Category = "Skill|Stealth")
	void OnStealthDeactivated();

	FTimerHandle StealthTimerHandle;

	virtual void BeginPlay() override;
	void BoostSpeed(float Amount);
	void ResetSpeed();
};
#include "Monster/Component/StealthModeSkillComponent.h"
#include "Monster/Component/MonsterStatComponent.h"
#include "GameFramework/Actor.h"

UStealthModeSkillComponent::UStealthModeSkillComponent()
{
    PrimaryComponentTick.bCanEverTick = false;
}

void UStealthModeSkillComponent::BeginPlay()
{
    Super::BeginPlay();
}

void UStealthModeSkillComponent::ActivateSkill()
{
    if (bIsStealthMode || !IsCooldownOver())
    {
        UE_LOG(LogTemp, Warning, TEXT("Cooldown not over yet or already in Stealth Mode"));
        return;
    }

    bIsStealthMode = true;
    StartCooldown();
    PlaySkillMontage();
    BoostSpeed(SpeedMultiplier);

    // 블루프린트에서 머티리얼 Dissolve 적용
    OnStealthActivated();

    // StealthTime 후 속도 복구 타이머 설정
    GetWorld()->GetTimerManager().SetTimer(
        StealthTimerHandle,
        this,
        &UStealthModeSkillComponent::ResetSpeed,
        StealthTime,
        false
    );

    UE_LOG(LogTemp, Warning, TEXT("Stealth mode activated. Speed boosted by %.2f for %.2f seconds."), SpeedMultiplier, StealthTime);
}

void UStealthModeSkillComponent::BoostSpeed(float Amount)
{
    if (AActor* Owner = GetOwner())
    {
        if (UMonsterStatComponent* StatComp = Owner->FindComponentByClass<UMonsterStatComponent>())
        {
            StatComp->IncreaseSPD(Amount);

        }
    }
}

void UStealthModeSkillComponent::ResetSpeed()
{
    if (AActor* Owner = GetOwner())
    {
        if (UMonsterStatComponent* StatComp = Owner->FindComponentByClass<UMonsterStatComponent>())
        {
            StatComp->IncreaseSPD(1.0f / SpeedMultiplier);
            UE_LOG(LogTemp, Warning, TEXT("Stealth Mode End"));
        }
    }

    // 블루프린트에서 머티리얼 복원 처리
    OnStealthDeactivated();

    bIsStealthMode = false;
}

 

은신 모드 중 몬스터의 속도를 조금 빨라지게 해주자 하여 Speed 조작 관련 코드가 있습니다. 무엇보다 눈여겨봐야하는 것은 UFUNCTION 매크로 중 "Blueprintimplementable"로 선언된 OnStealthActivated()와 OnStealthDeactivated()입니다. 잠시 관련 지식을 짚고 넘어가겠습니다.

 

BlueprintImplementable 이란?

  • C++에서 정의한 함수나 메서드를 블루프린트에서 구현할 수 있도록 하는 UFUNCTION 매크로

다른 비슷한 UFUNCTION 매크로와의 차이

  • BlueprintCallable: C++에서 함수 정의. 블루프린트에서 호출 가능.
  • BlueprintPure: 상태를 변경하지 않고 계산만 하는 순수 함수. 입력값에만 의존해 값을 반환
  • BlueprintImplementable: C++에서 함수 시그니처만 정의, 로직은 블루프린트에서 구현

 

다시 한번 말하자면 은신 모드를 활성화하고 비활성화하는 동작은 결국 머티리얼 조작을 필요로 합니다. 하지만 머티리얼 조작은 Blueprint로 하는 것이 효과적입니다. 그래서 해당 동작 역할을 담당하는 두 함수의 정의를 Blueprint에서 해주겠다는 저의 의도가 담겨 있습니다. 참고로 UCLASS 선언에 Blueprintable (Blueprint 클래스로 상속 가능) 매크로를 추가하여야 OnStealthActivated()와 OnStealthDeactivated()가 제대로 Blueprint에 반영됩니다. 이제 머티리얼 부분을 보겠습니다.


2. 머티리얼 그래프 작업

 

Texture의 각 픽셀에는 RGB에 해당하는 값이 들어있고 그 값은 0~1에 사이 값입니다. 검은색에 가까울수록 RGB 값은 (0, 0, 0)에 가까워지고 반대로 흰색에 가까울수록 해당 픽셀에 들어있는 값은 (1, 1, 1)에 가깝다고 할 수 있습니다. 머티리얼 그래프 작업은 0~1까지의 값들을 사칙연산을 통해 조작하는 작업이라고 느꼈습니다. 이를 바탕으로 아래 노드들을 구성하였습니다.

 

우선 사라지는 효과를 담당하는 머티리얼 노드는 Opacity(투명도)와 Opacity Mask입니다. 특히 Opacity Mask는 마스크로 사용된 텍스처의 검은 부분을 투명하게 만듭니다.

 

1번 박스의 노드들을 살펴보겠습니다.

우선 일정하지 않은 패턴의 Noise Texture를 활용했고 검은색-회색-흰색들로만 분포된 픽셀들을 볼 수 있었습니다. 여기서 어떠한 값(Dissolve)를 빼게 되면 그 값만큼 픽셀 값이 작아져 점점 더 어두워질 것이고 결국 검은색에 해당하는 픽셀들이 많아집니다. 그래서 Dissolve 값을 조절하면 머티리얼의 투명한 부분의 양 또한 조절할 수 있게 됩니다. 그 결괏값을 Cheap Contrast 노드에 연결해 주어 간편하게 대비 효과를 줄 수 있었습니다. 그렇게 뚜렷한 경계가 표현된 결과를 Opacity Mask 노드에 연결해주어 Dissolve 값에 따라 머티리얼의 부분 부분을 서서히 투명하게 만들 수 있는 효과를 얻었습니다.

 

다음은 2번 박스입니다.


대비 효과를 준 결과를 1에서 빼주어 흑백 반전 시켜주었습니다. 그리고 특정 색(빨간색)에 해당하는 값을 곱해주었는데, 곱셈은 1에 가까운 값에 더 반영이 잘 되기 때문에 원래 검은색에 해당했던 부분들이 특정 색을 더 잘 띠게 됩니다. 그리고 다시 한번 특정 값(Emissive)를 곱해주면 값들이 더 커지게 됩니다. Emissive는 발광 효과를 낼 수 있고 최고 값이 없기 때문에 그 값이 더 커질수록 더 발광합니다.  

 

이렇게 만든 Emissive와 Opacity Mask를 활용하면 투명한 부분과 아직 Texture가 남아 있는 부분에 테두리 효과를 줄 수 있습니다. 비록 대비 효과를 주었지만, 비교적 0이나 1에 가깝지 않던, 회색에 가깝던 부분들에 특정 색이 입혀졌고 그 부분들이 미쳐 Opacity Mask로 투명화되지 않았기 때문입니다.

 

이렇게 연결한 노드를 Material Function으로 만들어 기존 Material에 연결해주었습니다.

 

3. Blueprint Event Graph 작업

아래와 같이 C++에서 BlueprintImplementable 매크로로 선언한 OnStealthActivated()와 OnStealthDeactivated() 함수를 구현했습니다. Dynamic Material Instance를 만들어 그 Material의 Dissolve 값을 Loop와 Timer를 사용하여 조절하였습니다.

 

4. 프로젝트 기능 시연

 

 

'TIL > C++와 UE' 카테고리의 다른 글

네트워킹 및 멀티 플레이어 개요  (0) 2025.03.10
작성중  (0) 2025.02.26
Enemy(Monster) 클래스  (0) 2025.02.24
언리얼 엔진 AI 행동 제어 시스템  (0) 2025.02.17
파티클 시스템  (0) 2025.02.11

Enemy(Monster) 클래스

언리얼 거토
|2025. 2. 24. 21:38

목차

1.개요
2. Enemy(Monster) 클래스 구조
3. Monster 기능 컴포넌트
4. Monster 클래스별 컴포넌트 구성

5. 몬스터 컴포넌트 활용


1. 개요

프로젝트에서 적(몬스터) 구현 역할을 맡았고 특히 AI 구현은 복잡합니다. AI Controller, Behavior Tree, 그리고 Black Board에서는 각 몬스터의 기능을 활용하기 때문에 몬스터 클래스 구조부터 정리하고자 합니다. 

 

2. Enemy(Monster) 클래스 구조

몬스터 타입(일반, 보스) 별 각 기능을 구상하며 위와 같이 클래스를 설계하였습니다.

3. 몬스터 컴포넌트

  • 공격 관련
    • MonsterAttackComponent (일반 공격)
  • 상태 관련
    • MonsterStatComponent (스탯 관리)
    • HitReactionComponent (피격 반응)
    • BerserkModeComponent (광폭화 모드)
  • 스킬 관련
    • BaseSkillComponent (기본 스킬 추상 클래스)
      • JumpAttackComponent (점프 공격)
      • ChargeAttackComponent (돌진 공격)

MonstStatComponent(몬스터 스테이터스 컴포넌트) 코드 예시

//MonsterStatComponent.h
#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "MonsterStatComponent.generated.h"


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class PEPCCINE_API UMonsterStatComponent : public UActorComponent
{
	GENERATED_BODY()

public:	
	UMonsterStatComponent();

protected:
	virtual void BeginPlay() override;

public:	
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stat")
    float MaxHealth = 100.0f;
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Stat")
    float CurrentHealth;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stat")
    float Attack = 10.0f;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stat")
    float Defense = 5.0f;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stat")
    float Speed = 300.0f;

    UFUNCTION(BlueprintCallable, Category = "Stat")
    void DecreaseHealth(float Amount);
    UFUNCTION(BlueprintCallable, Category = "Stat")
    void IncreaseHealth(float Amount);
    UFUNCTION(BlueprintCallable, Category = "Stat")

    FORCEINLINE void IncreaseATK(float Amount) { Attack = Attack * Amount; }
    FORCEINLINE void IncreaseDEF(float Amount) { Defense = Defense * Amount; }
    FORCEINLINE void IncreaseSPD(float Amount){ Speed = Speed * Amount; }

    UFUNCTION(BlueprintPure, Category = "Stat")
    bool IsDead() const;
};
//MonsterStatComponent.cpp
#include "Monster/Component/MonsterStatComponent.h"

UMonsterStatComponent::UMonsterStatComponent()
{
	PrimaryComponentTick.bCanEverTick = false;
	CurrentHealth = MaxHealth;  // 초기 체력 = 최대 체력
}

void UMonsterStatComponent::BeginPlay()
{
	Super::BeginPlay();
}


void UMonsterStatComponent::DecreaseHealth(float Amount)
{
    float FinalDamage = FMath::Max(Amount - Defense, 1.0f);  // 방어력 적용, 최소 데미지 1
    CurrentHealth = FMath::Max(CurrentHealth - FinalDamage, 0.0f);

}

void UMonsterStatComponent::IncreaseHealth(float Amount)
{
    CurrentHealth = FMath::Min(CurrentHealth + Amount, MaxHealth);
}

bool UMonsterStatComponent::IsDead() const
{
    return CurrentHealth <= 0.0f;
}

 

4. 몬스터 클래스별 컴포넌트 구성

  • BaseMonster
    • MonsterAttackComponent
    • MonsterStatComponent
    • HitReactionComponent

일반 몬스터 ZombieCop의 컴포넌트

  • BossMonster
    • BerserkModeComponent
    • JumpAttackComponent
    • ChargeAttackComponent

보스 몬스터 JumpAttackComponent, BeserkModeComponent 추가 예시

5. 몬스터 컴포넌트 활용

  • AI Controller에서 사용
  • BehaviorTree 내 BTTask에서 호출


✏️ 스스로 Enemy AI의 이해를 돕기 위해 PPT를 활용하여 시각화해보았습니다. 어렵네요 ..ㅋㅋㅋ  

'TIL > C++와 UE' 카테고리의 다른 글

작성중  (0) 2025.02.26
머티리얼 조작  (0) 2025.02.25
언리얼 엔진 AI 행동 제어 시스템  (0) 2025.02.17
파티클 시스템  (0) 2025.02.11
게임 메뉴 UI 디자인  (0) 2025.02.07

STL 기본 구조

언리얼 거토
|2025. 2. 18. 22:12

STL이란?

STL(Standard Template Library)은 C++의 내장 템플릿 라이브러리로, 컨테이너, 반복자(Iterator), 알고리즘 세 가지 요소로 구성됨.

  • 컨테이너(Container): 데이터를 저장·관리하는 자료구조
  • 반복자(Iterator): 컨테이너 내 데이터를 순회하는 포인터 역할
  • 알고리즘(Algorithm): 정렬, 탐색, 삽입, 삭제 등 다양한 기능 제공

STL을 잘 활용하면 코딩 테스트에서 시간을 크게 절약할 수 있음. 직접 자료구조를 구현하는 것보다 훨씬 효율적.


STL의 3가지 요소

이 세 가지 요소는 서로 연동되어 강력한 기능을 제공함.

  • 컨테이너 → 데이터를 담는 창고
  • 반복자 → 창고 정리하는 도우미
  • 알고리즘 → 문제 해결을 돕는 용병

1. 컨테이너 (Container)

데이터를 저장하는 구조로, vector, list, deque 등이 있음.

vector (동적 배열)

  • 연속된 메모리 블록을 사용해 랜덤 접근이 빠름
  • push_back() / pop_back() 으로 끝부분 추가·삭제 효율적
  • 중간 삽입·삭제 시 데이터 이동이 발생해 비효율적

📌 주요 함수

vector<int> v;
v.push_back(10); // 맨 뒤 추가
v.pop_back();    // 맨 뒤 삭제
v.insert(v.begin() + 1, 20); // 중간 삽입
v.erase(v.begin() + 2); // 중간 삭제
 

list (이중 연결 리스트)

  • 중간 삽입·삭제 빠름 (포인터만 변경하면 됨)
  • 메모리가 연속적이지 않아 랜덤 접근 느림
  • 순차적 추가·삭제에 적합

📌 주요 함수

list<int> lst;
lst.push_back(30);
lst.push_front(20);
lst.insert(next(lst.begin()), 25); // 중간 삽입
lst.erase(lst.begin()); // 첫 번째 원소 삭제

deque (양방향 동적 배열)

  • 양쪽 끝 삽입·삭제 빠름
  • 랜덤 접근 가능
  • 중간 삽입·삭제는 비효율적

📌 주요 함수

deque<int> dq;
dq.push_back(10);
dq.push_front(20);
dq.pop_back();
dq.pop_front();

 

Map (Key - Value)

  • (key, value) 쌍을 저장하는 자료구조
  • 키를 통해 값을 빠르게 탐색 가능
  • 레드-블랙 트리 기반검색, 삽입, 삭제 O(log N)
  • 키는 유일하며 자동 정렬됨

📌 주요 함수

map<int, string> mp;
mp.insert({1, "Apple"}); //키-값 쌍 삽입
mp[2] = "Banana";  // operator[key]키로 값에 접근 또는 삽입
if (mp.find(1) != mp.end()) // 키로 요소 검색 (iterator 반환)
mp.erase(2); // 키로 요소 제거
int size = mp.size(); // 요소 개수 반환

 

Set

  • 유일한 키만 저장 (중복 불가)
  • 레드-블랙 트리 기반O(log N)
  • 자동 정렬됨

📌 주요 함수

set<int> s;
s.insert(10);
s.insert(5);
s.insert(20);
if (s.find(10) != s.end()) 
    cout << "10 exists in set" << endl;
s.erase(5);
cout << "Set size: " << s.size() << endl;

    // lower_bound(value), upper_bound(value)
    cout << "Lower bound of 10: " << *s.lower_bound(10) << endl;
    cout << "Upper bound of 10: " << *s.upper_bound(10) << endl;
}

2. 반복자 (Iterator)

컨테이너 원소를 순회하는 포인터 역할.

  • begin(), end() → 순차 탐색
  • rbegin(), rend() → 역순 탐색
  • ++it, --it → 이동
  • *it → 값 참조

📌 반복자 사용 예시

vector<int> v = {3, 1, 4, 1, 5, 9};
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
    cout << *it << " ";
}

3. 알고리즘 (Algorithm)

STL이 제공하는 다양한 기능 활용 가능.

 

📌 정렬 예시

vector<int> v = {3, 1, 4, 1, 5, 9};
sort(v.begin(), v.end()); // 정렬

 

 

📌 이진 탐색 예시

binary_search(v.begin(), v.end(), 4); // 4가 존재하면 true

어떤 컨테이너를 써야 할까?

중간 삽입/삭제 많음 → list
랜덤 접근 필요 → vector
양쪽 끝 추가/삭제 많음 → deque

 

'C++' 카테고리의 다른 글

클린코딩  (0) 2025.03.27
브루트포스 기법  (0) 2025.03.11

목차

1. Behavior Tree(비헤이비어 트리)

2. Black Board(블랙보드)

3. AI Controller

4. NavMesh


1. Behavior Tree (비헤이비어 트리)

비헤이비어 트리는 AI의 행동을 결정하는 계층적 구조를 가진 트리. 각 노드(Node)에는 특정 역할이 있으며, AI는 루트(Root) 노드에서 시작하여 조건에 따라 적절한 행동을 수행.

1-1. 비헤이비어 트리의 주요 노드 유형

  • Root 노드: 트리의 시작점
  • Composite 노드 (합성 노드): 여러 개의 하위 노드를 가질 수 있음
    • Selector (선택자): 왼쪽부터 실행하며, 성공하는 노드를 찾으면 중단
    • Sequence (시퀀스): 왼쪽부터 순서대로 실행하며, 하나라도 실패하면 중단
  • Decorator 노드 (데코레이터 노드): 특정 조건을 검사하여 실행 여부를 결정
  • Task 노드 (태스크 노드): AI가 수행할 실제 동작 (ex. 이동, 공격)


2. Blackboard (블랙보드)

AI가 정보를 저장하고 공유하는 데이터 저장소.

비헤이비어 트리와 함께 사용되며, AI의 의사 결정에 필요한 변수(위치, 상태 등)를 관리.

2-1 블랙보드의 주요 기능

  • 키(Key) 시스템: 데이터 항목을 저장하는 변수 (ex. TargetLocation, HasEnemy)
  • AI가 환경 정보를 저장하고 활용 가능
  • 비헤이비어 트리 내에서 데코레이터 또는 태스크 노드를 통해 활용


3. AI Controller (AI 컨트롤러)

  • AI 캐릭터를 제어하는 핵심 클래스
  • AI가 어떤 논리를 따라야 하는지 결정하고, Behavior Tree를 실행하는 관리자.
    •   예: AI의 상태(Idle, Chase 등) 전환 관리

3-1. AIController의 주요 역할

  • 비헤이비어 트리 및 블랙보드 초기화
  • AI 이동 및 감지 기능 (Perception System)
  • Pawn(캐릭터) 제어 및 명령 전달

3-2. AI Controller 설정 과정

  1. AIController 클래스를 생성하고 AController를 상속
  2. UseBlackboard() 함수로 블랙보드를 초기화
  3. RunBehaviorTree() 함수로 비헤이비어 트리 실행
  4. Possess() 함수를 오버라이드하여 AI 캐릭터를 제어
#include "MyAIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "BehaviorTree/BehaviorTree.h"

void AMyAIController::BeginPlay()
{
    Super::BeginPlay();

    if (UseBlackboard(BlackboardAsset, Blackboard))
    {
        RunBehaviorTree(BehaviorTree);
        
        // 블랙보드에 초기 목표 위치 설정
        FVector RandomLocation(1000.0f, 500.0f, 0.0f);
        Blackboard->SetValueAsVector(TEXT("PatrolLocation"), RandomLocation);
    }
}
 

4. NavMesh (내비게이션 메시)

  • AI가 이동할 수 있는 경로를 결정하는 내비게이션 시스템.

4-1. NavMesh 설정 방법

  1. NavMesh Bounds Volume 추가
    • Modes 패널에서 Nav Mesh Bounds Volume을 배치
    • AI가 이동할 수 있는 영역을 지정
  2. RecastNavMesh 확인
    • World Settings에서 RecastNavMesh 활성화
  3. AI 이동을 위한 Pathfinding
    • GetNavAgentLocation() 및 FindPathToLocation() 등의 함수를 사용 가능

4-2. AI가 NavMesh를 활용해 이동하는 코드 예제

UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(this);
FNavLocation NavLocation;

if (NavSys->GetRandomPointInNavigableRadius(GetActorLocation(), 500.0f, NavLocation))
{
    MoveToLocation(NavLocation.Location);
}

AI가 500 유닛 반경 내에서 랜덤한 위치를 찾아 이동하는 방식.

 


참조: Behavior Tree Quick Start Guide

'TIL > C++와 UE' 카테고리의 다른 글

머티리얼 조작  (0) 2025.02.25
Enemy(Monster) 클래스  (0) 2025.02.24
파티클 시스템  (0) 2025.02.11
게임 메뉴 UI 디자인  (0) 2025.02.07
Pawn 클래스 캐릭터의 부드러운 움직임  (1) 2025.02.05