어떤 게임을 만들어볼까 고민 하던 중
이런 랜덤 타워 디펜스를 구현 하는건 어떨까 하여 선택
조잡하게 완성 된 구상도
-
한 좌표에서 생성 되는 적들이 같은 길을 순환
-
적의 수가 일정치 이상 넘어가면 패배
-
적을 쓰러트려 자원을 모아서 타워를 뽑거나 합쳐서
-
마지막 라운드 까지 버텨서 보스를 쓰러트리면 승리
이런 느낌으로 클래스를 구분 지어봤다
동적 객체 타워와 적은 타이머로 움직임을 관리하고
맵은 메인에서 while문을 돌려서 계속 갱신
그리고 동적 객체들은 생성과 소멸이 자주 발생하기에
오브젝트 풀링 기법을 활용 하여
플레이어 목숨 만큼의 적들을 미리 Queue에 담아 놓고
타이머를 통해 적을 생성 해야 할 때마다 하나씩 꺼내 List에 담아
활성화 된 적들을 관리한다
적의 체력이 바닥나 소멸 해야 할 때 List에서 제거 후 Queue에 반환 한다
전에 만들었던 테트리스에서 만들었던 코드를 재활용
문자를 입력할 배열과
색을 넣을 배열을 구분
그렇게 일단 맵부터 생성
적이 지나는 길은 매번 갱신 해줘야 하기 때문에
따로 길만 범위를 지정해 사용하려 했지만
더 간단하고 보기 좋게 만들 수 있지 않을까 고민 해본 결과
Queue에 적의 길을 넣어두고 사용하니 훨씬 간단해졌다
그러나 사이즈를 늘려서 스톱워치를 통해 속도를 비교해보니
배열이 훨씬 더 빠른게 아닌가
구조체로도 만들어 봤으나 확실히 배열을 이길순 없었다
조금 불편하더라도 계속 반복문을 돌려서 호출 해야 하는 함수이니
속도가 빠른 쪽을 쓰는게 맞다 판단하여 결국 쓰던걸 쓰기로 했다
상수의 모음을 만들어둔 static 클래스 PixelType을 활용해 보기 쉽게 만들어주고
색상을 지정 해준 뒤 맵은 이렇게 끝내고서 다음 단계로 간다
적의 정보는 StageManager의 딕셔너리에 저장 하고
스테이지 레벨에 맞춰 정보를 꺼내며 생성 되는 적들에 초기화를 해준다
적이 생성 될 때 타이머의 이벤트에 추가 되는데
타이머가 0.1초 마다 반복 될 때마다
적의 이동 함수가 호출 된다
그리고 호출 될 때마다 쿨다운을 체크 하는 변수를 증가 시켜
이동 속도와 같은 값이 되면 그때 적이 이동한다
적의 이동 함수는 적이 끝 부분에 도달 할 때마다 상태를 변경 해
방향을 변경하도록 간단하게 구현
잘 움직인다
그리고 타이머를 적용해 매 초 마다 적을 생성하게 했다
타워에게 공격 당해 적의 체력이 0 이하로 떨어지면
GameManager의 이벤트를 호출하면서
자기 자신을 매개 변수로 보내 List에서 제거 되고 Queue로 돌아간다
타워에게 공격 당했을 때 체력이 줄어야 하지만
일시적으로 이동 할 때마다 체력이 줄어들게 만들어서 테스트 해본 결과
잘 적용 되는 듯 하다
적은 대강 구현이 끝났으니 다음은 타워를 구현 할 차례다
적과 타워의 비활성화와 타이머의 이벤트로 받는 움직임은
비슷한 로직이기에 인터페이스로 상속 했다
타워의 생성은 랜덤으로 값을 받아오고 그 값에 맞는 타워의 정보를
Queue에서 꺼내온 타워 객체에 초기화 해준다
타이머를 통해 행동 하는 것은 비슷하나
타워는 공격 조건이 충족 되면
자신을 매개 변수로 GameManager의 타워의 충돌 확인 이벤트를 호출 하고
타워의 범위와 List에 담겨 있는 적들 중 좌표가 일치 하는 적을 찾아서
해당 적의 TakeDamage 함수를 호출해 데미지를 입힌다
대략 이런 흐름
타워의 공격에 적이 제거 당하고 있다
동적 객체들의 구현이 거의 끝났으니 이제 플레이어의 조작을 구현하면 되겠다
Player는 GameManager의 인스턴스로 저장 했다
이동의 구현은 화살표 키 입력을 받고 범위를 제한한 좌표 값만 변경 해주면 되기 때문에 간단했다
특정 키를 입력 했을 때
StageManager에 저장된 골드 변수의 값이 감소하며
랜덤 값을 넘겨주고 플레이어 좌표에 타워를 생성 시킨다
플레이어 좌표에 있는 타워의 종류와 같은 타워를 찾아 3개 이상일 경우 3개의 타워를 지우고
상위 등급의 랜덤한 타워를 생성 시킨다
플레이어 좌표 위의 타워를 지운다 즉 List에서 제거 하고 Queue에 저장한다
그리고 StageManager의 골드 변수의 값이 증가 한다
적이 일정 수를 넘어서거나 보스를 제한 시간내 쓰러트리지 못하면 패배하며
게임 오버 씬이 출력 된다
마지막 스테이지에서 보스를 쓰러트리면 클리어가 출력 된다
적 뒤에 숫자를 붙여 적이 겹쳐 있을 때의 확인과 문자수가 차이나는걸 해결
10 스테이지가 되면 보스가 등장
게임이 너무 정적인 듯 하여
적의 체력이 줄어들면 색상이 변경 되게 수정
또한 타워의 공격이 쿨다운 중일 때 흑백 처리를 하여
더욱 동적으로 표현 할 수 있게 만들어 보았다
라운드 시간과 스테이지, 체력 등 표시 해주고
이렇게 랜덤 타워 디펜스를 완성 시켰다
그러나 생각보다 너무 빨리 완성 되었기에
어떤 기능을 더 추가 해볼까 고민하다가
맵을 미로로 만들고 적에게 A* 알고리즘을 적용 해보기로 했다
대충 이런 느낌이 되지 않을까
일단 테스트용 프로젝트를 만들자
미로는 Binary Tree라는 간단한 알고리즘으로 구현 했다
일단 외곽과 2의 배수의 칸을 막아주고
외곽과 2의 배수의 칸은 제외하는 조건문을 걸고
랜덤 함수를 돌려 밑이나 오른쪽을 뚫게 만들면 끝
걱정 했는데 금방 만들어서 다행이다
어디 괜찮은 예제가 없을까 찾던 중 교수님 깃허브에 올라와 있는 것을 발견
따라치면서 하나씩 분석 해보니
기본적으로 다익스트라 알고리즘과 비슷하지만
휴리스틱 추정값이라는 가중치를 이용해 최단 경로를 구하는 알고리즘이였다
알고리즘의 작동 원리를 이해하기 쉽게 만들어주는 사이트가 있었다
https://www.101computing.net/a-star-search-algorithm/
이 사이트를 통해 대략적인 흐름을 파악하게 되었다
그리고 만들어둔 미로에 접목 시켜보았다
이제 본 프로젝트에 클래스를 추가하고 적용 시켜보자
기존에 만든 맵을 0번 모드
랜덤 맵을 1번 모드로 사용하기로 했다
1번 모드일 때 초기화 단계에서
적들에게 A스타 알고리즘으로 구한 길을 입력 시키고
그 길을 따라 이동 시키도록 구현
잘 찾아간다
하지만 만들고 나서 든 생각이지만 이러면 굳이 미로가 될 필요가 있을까?
결국 미로가 의미 없다 생각하여 적이 지나는 길 외엔 전부 유저의 공간으로 메꿔버렸다
적이 지나는 길에 타워가 생성 되거나
플레이어와 적의 좌표가 오버랩 되면 적이 이상하게 나오는 등
여러 버그가 있었으나 수정하고
적이 목적지에 도달 했을 때 플레이어의 체력이 줄어드는 것까지 구현하였다
어찌저찌 게임이 완성 되었다
너무 쉽다 밸런스 조절에 실패했다
전체적인 씬의 흐름은 대략 이렇다
아쉬운점은 미로 맵이 설계 단계에 없었기 때문에
급하게 추가하다가 코드가 많이 지저분해졌고
적의 체력 표시를 구현하다 타이머로 인해
색상이 잠깐 다르게 보이는 버그가 생겼다
다음에는 기능의 수정, 추가가 쉽도록 설계를 더 탄탄히 해야겠다





























































