로그라이크 게임 구현 (4 - 2) 스킬 및 몬스터와의 상호작용 구현
캐릭터와 몬스터와의 충돌을 구현하였다.
충돌 판정을 구현하는 것 자체는 비트맵끼리 충돌을 감지해 bool값을 반환하는 IntersectRect를 활용하면 간단했다.
그러나 충돌 판정을 약 30프레임 즉 32ms마다 감지한다면
몬스터와 스치기만해도, 순식간에 CharacterLife가 줄어들 것이다.
때문에 충돌판정을 구현할 때 가장 신경써야 할 점은 캐릭터의 무적시간을 구현하는 것이다.
먼저 character 구조체에 characterInvincibleTime이라는 DWORD 자료형(unsigned long) 변수를 선언한다.
그리고 버퍼링을 구현한 메인 함수에서 선언된 시간을 저장하는 dwTime변수를 참조하는 포인터를 선언한다.
그리고 포인터 변수 활용해 CheckCharacterDamaged 함수에서 몬스터와 충돌했을 때 시간을 characterInvincibleTime에 삽입한다.
마지막으로 캐릭터가 충돌한 시간이 일정시간(100ms) 지나지 않았다면 Life를 깍지 않고, 해당 함수를 리턴한다.
그 다음으로 스킬을 구현하였다.
스킬은 일정 방향으로 움직이고, 그래픽을 필요로하고, 스킬의 특성을 저장해야한다는 점에서
몬스터 구조체와 비슷한 특성을 가진다.
때문에 몬스터와 마찬가지로 스킬의 구조체와 리스트를 선언한다.
스킬의 구조체를 선언했다면, 스킬이 발사될 시간 (공격속도라 생각하면 편하다.) 을 구현해야한다.
프레임이 바뀔때마다 1씩 증가하는 토글 변수를 선언한다. (즉 이 토글변수가 1 증가할 때마다 32ms가 지난 것이다.)
이 토글 변수를 내가 원하는 시간만큼 나머지 연산을 하여 나머지가 0이 될 때 스킬을 발사시킨다.
첫번째로 구현한 스킬은 토글을 30으로 나머지연산을 하여 약 1초마다 나가게끔 구현했다.
Vampire Survivors 게임에서는 스킬이 자동으로 발사된다.
때문에 스킬이 나가는 방향은 플레이어가 정할 수 없으며, 무작위 방향으로 나아간다.
그러나 최소한 공격이라면, 몬스터들을 향해 발사돼야하지 않을까?
밀집된 몬스터들을 향해 조준이 된다면 좋겠지만, 나는 스킬을 일부러 불친절하게 조준하게끔 구현했다.
너무 잘 조준하면 몬스터들이 쉽게 죽어 게임의 난이도가 쉬워질테니 말이다.
참고로 setSkillDirection 함수는 strSkillInsert 함수에 포함 되어있다. 스킬을 만들 때 방향이 정해져야할테니.
스킬에 맞으면 몬스터는 죽어야한다. 앞서 스킬 구조체에서 스킬의 데미지를 선언하였다.
몬스터와 스킬이 충돌하면 해당 몬스터 구조체의 hp는 스킬의 데미지만큼 감소하고 몬스터 hp가 0이 되면
해당 몬스터 노드를 삭제한다.... 인데
사실 몬스터와 스킬 충돌의 구현이 가장 어려웠다.
몬스터 또한 캐릭터와 마찬가지로 무적시간이 있어야하기 떄문이다.
몬스터의 무적시간은 한번 맞은 공격에는 두번 맞으면 안되게 구현하면 된다.
그러나 생각보다 케이스가 많아서 분기점이 많이 나뉘고, 그에 따라 코드가 길어졌다.
분기점을 간단히 나누면 아래와 같다.
먼저 스킬 구조체에는 해당 스킬의 번호가 있다.
1. 만약 몬스터가 스킬을 처음 맞는다면 (큐가 비었다면) 몬스터 구조체에 선언된 short int 자료형 큐(damagedSkillCount)에 해당 스킬의 번호가 들어간다.
2. 몬스터가 스킬을 맞았을 때 damagedSkillCount 큐가 비어있지 않다면 해당 큐를 하나씩 팝하여 맞은 스킬의 번호와 비교한다. 만약 해당 스킬의 번호가 없다면 (그 스킬을 처음 맞았다면)damagedSkillCount 큐에 해당 스킬의 번호를 집어넣는다.
2-1. 큐가 비어있지않고, 해당 스킬 번호가 그 큐에 있다면 몬스터는 공격에 맞지 않으며, bpass 부울 값을 1로 변경한다.
3. 앞의 분기점에서 모두 적용되지 않는다면 bpass 부울값은 항상 1이다. 이는 한번 맞은 스킬에 대해서 더이상 검사하지 않는다는 의미이다. 해당 몬스터 구조체와 스킬의 충돌 검사를 중지한다. 그리고 bpass 부울값을 0으로 바꾸어 다음 검사 때 다시 1번 혹은 2번 분기점으로 넘어가게 한다.
해당 분기점을 모두 지나면, 2번 큐에서 팝하였던 큐를 다시 돌려준다.
마지막으로 스킬의 데미지를 표시하였다.
해당 게임에서는 스킬에 맞으면 그 스킬의 데미지가 표시된다.
이 스킬의 데미지는 이후의 코딩에서 레벨업 등을 활용하여 데미지가 늘어나는게, 눈에 보여야하기 떄문에 필수이다.
구현 자체는 어렵지 않았다.
몬스터가 데미지를 받았다는 판정을 받으면, 그 죄표에 수치를 뿌려준다.
그 수치는 일정 시간 (dwTime 활용)이 지나면, 스스로 사라진다.