창작에 관련된 질문이나 간단한 팁, 예제를 올리는 곳
11편 : 적의 사망판정
일단 대미지를 입었을 때 처리를 바꿔 봅시다.
워프 하듯이 뒤로 날아가는 것은 아닌 듯 싶으니 말입니다.
일단 대미지를 입었을 때의 상태 하나를 추가합니다.
#define STATE_PAIN 5
대미지를 입었을 때는 아무 것도 못하게 컨트롤도 막습니다.
void Unit::Control()
{
if(state==STATE_PUNCH || state==STATE_KICK || state==STATE_PAIN)return;
......
이제 Action 부분에서 새로운 상태를 추가해 줍니다.
상태에 따라 그림을 바꿔야 할 테니 허접하게 고친 제가 그린 그림을 일단 쓰겠습니다.
그림 잘 그리신 분들은 자연스럽게 고쳐 보시고
(밑에 첨부에서 다운 받으십시오.)
일단 이것을 받고 작업 폴더에 넣으신 후,
그림 불러 오는 곳에서 이것을 추가합니다.
jdd->LoadPicture("고통", "pain.gif", &jpi, true);
그럼 이번엔 Action에서 새로운 동작에 대한 처리를 추가합시다.
//대미지
else if(state==STATE_PAIN)
{
if(aim == AIM_LEFT)jdd->DrawPicture(backbuffer, "고통", x, y-2, NULL);
else jdd->DrawPictureEx(backbuffer, "고통", x, y-2, NULL, DPX_HFLIP);
++delay;
if(delay >= 20)state=STATE_NORMAL;
attack.left = -999;
}
대미지를 입은 상태에서는 '고통' 그림을 보여주면서
delay가 20까지 되면 다시 원래 상태로 돌아갑니다.
즉, 0.2초간 고통스러워 하다가 원래대로 돌아가는 겁니다.
이제 마지막으로 Damage 부분을 바꿉니다.
이전 것은 다 지워 버리고...
void Unit::Damage(bool hit_aim)
{
state = STATE_PAIN;
}
이렇게 상태 변화만 넣어주고 실행시켜 보면...
아니? 이게 왠 일! 적이 맞아도 전혀 반응을 하지 않습니다.
어디가 잘못 된 걸까요?
그건 Control만 고치고 AI는 고치지 않았기 때문입니다.
AI에도 고통 상태에서는 아무것도 못 하게 고쳐줍시다.
void Unit::AI(int hero_x, int hero_y)
{
if(state==STATE_PAIN)return;
......
AI와 주인공 캐릭터의 공통되는 사항은 나중에 하나로 묶어서 따로 분리해야 할 듯 싶습니다.
아무튼 여기까지 했다면 맞을 때마다 얼굴 색이 변하는 적을 볼 수 있습니다.
이젠 불사인 적이 지겨우니 죽도록 해봅시다.
Unit 클래스에 hp를 추가합니다.
class Unit
{
private:
......
int hp; //체력
public:
......
}
그리고 생성할 때 초기값은 8.
Unit::Unit(int x, int y, int speed)
{
......
hp = 8;
}
그리고 맞을 때마다 1씩 깎입니다.
void Unit::Damage(bool hit_aim)
{
state = STATE_PAIN;
--hp;
}
hp를 알아낼 수 있는 GetHP도 추가합니다.
이건 알아서 하세요.
마지막으로 hp가 없을 때는 아무것도 처리하지 않게
메인 루프를 바꿉니다.
while(!GetKey(vkey_esc))
{
if(!ProcessMessage())break;
jdd->DrawPicture(backbuffer, "배경", 0, 0, NULL);
hero.Control();
if(enemy.GetHP()>0)enemy.AI(hero.GetX(), hero.GetY());
hero.Action();
if(enemy.GetHP()>0)enemy.Action();
//충돌 검사
if(enemy.GetHP()>0)
{
RECT attack = hero.GetAttackRect();
RECT body = enemy.GetBodyRect();
if(attack.left != -999) //공격영역이 존재할 때
{
if(attack.right >= body.left && attack.left <= body.right && attack.bottom >= body.top && attack.top <= body.bottom)
{
enemy.Damage(hero.GetAim());
}
}
}
jdd->Render();
}
곧 hp가 1이상이 되지 않으면 AI가 작동하지도 않고
움직이지도 보이지도 않는다는 것이죠.
충돌 검사도 하지 않습니다. 즉, 존재하지 않게 되는 겁니다.
한번 실행해 봅시다.
그런데 이상한 증상을 발견할 수 있습니다.
엥? 2대만 때렸는데 사라져 버리네?
분명히 hp가 8이니 8대를 맞고 사라져야 할 텐데 왜 2대에 사라져 버리는 걸까요?
그것은 중복해서 대미지를 입고 있기 때문입니다.
펀치를 내밀고 있는 동안 지속적으로 대미지를 주기 때문에 2대 정도에 적이 죽어버리고 마는 겁니다.
한번의 펀치에 한번만 대미지를 입도록 Damage 부분을 바꿔 봅시다.
void Unit::Damage(bool hit_aim)
{
if(state != STATE_PAIN)
{
state = STATE_PAIN;
--hp;
}
}
이제 대미지 입은 상태에서 또 대미지를 입지 않을 겁니다.
다시 실행해서 테스트 해봅시다. 정확히 8대에... 8대에...
엥? 똑같이 1,2대에 죽습니다.
도대체 뭐가 잘못 된 걸까요? 으아아악!
이런 버그로 이렇게 공황상태에 빠질 수도 있습니다.
그래서 디버깅을 가르쳐 드리고 싶지만 그건 글로 적기엔 힘들 것 같군요.
아무튼 원인은 무엇이냐?
바로 Action 부분에 있습니다.
Action에서는 delay가 20이상 되면 다시 원래 상태로 돌리는데,
바로 이 delay를 대미지 입었을 때 초기화를 안 한게 문제였습니다.
펀치나 킥을 날릴 때는 확실히 초기화하고 있는데 말이죠.
추가합시다.
void Unit::Damage(bool hit_aim)
{
if(state != STATE_PAIN)
{
state = STATE_PAIN;
--hp;
delay=0;
}
}
이렇게 여러 트러블을 겪으면서 고쳐 나가다 보면
드디어 8대에 아름답게 사라지는 적을 볼 수 있습니다.
죽는 애니메이션을 넣고 싶으시면
새로운 STATE_DIE 같은 것을 넣고,
그 상태에서는 조종과 충돌검사가 안 되게 한 뒤
일방적으로 애니메이션을 보여준뒤 사라지게 하면 됩니다.
이건 그래픽 재료도 없고 하니 도전과제로 남기겠습니다.