2012-06-10 41 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); 
      } 
     } 
    } 

谢谢大家的帮助,非常感谢!