Skip to content

Z1758/KGA_OOPConsoleProject

Repository files navigation

랜덤 타워 디펜스

1

어떤 게임을 만들어볼까 고민 하던 중

이런 랜덤 타워 디펜스를 구현 하는건 어떨까 하여 선택




2

조잡하게 완성 된 구상도


전체적인 게임의 흐름

gm712537_luckydefense_main

  1. 한 좌표에서 생성 되는 적들이 같은 길을 순환

  2. 적의 수가 일정치 이상 넘어가면 패배

  3. 적을 쓰러트려 자원을 모아서 타워를 뽑거나 합쳐서

  4. 마지막 라운드 까지 버텨서 보스를 쓰러트리면 승리




작업 순서


1. 초기화 작업, 맵 출력

2. 적 생성, 이동, 제거

3. 타워 생성, 공격

4. 플레이어 조작

5. 타워 합성, 판매

6. 스테이지 설정, 패배, 승리

7. 마무리





클래스


제목 없음-1

이런 느낌으로 클래스를 구분 지어봤다

33

동적 객체 타워와 적은 타이머로 움직임을 관리하고

맵은 메인에서 while문을 돌려서 계속 갱신

34

그리고 동적 객체들은 생성과 소멸이 자주 발생하기에

오브젝트 풀링 기법을 활용 하여

플레이어 목숨 만큼의 적들을 미리 Queue에 담아 놓고

타이머를 통해 적을 생성 해야 할 때마다 하나씩 꺼내 List에 담아

활성화 된 적들을 관리한다

35

적의 체력이 바닥나 소멸 해야 할 때 List에서 제거 후 Queue에 반환 한다




맵 출력


Pasted image 20240814232016

Pasted image 20240814232033

전에 만들었던 테트리스에서 만들었던 코드를 재활용

문자를 입력할 배열과

색을 넣을 배열을 구분

Pasted image 20240814232052

그렇게 일단 맵부터 생성

Pasted image 20240815003412

적이 지나는 길은 매번 갱신 해줘야 하기 때문에

따로 길만 범위를 지정해 사용하려 했지만

3e4c529ecd03d5c8942a15077a464c24_res

더 간단하고 보기 좋게 만들 수 있지 않을까 고민 해본 결과

Pasted image 20240815020902

Queue에 적의 길을 넣어두고 사용하니 훨씬 간단해졌다

Pasted image 20240815021148

Pasted image 20240815021135

그러나 사이즈를 늘려서 스톱워치를 통해 속도를 비교해보니

배열이 훨씬 더 빠른게 아닌가

1714c213ba87e94a 1

Pasted image 20240815021311

구조체로도 만들어 봤으나 확실히 배열을 이길순 없었다

조금 불편하더라도 계속 반복문을 돌려서 호출 해야 하는 함수이니

속도가 빠른 쪽을 쓰는게 맞다 판단하여 결국 쓰던걸 쓰기로 했다

Pasted image 20240815100521

상수의 모음을 만들어둔 static 클래스 PixelType을 활용해 보기 쉽게 만들어주고

색상을 지정 해준 뒤 맵은 이렇게 끝내고서 다음 단계로 간다




적 구현


생성

12

적의 정보는 StageManager의 딕셔너리에 저장 하고

스테이지 레벨에 맞춰 정보를 꺼내며 생성 되는 적들에 초기화를 해준다

이동

ezgif-1-442d11ff1d

적이 생성 될 때 타이머의 이벤트에 추가 되는데

타이머가 0.1초 마다 반복 될 때마다

적의 이동 함수가 호출 된다

그리고 호출 될 때마다 쿨다운을 체크 하는 변수를 증가 시켜

이동 속도와 같은 값이 되면 그때 적이 이동한다

Pasted image 20240815162314

적의 이동 함수는 적이 끝 부분에 도달 할 때마다 상태를 변경 해

방향을 변경하도록 간단하게 구현

5

잘 움직인다

6

그리고 타이머를 적용해 매 초 마다 적을 생성하게 했다

제거

ezgif-7-f3f52b3b50

타워에게 공격 당해 적의 체력이 0 이하로 떨어지면

GameManager의 이벤트를 호출하면서

자기 자신을 매개 변수로 보내 List에서 제거 되고 Queue로 돌아간다

7

타워에게 공격 당했을 때 체력이 줄어야 하지만

일시적으로 이동 할 때마다 체력이 줄어들게 만들어서 테스트 해본 결과

잘 적용 되는 듯 하다

적은 대강 구현이 끝났으니 다음은 타워를 구현 할 차례다




타워 구현


Pasted image 20240815210431

적과 타워의 비활성화와 타이머의 이벤트로 받는 움직임은

비슷한 로직이기에 인터페이스로 상속 했다

생성

11

타워의 생성은 랜덤으로 값을 받아오고 그 값에 맞는 타워의 정보를

Queue에서 꺼내온 타워 객체에 초기화 해준다

공격

타이머를 통해 행동 하는 것은 비슷하나

타워는 공격 조건이 충족 되면

자신을 매개 변수로 GameManager의 타워의 충돌 확인 이벤트를 호출 하고

타워의 범위와 List에 담겨 있는 적들 중 좌표가 일치 하는 적을 찾아서

해당 적의 TakeDamage 함수를 호출해 데미지를 입힌다

Pasted image 20240815214655

대략 이런 흐름

10

타워의 공격에 적이 제거 당하고 있다




플레이어 조작


동적 객체들의 구현이 거의 끝났으니 이제 플레이어의 조작을 구현하면 되겠다

Player는 GameManager의 인스턴스로 저장 했다

이동

13

이동의 구현은 화살표 키 입력을 받고 범위를 제한한 좌표 값만 변경 해주면 되기 때문에 간단했다

타워 뽑기

14

특정 키를 입력 했을 때

StageManager에 저장된 골드 변수의 값이 감소하며

랜덤 값을 넘겨주고 플레이어 좌표에 타워를 생성 시킨다

타워 합치기

16

플레이어 좌표에 있는 타워의 종류와 같은 타워를 찾아 3개 이상일 경우 3개의 타워를 지우고

상위 등급의 랜덤한 타워를 생성 시킨다

타워 판매

15

플레이어 좌표 위의 타워를 지운다 즉 List에서 제거 하고 Queue에 저장한다

그리고 StageManager의 골드 변수의 값이 증가 한다




게임 클리어, 게임 오버


19

적이 일정 수를 넘어서거나 보스를 제한 시간내 쓰러트리지 못하면 패배하며
게임 오버 씬이 출력 된다

18

마지막 스테이지에서 보스를 쓰러트리면 클리어가 출력 된다




마무리 작업


20

적 뒤에 숫자를 붙여 적이 겹쳐 있을 때의 확인과 문자수가 차이나는걸 해결

21

10 스테이지가 되면 보스가 등장

22

게임이 너무 정적인 듯 하여

적의 체력이 줄어들면 색상이 변경 되게 수정

또한 타워의 공격이 쿨다운 중일 때 흑백 처리를 하여

더욱 동적으로 표현 할 수 있게 만들어 보았다

24

페페개구리12 1

25

라운드 시간과 스테이지, 체력 등 표시 해주고

이렇게 랜덤 타워 디펜스를 완성 시켰다

E8uqGYZVIAcCR-i




26

그러나 생각보다 너무 빨리 완성 되었기에

어떤 기능을 더 추가 해볼까 고민하다가

NB_qC6YRjH7hv6elNznBIBOBZ5AwE-PKYEWKcU03aFzGsc60bOt9KLxocyvB01OxAbOG8joW9mgkShFmTaTKsQ

맵을 미로로 만들고 적에게 A* 알고리즘을 적용 해보기로 했다




순서


1. 미로를 만든다

2. A* 알고리즘으로 미로의 최단 경로를 찾는다

3. 적들에게 최단 경로를 적용하여 이동 시킨다

4. 적이 목적지에 도달 했을 때 체력이 줄어든다

yeGPQm36sDBWn9Q

대충 이런 느낌이 되지 않을까

일단 테스트용 프로젝트를 만들자

미로


미로는 Binary Tree라는 간단한 알고리즘으로 구현 했다

26

일단 외곽과 2의 배수의 칸을 막아주고

27

외곽과 2의 배수의 칸은 제외하는 조건문을 걸고

랜덤 함수를 돌려 밑이나 오른쪽을 뚫게 만들면 끝

9b9daa0df048eabc82c659bc7967670d

걱정 했는데 금방 만들어서 다행이다

A*


Illustration-of-A-algorithm-path-planning

i13291473274

28

어디 괜찮은 예제가 없을까 찾던 중 교수님 깃허브에 올라와 있는 것을 발견

156c5b1fddf2f5a4e

카피



m_1584583752_4411_1583802953ed991efcf5ae428497f50fc842678a50__mn773959__w504__h468__f38536__Ym202003 1

따라치면서 하나씩 분석 해보니

기본적으로 다익스트라 알고리즘과 비슷하지만

휴리스틱 추정값이라는 가중치를 이용해 최단 경로를 구하는 알고리즘이였다

제목 없음 알고리즘의 작동 원리를 이해하기 쉽게 만들어주는 사이트가 있었다

https://www.101computing.net/a-star-search-algorithm/

이 사이트를 통해 대략적인 흐름을 파악하게 되었다

29

그리고 만들어둔 미로에 접목 시켜보았다

이제 본 프로젝트에 클래스를 추가하고 적용 시켜보자

적용



기존에 만든 맵을 0번 모드

랜덤 맵을 1번 모드로 사용하기로 했다

1번 모드일 때 초기화 단계에서

적들에게 A스타 알고리즘으로 구한 길을 입력 시키고

그 길을 따라 이동 시키도록 구현

30

잘 찾아간다

20220311083837_1EfHk5lPk0

하지만 만들고 나서 든 생각이지만 이러면 굳이 미로가 될 필요가 있을까?

31

결국 미로가 의미 없다 생각하여 적이 지나는 길 외엔 전부 유저의 공간으로 메꿔버렸다

32

적이 지나는 길에 타워가 생성 되거나

플레이어와 적의 좌표가 오버랩 되면 적이 이상하게 나오는 등

여러 버그가 있었으나 수정하고

적이 목적지에 도달 했을 때 플레이어의 체력이 줄어드는 것까지 구현하였다



완성1


어찌저찌 게임이 완성 되었다

완성2

너무 쉽다 밸런스 조절에 실패했다

제목 없음-1

전체적인 씬의 흐름은 대략 이렇다


E-U9cMJ2qVCiG5Vse65G_E4-Cb5Xg

아쉬운점은 미로 맵이 설계 단계에 없었기 때문에

급하게 추가하다가 코드가 많이 지저분해졌고

적의 체력 표시를 구현하다 타이머로 인해

색상이 잠깐 다르게 보이는 버그가 생겼다

다음에는 기능의 수정, 추가가 쉽도록 설계를 더 탄탄히 해야겠다

About

랜타디

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages