본문 바로가기

개발 프로젝트/Win32 - VampireSurvivor 모작

(10)
로그라이크 게임 구현 (4 - 2) 스킬 및 몬스터와의 상호작용 구현 캐릭터와 몬스터와의 충돌을 구현하였다. 충돌 판정을 구현하는 것 자체는 비트맵끼리 충돌을 감지해 bool값을 반환하는 IntersectRect를 활용하면 간단했다. 그러나 충돌 판정을 약 30프레임 즉 32ms마다 감지한다면 몬스터와 스치기만해도, 순식간에 CharacterLife가 줄어들 것이다. 때문에 충돌판정을 구현할 때 가장 신경써야 할 점은 캐릭터의 무적시간을 구현하는 것이다. 먼저 character 구조체에 characterInvincibleTime이라는 DWORD 자료형(unsigned long) 변수를 선언한다. 그리고 버퍼링을 구현한 메인 함수에서 선언된 시간을 저장하는 dwTime변수를 참조하는 포인터를 선언한다. 그리고 포인터 변수 활용해 CheckCharacterDamaged 함수에..
로그라이크 게임 구현(4) - 비쥬얼 업데이트, TransparentBlt 함수 기존의 무미건조한 맵을 수정했다. 기존의 맵을 자세히 보면 파란색 사각형이 눈에 보일 것이다. 이는 플레이어가 이동할 수 있는 맵의 한계를 표시한 것이다. 포토샵을 사용해 새롭게 만든 맵에서 이 테두리를 따라 나무를 배치하여 이동의 한계선을 표현하였다. 숲을 연상시키는 필드에 어울리게 몬스터 비트맵도 변경했다. 기존 몬스터 비트맵과 달리 새로운 몬스터 비트맵의 배경색은 초록색이다. 배경색을 초록색으로 설정한 이유는, 비트맵의 배경을 생략시키고, 몬스터만 나오게 하기 위해서이다. window.h 헤더 파일에는 비트맵을 표현하는 함수가 있는데, 그 중에서 특정 색상을 생략시키는 함수가 있다. 비트맵의 배경색을 자주 쓰이지 않는 색으로 설정하고 그 색을 생략시키면, 몬스터만 그리게 할 수 있다. 해당 함수의 ..
로그라이크 게임 구현 - Context based steering algorithm을 활용한 움직임 구현 https://kidscancode.org/godot_recipes/ai/context_map/ 이번 알고리즘을 구현하는데 40시간 이상은 걸린거같다. Context based steering algorithm은 장애물을 피하게끔 이동하는 탐색 기법이다. 위 알고리즘을 한국어로 번역하면 "배열에 기반한 움직임 알고리즘"이다. 알고리즘의 이름처럼 움직임을 배열로 선언하고, 장애물을 피하게끔 코드를 짜면 된다. 그러나 해당 알고리즘은 전문적인 게임 툴을 사용하고 있다는 전제 하에 작성된 알고리즘이였다. 때문에 이를 게임 개발 툴이 아닌 WinAPI에 적용 시키는 것은 꽤 힘들었다. context-based steering algorithm을 활용한 몬스터 움직임 먼저 위 알고리즘에 대해 설명하겠다. 가장 먼..
로그라이크 게임 구현 2주차 (2) 1. 몬스터 생성 구현 2주차에선 몬스터를 생성하고 몬스터의 움직임을 구현했다. 그리고 난수 생성기에 들어갈 난수 시드값은 randomdevice로 선언했다. 이것은 프로그램이 실행될 때 하드웨어의 상태에 따라 다른 시드값이 발생한다. 단 이 선언 자체가 작업량이 매우 큰 편이므로 static 선언으로 프로그램 실행 중 한번만 선언하게끔 했다. 이 시드값을 바탕으로 난수 생성기를 돌려야했다. 이 프로젝트를 진행하기 전 나는 시간(currentTime)을 시드값으로 사용하는 rand함수를 사용했다. 그러나 자료 조사를 하면서, rand함수는 한계가 명확하단걸 알았다. 그러다 찾은 대안의 랜덤 함수가 메르센 트위스터라는 난수 생성기이다. 기존의 rand 함수는 난수의 반복주기가 약 2^32로 짧다는 단점을 ..
로그라이크 게임 구현 2주차 (1) 이번 글에선 이중 연결리스트로 몬스터를 구현한 것에대해 적겠다. struct strMonster { strMonster* next; strMonster* prev; short int monsterCount; // 몬스터 식별 번호 short int monsterCategory; //몬스터 종류 번호 (무슨 비트맵을 사용하는가 , 어떤 움직임을 보이는가) POINT monsterPos; // 몬스터 좌표 }; strMonster* strMonsterList = NULL; strMonster* strMonsterInit(strMonster* tmp) { tmp = new strMonster; tmp->prev = NULL; tmp->next = NULL; tmp-> monsterCount = 0; tmp->..
로그라이크 게임 구현 1주차 (5) 이번 글에선 캐릭터를 뱀파이어 서바이버처럼 움직이게 하는 코드를 설명하겠다. 결론부터 말하면 뱀파이어 서바이버는 캐릭터가 움직이지 않는다. 캐릭터는 항상 중앙에 고정되어있다. 그렇다면 왜 나는 움직인다고 느낀걸까? 답은 간단하다. 캐릭터가 움직인게 아니라 배경과 몬스터들이 움직였기 때문이다. 마치 속도의 상대성처럼 캐릭터를 오른쪽으로 이동하라 명령하면 배경과 몬스터들이 왼쪽으로 이동한다. 즉 캐릭터의 좌표를 건드는게 아니라, 비트맵을 움직이게 하면 된다. 앞선 글에서 움직임을 구현하는 코드를 작성했다. 이 코드에서 움직일 좌표를 계산했는데 이 좌표들을 이용해서 배경을 움직이게한다. void CharacterMoveFun() { POINT newPoint; if (keyLayout[VK_LEFT] == k..
로그라이크 게임 구현 1주차(4) 이번 글에선 부드러운 움직임 구현에 관해 적겠다. https://pang2h.tistory.com/375 Win32 - 키보드 입력으로 사각형 움직이기 키보드 입력으로 사각형을 움직여봅니다. # Win32 프로그래밍을 이해하고 있어야합니다. # 알지 못하는 경우 여기에서부터 시작할 것을 권장합니다. # 본 문서는 Direct2D 기반으로 구현합니다. Win3 pang2h.tistory.com 내가 MFC수업을 들을 땐 키보드 처리를 '키보드 다운 윈도우 메세지' (WM_KEYDOWN)에서 처리하게끔 구현했다 그런데 이러한 방법으로 처리하면 부드럽게 움직이지 않는다. 1.........111111111111111 지금 한번 시도해보자. 1을 꾹 누르면 1이 따따따딱 바로 찍히는게 아니라 처음 누르고 얼마 ..
로그라이크 게임 구현 1주차 (3) 이번 글에선 더블 버퍼링에 대해서 작성하겠다. 게임의 기본은 버퍼링이다. 아무리 재밌는 게임이라도, 프레임이 작동을 하지 않는다면, 플레이어는 아무것도 하지 못한다. Win32에선 프레임을 생각보다 쉽게 구현이 가능하다. 바로 Invalidate()함수를 이용하는 것이다. 그런데 나는 Invalidate()함수만을 이용해서 프레임을 구현하다가, 얼마지나지 않아 문제를 직면했다. Invalidate()함수는 클라이언트 영역의 전체 또는 일부를 잘못된 것으로 표시한다. 이렇게 적으면 너무 어려워 보이지만, 쉽게 말하면 클라이언트 영역을 초기화하고, 다시 그리게 하는 함수이다. 게임을 진행하면서 장면이 전환 되었다면, 우리는 Invalidate()함수를 호출해서 새로 그려주어야한다. 그런데 이 그려주는 방식이..