티스토리 뷰

Project

#008 : Unlight Copycat [DAY #09]

BaeMinCheon 2018. 3. 2. 19:45

Project Note #008


Unlight Copycat DAY #09

개요

  • Window API의 일종인 pclaf를 활용해 게임을 만드는 과정을 정리합니다.
  • 참고
    ※ https://github.com/BaeMinCheon/unlight-copycat (Github, "v0.7.0" 태그)

환경

  • Visual Studio 2015 Professional
  • Windows 10 Home
  • pclaf (C/C++)


이전 글에 작성해야할 내용이었는데, 깜빡하고 누락하여 오늘 올립니다. Unlight 캐릭터 카드를 비트맵 리소스로 적용하는 과정에 대한 내용입니다. 기존 Quest 시퀀스에서의 덱 출력은 임시로 만든 비트맵 리소스인 카드 뒷면을 사용했습니다. 이를 Unlight캐릭터 카드로 교체하기 위해 우선 에바리스트, 아이자크, 그룬왈드 카드들을 비트맵 리소스로 추가합니다.


그리고 추가된 캐릭터 카드를 사용하기 위해 userInfo.txt 파일도 수정합니다(이전에 언급했던 것처럼, ID값은 기존 Unlight와 동일하게 적용했음). 프로그램을 실행해 확인해보면 아래와 같이 비트맵 리소스가 손실되어 출력됨을 볼 수 있습니다. 기존 비트맵 리소스는 색상이 듬성듬성한 배치였기 때문에, 축소 과정을 거쳐도 이미지 손실이 거의 없었지만 이번 비트맵 리소스는 거의 빈틈없이 색상이 배치되었기 때문에 이와 같은 문제가 발생합니다.



이전에 만들었던 float 매개변수를 추가한 drawBitmap() 내부에서 StretchBlt() 이전에 SetStretchBltMode(hdc, COLORONCOLOR);를 작성해줍시다. COLORONCOLOR로 StretchBlt() 모드를 지정해주면, 축소 과정에서 겹치는 픽셀을 제거하여 방금과 같은 현상이 일어나는 것을 막아줍니다. 이를 적용한 뒤 실행해보면 아래와 같은 출력을 볼 수 있습니다.





저번 코드에서 맵블럭의 배경을 메뉴버튼으로 추가했었는데, 이를 Map 클래스의 정적 멤버변수로 변경하겠습니다(코드를 정리하기 위함입니다). 이로써 Map::infoDraw()와 Map::infoClick() 그리고 MapBlock::blockIn()과 MapBlock::blockOut()을 변경하게 되었습니다. 또한 Quest 시퀀스 내에서 해당 함수들을 사용하는 곳을 수정해줍니다.


메뉴버튼 중 시작버튼을 구현해봅니다. 시작버튼을 눌렀을 경우 포기버튼 또는 맵블럭만 클릭할 수 있도록 조정해야합니다. 이를 위해 미리 정의했던 mapInProcess의 값을 변경하는 코드를 작성합니다(mapInProcess = true;). 그리고 시작/삭제버튼을 화면 밖으로 보냅니다(Map::menuOut();).


포기버튼을 화면 안으로 가져옵니다(moveTo(10, 170)). 그리고 SD캐릭터를 첫번째 맵블럭에 등장시켜야 하겠죠. 지금은 빨간 사각형으로 대신하겠습니다. 그리고 몇번째 맵블럭인지 위치를 저장하기 위해 Map 클래스 내에 static int position;을 선언합니다. Quest.cpp에서 positon의 초기값을 -1로 정의합시다. 아직 맵을 시작하지 않았음을 의미합니다.


그리고 시작버튼의 람다표현식을 마저 작성합니다. Map::position = 0;으로 첫번째 맵블럭부터 시작하도록 합시다. 그럼 이로써 시작버튼의 역할은 끝입니다. Map::infoDraw()에서 positon이 0 이상일 때 빨간색 사각형을 맵블럭 위치에 그리도록 합시다. 실행해보면 다음과 같이 맵블럭 위에 그려지는 것을 확인할 수 있습니다.



포기버튼을 구현해봅시다. mapInProcess = false;로 맵을 진행하던 상태에서 빠져나오고 moveTo(-800, 0)로 포기버튼을 화면 밖으로 보냅니다. 포기버튼은 삭제버튼의 기능을 포함합니다. 따라서, 삭제버튼의 doWork()를 호출한 뒤, Map::positon = -1;로 다음 맵을 진행하기 위한 환경를 마련하면 완성이군요. 시작버튼을 더블클릭하고 포기버튼을 더블클릭하면, 삭제버튼을 더블클릭했을 때와 같은 결과를 얻게 됩니다(맵목록이 하나 줄어드는 결과).


맵 진행 중 불필요한 마우스 입력을 받지않도록 Quest::leftClick()에서 마우스 입력처리에 대한 코드를 mapInProcess로 분기합니다(if(!mapInProcess)). 다음 맵블럭이 클릭되면, Map::position의 값을 +1 하는 코드를 작성합니다. Map::positon의 값이 범위를 벗어나지않도록 if문으로 검사도 해줍니다.


if문 내에서는 mapInProcess = false;로 맵을 진행하던 상태에서 빠져나오고, 포기버튼의 doWork()를 호출해 진행완료한 맵을 삭제합니다. 실행해보면, 다음 맵블럭을 누를 때마다 빨간 사각형이 움직이고 마지막 맵블럭에 다다르면 맵이 삭제됨을 알 수 있습니다. 하지만, 기존 Unlight는 모든 맵블럭을 클리어했을 때 별도의 출력을 해줬었습니다.


이 별도의 출력을 위해 Quest::leftClick()의 다음 맵블럭의 클릭을 검출하는 코드를 수정합니다. Map::positon의 값이 맵의 길이와 동일할 때를 검사하는 if문을 밖으로 빼내 먼저 검사하도록 합니다. 그리고 기존 if문(다음 맵블럭 클릭 검출)을 else if()로 연결합시다. 이렇게 수정하면 빨간색 사각형이 마지막 맵블럭에 도달한 뒤, 한 번 더 클릭을 해줘야 맵이 사라지게 됩니다. 즉, 이 한 번의 클릭에 별도의 출력을 처리하면 되겠군요.


맵 클리어를 알려주는 문구가 적혀있고, OK버튼이 달린 사각형을 만들어야하므로 RectButton을 상속받아 OKBox를 만듭시다. Button.h에 OKBox 클래스를 선언하고 Button.cpp에서 구현합니다. 생성자는 부모의 것과 거의 동일하지만, OK버튼 역할을 수행할 멤버변수 RectButton ok를 초기화하는 코드가 추가됩니다. isClick()의 경우 ok의 isClick()만 호출하고, draw()와 moveTo()의 경우 본체와 ok 둘 다 처리해줍니다.


이렇게 만든 OKBox 클래스는 Map 클래스 내에 정적 멤버변수로 선언합니다(static OKBox clear;).이제 다시 Quest::leftClick()으로 돌아와서, Map::positon이 맵길이와 동일한지 검사하는 if문에서 포기버튼을 화면 밖으로 내보내고 클리어버튼을 화면 안으로 가져옵니다. 그리고 클리어버튼이 눌렸는지(클리어문구의 OK버튼) 검사하고, 그렇다면 이전에 작성했던 코드(mapInProcess = false; ...)를 실행하도록 한 뒤 클리어버튼을 다시 화면 밖으로 보냅니다.


실제로 실행해보면 아래의 영상과 같은 결과를 볼 수 있습니다. 오늘은 여기까지 작업하도록 하겠습니다. 이 다음으로는 맵블럭의 정보를 토대로 Battle 시퀀스를 초기화한 뒤, 시퀀스를 전환하는 과정을 진행하겠습니다.



추가

  • 본 깃헙 레포지터리의 README.markdown에 작성된 Sequence Summary는 매번 업데이트할 예정이므로 참고하기 바랍니다.


'Project' 카테고리의 다른 글

#010 : Speedrun Gunner  (0) 2018.06.22
#009 : Unlight Copycat [DAY #18]  (0) 2018.03.11
#007 : Unlight Copycat [DAY #08]  (0) 2018.03.01
#006 : Unlight Copycat [DAY #05]  (0) 2018.02.26
#005 : Unlight Copycat [DAY #04]  (0) 2018.02.25
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함