유니티에서 생성과 파괴는 생각보다 무거운 작업이다. 그래서 많은 오브젝트를 빠르게 생성할수록 프로그램은 부하가 걸릴 것이다. 그래서 사용하는 것이 Object Pooling이다.

Object Pooling은 미리 오브젝트를 게임 시작할 때에 만들어두고 필요할 때마다 미리 만들어 두었던 오브젝트를 가져와 사용하는 기법이다.

 

https://notminseodevelop.tistory.com/7?category=901556 

 

2022년 01월 03일 Unity 개인 공부 1일차

구현한 것 - GetAxisRow 함수를 이용하여 플레이어 이동 구현 - 탄젠트 성질을 이용하여 Bullet이 생성될 때 마우스 포인터의 위치를 바라보도록 각도 지정 - CameraShake 기능을 구현하여 총알을 발사할

notminseodevelop.tistory.com

저번 글에서 총알 발사를 구현할 때 나는 총알을 생성하고 1초뒤에 파괴하는 식으로 구현을 했었다.

이것을 Object Pooling 기법을 이용해 조금 더 효율적으로 프로그램을 짜 보도록 하겠다.

 

전체적인 프로그래밍은 https://youtu.be/tdSmKaJvCoA 이 영상을 참고하여 만들었다.

 

그렇게 해서 만들어진 오브젝트 풀링 시스템이다.

Pool이라는 클래스를 어떤 오브젝트인지 구분해주는 tag와 생성할 오브젝트를 저장하는 prefab 그리고 처음 생성할 때 총 몇 개를 생성할 것인지 저장하는 size 총 3개의 변수가 구성되도록 만들었다.

 

List를 public으로 생성하면 인스펙터 창에서 이런식으로 직접 생성을 할 수 있다.

Start()에서는 이런식으로 저장된 List들을 모두 불러와 tag별로 Queue를 만들어 저장하는 작업을 진행해준다.

SpawnFromPool()에서는 매개변수로 무슨 오브젝트인지 구별해주는 tag, 어느 위치에 어느 방향으로 생성할 것인지를 받는다. 처음에 예외처리로 tag가 존재하는지 확인하고 만약 내가 준비해둔 오브젝트들을 다 썼을 때 추가로 생성하는 코드를 짰다. 그 이후로 아까 Queue에 저장돼있던 오브젝트를 꺼내와서 매개변수로 받아온 위치와 방향으로 설정해 생성해준다.

InputToPool()은 총알처럼 특정 조건이 되면 사라져야하는 오브젝트를 구현할 때 사용하는 함수로 다시 Queue에 함수를 넣고 지워준다.

총알을 예시로 Object Pooler 시스템을 사용하는 예시 코드를 보여주겠다.

총알 생성 코드
총알 삭제 코드

16~21번째 줄 코드처럼 생성하면 어떤 파일에서든지 GetComponent<>()를 사용하지 않고도 한 줄로 쉽게 접근할 수 있다. 이와 관련된 내용을 싱글톤 패턴이라고 하는데 찾아보면 도움이 많이 된다.

그렇게 해서 조금더 효율적으로 수정된 게임의 결과물이다.

총알 10개가 게임 시작과 동시에 생성
준비된 오브젝트가 부족할 때 추가되는 총알들

느낀 점

이런 기법들을 배울 때마다 어떻게 사람들은 이렇게 창의적인 생각을 할 수 있는 거지라고 감탄을 금치 못한다.

이런 기법들을 배우고 실제로 내 게임에 활용할 때 꾸준히 개발을 할 수 있게 해주는 '재미'를 느끼게 된다.

앞으로도 조금 더 효율적이고 재미있는 게임을 만들기 위해 더 노력해야겠다.

'유니티 개발' 카테고리의 다른 글

Danma 완성  (1) 2022.04.05
유니티 개발 현황 #2  (0) 2022.02.19
유니티 개발 현황 ( 탄막 패턴, 버그 )  (0) 2022.01.30
2022년 01월 03일 Unity 개인 공부 1일차  (0) 2022.01.03

1. 상금 배분 (8점)

문제

   한국 시리즈 야구 결승은 7전 4선승제로 4번을 먼저 이기는 팀이 우승한다.

   A팀과 B팀이 맞붙었는데, 처음 2경기를 A팀이 이긴 상태에서 사회적 거리두기로 더 이상 경기를 진행하지 않기로 했다.

   A팀과 B팀의 실력은 동일하여 이길 확률은 같고, 승패를 결정하는 다른 요인이 없다고 하자.

   한국 시리즈 우승 상금은 16억원이고, 이를 A팀이 2승으로 앞선 상태에서 A팀과 B팀의 우승확률을 가지고 배분하려고 한다.

   A팀에게 얼마를 배정하는 것이 공정할까?

 

1. 8억원

2. 10억원

3. 13억원

4. 14억원

5. 15억원

정답

3번

풀이

A팀은 이미 2번을 이겼기 때문에 2번만 더 이겨주면 되는 상황

A팀이 2번 연속 우승할 때와 1번지고 2번 우승할 경우, 2번지고 2번 우승할 경우, 3번지고 2번 우승할 경우의 확률을 구해 더해준다. 

이긴 팀 | A가 이길 확률

AA | 1/4
BAA | 1/8
ABA | 1/8
BBAA | 1/16
BABA | 1/16
ABBA | 1/16
BBBAA | 1/32
BBABA | 1/32
BABBA | 1/32
ABBBA | 1/32

A가 이길 확률 26/32 즉, 13/16이므로 3번이다.

이때 주의해야할 점은 BBAAB 같은 경우는 이미 A가 2번 우승했기에 BBAA 상황과 겹치게 된다. 고로 A가 한번 이상 지고 2번 이겨 우승할 경우의 수를 구할 때 A가 우승할 경우의 2번 중 한번은 무조건 마지막 판에 우승해야한다.

알레프

  • 기초과학연구원이 사용하는 국내 공공기관 세 번째 슈퍼컴퓨터
  • 미국 슈퍼컴퓨터 전문 업체인 크레이에서 제작되었다.
  • 가격은 약 100억원이며 이론상 연산 속도는 1.43PT(페타플롭스) 가 나온다.
  • 이때 1PT(페타플롭스)는 1초에 1000조번 연산이 가능하다.
  • 저장용량은 대략 8740TB정도 된다.
  • 사용되는 분야는 장, 단기 기후 변화 예측과 물리학, 화학, 생명과학에 활용된다.
  • 2018년 11월에 열린 세계 슈퍼컴퓨터 순위에 따르면 알레프는 실측 연산 속도 기준 0.97PF를 기록했으며 세계 443위를 차지하였다.

출처: 기초과학연구원

 

빅오표기법과 stack 자료구조에 대해서 배웠다
수업 종료 10분전 문제 하나를 과제로 내주셨는데 내용은 이러하다
이런식으로 그래프가 주어지면 막대 그래프 맨 위쪽에 빨간 선을 그 그래프 기준 왼쪽으로 긋는데
이때 빨간 선이 닿는 그래프가 몇번인지 출력하는 문제이다.

그럼 한번 이 문제를 풀어보자

첫번째로 1번 배열에 있는 정보를 스택에 넣는다.

탐색을 2번 배열부터 시작하며 탐색하려는 값과 스택을 비교한다.
비교하는 도중 스택의 top에 자신보다 작은 값이 있으면 그 값은 결국 지금 탐색하는 값에 가려져 더이상 닿을 레이저가 없기 때문에 pop한다.

위와 같은 행동을 자신보다 큰 값이 나올 때 까지 반복한다.

i) 자신보다 큰 값이 나왔으면 현재 탐색하고 있는 값의 빨간 선은 그 값을 가리킨다.
ii) 자신보다 큰 값이 없다면 (스택이 비었다면) 현재 탐색하고 있는 값은 가장 큰 값이 된다.
즉 빨간 선은 제일 왼쪽 끝으로 간다.

이것은 실제로 학원에서 집으로 돌아오기 전에 짠 순서도이다. 선생님께서는 항상 문제를 풀 때 키보드에 바로 손을 대지 말고 먼저 내가 어떻게 코드를 짤 것인지 생각을 하라고 강조하셨다.
이 조언과 미리 짜둔 순서도 덕분에 나는 코드를 짤 때 전보다 더 수월하게 짤 수 있었다.
그렇게 해서 나온 코드이다.

 


HM(최대치) 를 10으로 설정하여 돌려봤을 때 잘 나오는 것을 확인 할 수 있었다.

이런식으로 코드를 짜면 스택을 바로바로 비워줄 수 있기 때문에 속도가 조금 빨라 질 수 있다.
시간복잡도는 탐색할 때 한번 스택으로 다시 검사할 때 한번으로 O(2N)이 나온다

구현한 것
- GetAxisRow 함수를 이용하여 플레이어 이동 구현
- 탄젠트 성질을 이용하여 Bullet이 생성될 때 마우스 포인터의 위치를 바라보도록 각도 지정
- CameraShake 기능을 구현하여 총알을 발사할 때 타격감 조성
- AudioSource 기능을 이용하여 총알 발사 음 구현
- 마우스 클릭 지속 혹은 연타하더라도 일정한 간격으로 총알이 발사되도록 조정
- 메모리 누수를 막기 위해 총알이 생성된 기점으로 1초가 지나면 제거되도록 설정

'유니티 개발' 카테고리의 다른 글

Danma 완성  (1) 2022.04.05
유니티 개발 현황 #2  (0) 2022.02.19
유니티 개발 현황 ( 탄막 패턴, 버그 )  (0) 2022.01.30
Object Pooling (오브젝트 풀링)  (0) 2022.01.24

이 글은 그래프 탐색을 이해했다는 것을 전제 하에 쓰였습니다.
이 문제는 DFS(깊이우선탐색)을 연습하는게 딱 좋은 맵이라고 생각한다. 영어라고 겁먹을 필요없다.
우리에게는 파파고라는 좋은 친구가 있으니까

영어싫어

우리 파파고가 말해준 문제를 약간 요약했을때 이 문제는 저 사진에 나와있는 피라미드로 되어있는 숫자들이 보일것이다. 그래서 맨위의 숫자부터 밑으로 한층씩 내려오는데 이때 자신의 위치에서 바로 왼쪽, 오른쪽 밖에 갈 수가 없다. 그렇게 끝까지 내려왔을때의 합이 가장 큰 경우에서 그 합을 출력하면 되는것이다.
입력으로는 첫번째로 몇층으로 할건지 받고
그이후 피라미드가 만들어졌을때의 갯수 만큼의 숫자를 입력받는다.
출력은 가장 큰 합을 출력한다.
예시로

못그려서 죄송합니다

저 원을 노드라하고 빨간선을 간선이라고 했을때 맨 위에 있는 노드로 부터 시작해서 점점 탐색을 하는데 만약 탐색을 하던 도중 노드에서 외부 노드로 향하는 간선의 갯수가 0일때를 가장 피라미드의 밑부분까지 왔다고 판단하여 지금까지 지나온 경로를 합으로 더하는 방식으로 코드를 짰다.

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

int Num = 0;
int* answer;
int Real_answer = 0;
int N;

typedef struct Node {
	int score = 0;
	vector<int> adj;
} Node;

vector<Node> x;
int real_box = 0;
void DFS(int num, int a) {
	answer[a] = x[num].score;
	if (x[num].adj.size() == 0) {
		for (int i = 0; i < N; i++) {
			real_box += answer[i];
		}
		if (Real_answer < real_box) {
			Real_answer = real_box;
			
		}
		real_box = 0;
		return;
	}
	for (int i = 0; i < x[num].adj.size(); i++) {
		DFS(x[num].adj[i], a + 1);
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> N;
	answer = new int[N];
	for (int i = N; i >= 1; i--) {
		Num = Num + i;

	}
	for (int i = 0; i < N; i++) {
		answer[i] = 0;
	}
	x.resize(Num);
	int as = 1; 
	int ad = 0;
	for (int i = 0; i < Num; i++) {
		if (ad == as) {
			ad = 0;
			as++;
		}
		cin >> x[i].score;
		if (as < N) {
			x[i].adj.push_back(i + as);
			x[i].adj.push_back(i + as + 1);
		}
		ad++;
	}
	DFS(0, 0);
	cout << Real_answer;
	return 0;
}

이 코드는 처음 짰을 당시 보여주기 용으로 짠 코드가 아니기에 보기에 다소 불편한 구조들이 많다. ex) 변수명

DFS 기초 문제이기 때문에 방식만 안다면 쉬울 것 이므로 코드를 보기보다는 방식만 알아둬도 푸는데 지장이 없다.

막상 일기를 쓰려하니 무엇을 써야할지 고민하던 찰나 고맙게도 친구에게 해당 카톡이 왔다.

이게 보통 C언어에서 발생하는 문제인데 이걸 처음 직면하면 답이 없다.
왜냐하면 컴파일할때 로그를 봐도 뭐가 문제인지 안보이기 때문이다.
문제는 해당 변수를 입력하고 엔터를 입력할 때 입력버퍼에게 엔터가 남아있어서 다음 입력을 받을때 scanf가 남아있는 입력버퍼로 입력을 받아들인다는 것이다.
입력버퍼는 scanf() 같은 입력을 받는 함수에서 입력을 받을 때 입력버퍼라는 저장소에 한번 저장이 되었다가 변수로 대입하는 것이다.
그래서 저 엔터를 입력버퍼에서 지워줘야 하는데
입력버퍼를 비우는 방법은 간단하다.
사이에 getchar(); 코드를 넣어줘서 입력버퍼를 비워버리자

이렇게 말이다!

그거 말고도 여러방법이 있지만 나는 이 방법이 제일 간단한 것 같다.
근데 이게 처음에 말했듯이 오류창도 로그에도 안떠서 뭐가 문젠지 모른다.
이 글이 도움이 됬으면 좋겠다.

혹시 틀린것이 있으면 댓글로 말해주시면 감사하겠습니다.

안녕하세요 현재 한국애니메이션고등학교에 재학 중인 22기 김민서라고 합니다.
주로 백준 알고리즘 문제에 관해서 올릴 것 같습니다.
또한 유니티로 개발중인 게임과 개발을 하면서 얻은 정보, 팁들도 올릴 예정입니다.
만약 정보가 틀리거나 코드가 정리가 필요하거나 고쳐야한다면 언제든지 피드백 부탁드립니다.
제 블로그의 최종 목표는 같이 알아가는 입장에서 쉽게 이해할 수 있는 글을 쓰는 것입니다.
글 읽어주셔서 감사합니다. 다음 글에서 뵙도록 하겠습니다.

+ Recent posts