2012-06-10 39 views
0

我正在C++中使用簡單的2D自頂向下塞爾達風格遊戲,但是我無法獲取敵人類的多個實例來產卵。每當我產生超過一個敵人,只有第一個註冊任何碰撞檢測;所有其他敵人似乎只是呈現在屏幕上的視覺「鬼魂」。當第一個敵人死亡時,唯一可以的,那麼所有其他的「鬼魂」隨之消失。敵人鬼實例/非唯一對象

我已經創建了一個敵人管理員類,它使用向量列表來保存活躍的敵人,檢查每個人對任何傳入的盒子的碰撞,並更新/渲染敵人。

class cEnemyMgr { 
public: 
std::vector<cEnemy*> mobList; 

cEnemyMgr(){} 
~cEnemyMgr(){ 
    for (int i=0; i < mobList.size(); i++) { 
     mobList[i]->texture.Close(); 
      //delete mobList[i]; 
    } 
} 

    void render() { 
     for (int i=0; i < mobList.size(); i++) { 
      mobList[i]->render(); 
     } 
    } 

    void update(float dt){ 
     for (int i=0; i < mobList.size(); i++) { 
      if (mobList[i]->hp <= 0){ 
       mobList[i]->die(); 
       mobList.pop_back(); 
      } else { 
       mobList[i]->update(dt); 
      } 
     } 
    } 

    void spawnMob(int x, int y){ 
     cEnemy* pEnemy = new cMeleeEnemy(); 
     pEnemy->init(x, y); 
     mobList.push_back(pEnemy); 
    } 

    cEnemy* checkCollisions(int x, int y, int wd, int ht){ 
     for (int i=0; i < mobList.size(); i++) { 
      int left1, left2; 
      int right1, right2; 
      int top1, top2; 
      int bottom1, bottom2; 

      left1 = x; 
      right1 = x + wd; 
      top1 = y; 
      bottom1 = y + ht; 

      left2 = mobList[i]->pos.x; 
      right2 = mobList[i]->pos.x + 64; 
      top2 = mobList[i]->pos.y;  
      bottom2 = mobList[i]->pos.y + 64; 

      if (bottom1 < top2) { return NULL; } 
      if (top1 > bottom2) { return NULL; } 
      if (left1 > right2) { return NULL; } 
      if (right1 < left2) { return NULL; } 

      return mobList[i]; 
     } 
    } 
}; 

敵方階級本身很基礎, cEnemy是派生cMeleeEnemy的基類。它具有標準的hp,dmg和運動變量,因此它可以在屏幕上爬行以嘗試與玩家的頭像發生衝突,並對玩家的攻擊作出反應。所有這些工作正常,只是當我嘗試擁有多個敵人時,只有第一個產生了正確的工作,而其餘的都是空殼,只是屏幕上的紋理。如果我在同一個塊中快速地調用spawnMob,或者如果我用一個定時器動態地將它們間隔開,那並不重要;結果是一樣的。任何人都可以將我指向正確的方向嗎?

- 編輯 - 下面的代碼在for enemy.h:

#ifndef ENEMY_H 
#define ENEMY_H 

#include "texture.h" 
#include "timer.h" 

#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0) 

class cEnemy { 
public: 
int hp; 
int dmg; 
D3DXVECTOR2 pos; 
D3DXVECTOR2 fwd; 
D3DXVECTOR2 vel; 
D3DCOLOR color; 
int speed; 
float rotate; 
bool hitStun; 
float hitTime; 
CTexture texture; 

virtual void init(int x, int y) = 0; 
virtual void update(float dt) = 0; 
virtual void die() = 0; 

void render(){ 
    texture.Blit(pos.x, pos.y, color, rotate); 
} 

void takeDamage(int dmg) { 
    if (hitStun == false){ 
     extern CTimer Timer;   
     hitTime = Timer.GetElapsedTime(); 
     hp -= dmg; 
     color = 0xFFFF0000; 
     hitStun = true; 
    } 
} 

void hitStunned(float duration) { 
    extern CTimer Timer; 
    float elapsedTime = Timer.GetElapsedTime(); 
    if (elapsedTime - hitTime > duration){ 
     color = 0xFFFFFFFF; 
     hitStun = false; 
    } 
} 

}; 

class cPlayer : public cEnemy { 
public: 
int facing; 

void init(int x, int y); 
void update(float dt); 
void die(); 

}; 

class cMeleeEnemy : public cEnemy { 
public: 
cMeleeEnemy(){} 
~cMeleeEnemy(){ 
    texture.Close(); 
} 

void init(int x, int y); 
void update(float dt); 
void die(); 

}; 
#endif 

而且enemy.cpp:

#include "enemy.h" 

void cPlayer::update(float dt){ 
// Player Controls 
if (KEY_DOWN('W')) { 
    pos.y -= speed * dt; 
    facing = 0; 
} else if(KEY_DOWN('S')) { 
    pos.y += speed * dt; 
    facing = 2; 
} 

if (KEY_DOWN('A')) { 
    pos.x -= speed * dt; 
    facing = 3; 
} else if(KEY_DOWN('D')) { 
    pos.x += speed * dt; 
    facing = 1; 
} 

// Hit Recovery 
if (hitStun == true) {  
    hitStunned(1.0); 
} 
} 

void cMeleeEnemy::update(float dt){ 
extern cPlayer player1; 
extern int ScreenWd; 
extern int ScreenHt; 

D3DXVECTOR2 dir; 
dir = player1.pos - pos; 
D3DXVec2Normalize(&dir, &dir); 
//fwd = (fwd * 0.2) + (dir * 0.8); 
fwd = dir; 
vel = vel + fwd * speed * dt; 

pos = pos + vel * dt; 

//keep em on screen 
if (pos.x < 0) { pos.x = 0; } 
if (pos.x > ScreenWd - 64) { pos.x = ScreenWd - 64; } 
if (pos.y < 0) { pos.y = 0; } 
if (pos.y > ScreenHt - 64) { pos.y = ScreenHt - 64; } 

// Hit Recovery 
if (hitStun == true) {  
    hitStunned(0.5); 
} 

} 

void cMeleeEnemy::die(){ 
extern int score; 
extern int numMobs; 
score += 1; 
numMobs -= 1; 
//texture.Close(); 
} 

void cPlayer::die(){ 
extern char gameState[256]; 
sprintf(gameState, "GAMEOVER"); 
} 

void cMeleeEnemy::init(int x, int y){ 
hp = 6; 
dmg = 1; 
speed = 25; 
fwd.x = 1; 
fwd.y = 1; 
vel.x = 0; 
vel.y = 0; 
pos.x = x; 
pos.y = y; 
rotate = 0.0; 
color = 0xFFFFFFFF; 
hitStun = false; 
texture.Init("media/vader.bmp"); 
} 

void cPlayer::init(int x, int y){ 
facing = 0; 
hp = 10; 
dmg = 2; 
color = 0xFFFFFFFF; 
speed = 100; 
fwd.x = 1; 
fwd.y = 1; 
vel.x = 0; 
vel.y = 0; 
pos.x = x; 
pos.y = y; 
rotate = 0.0; 
hitStun = false; 
texture.Init("media/ben.bmp"); 
} 

正如你所知道的,我沒那麼經歷尚。這是我第一次爲學校開設自己的項目。我只是不得不說,我有點困惑,我應該關閉紋理和刪除對象。謝謝你的時間,夥計!

+0

我們需要查看敵人對象的代碼。另外,除非'die'導致物體自身破壞,否則你似乎正在泄漏內存。 – tmpearce

+0

請發佈代碼類checkCollisions() –

+0

你說得對,我沒有銷燬每個實例後,它是作出。 Die()只是簡單地改變當前相關的分數點和暴民閾值變量。我是否通過在if語句中使用類似delete delete mobList [i]的方法來執行此操作,其中hp <= 0? – DanTheMan

回答

2

在您的checkCollisions函數中,您返回NULL或每個循環後敵方向量第一個索引位置的對象。

因此,當第一次重影未被擊中時,checkCollisions函數將返回NULL而不是遍歷向量中的每個後續重影。

爲了解決這個問題,改變你的checkCollisions功能如下:

cEnemy* checkCollisions(int x, int y, int wd, int ht){ 
    for (int i=0; i < mobList.size(); i++) { 
     int left1, left2; 
     int right1, right2; 
     int top1, top2; 
     int bottom1, bottom2; 

     left1 = x; 
     right1 = x + wd; 
     top1 = y; 
     bottom1 = y + ht; 

     left2 = mobList[i]->pos.x; 
     right2 = mobList[i]->pos.x + 64; 
     top2 = mobList[i]->pos.y;  
     bottom2 = mobList[i]->pos.y + 64; 

     if (bottom1 < top2) { continue; } 
     if (top1 > bottom2) { continue; } 
     if (left1 > right2) { continue; } 
     if (right1 < left2) { continue; } 

     return mobList[i]; 
    } 

    return NULL; 
} 

希望這有助於!

編輯:

需要注意的是,如果它是HP爲0或更小,使用的是mobList.pop_back(),當你從列表中刪除的敵人,但這刪除Vector中最後一個元素,你應該使用類似的下面從列表中移除你想要的敵人:

std::remove_if(mobList.begin(), mobList.end() [](cEnemy* pEnemy)->bool 
{ 
    if(pEnemy->hp <= 0) 
    { 
     pEnemy->die(); 
     return true; 
    } 
    else 
    { 
     pEnemy->update(); 
     return false; 
    } 
}); 
+0

他可能正在調用CheckCollisions,刪除相關的ghost,然後再次調用它。這可能只能部分解決問題。但很好。 –

+0

這已經部分解決了問題!我可以擊中並擊中所有的實例,但它看起來像是一個被破壞的敵人,它也會將所有後面創建的敵人都帶走。 – DanTheMan

+0

@DanTheMan我們需要查看您的通話代碼才能進一步提高幫助。 –

0

問題解決了!我用mobList.erase()方法替換了pop_back()

void update(float dt){ 
     for (int i=0; i < mobList.size(); i++) { 
      if (mobList[i]->hp <= 0){ 
       mobList[i]->die(); 
       mobList.erase(mobList.begin() + i); 
      } else { 
       mobList[i]->update(dt); 
      } 
     } 
    } 

謝謝大家的幫助,非常感謝!