【问题标题】:Crash, on Console Application, trying to draw enemies, out of bounds (following vid tutorial)崩溃,在控制台应用程序上,试图绘制敌人,越界(遵循 vid 教程)
【发布时间】:2011-06-20 03:48:49
【问题描述】:

{希望改进了我的帖子,请仍然建议您需要的任何其他代码,再次抱歉我如此无能,但我决心克服这个问题,所以我真的很感谢你的时间! !}

**编辑:感谢弗兰克在下面的回复,程序现在启动并绘制了三个敌人,但仅仅几秒钟后就崩溃了,因此下面的程序代码仍然适用,因为它基本上是移动循环和某处还是有问题。

我意识到这非常晦涩难懂,我已尽力解释它,但如果没有人可以建议,那么它的几秒钟应该足以完成教程,并且在完成后对整个项目进行剖析并真正尝试并将其分解并尽可能多地学习。**

好的,所以我运行这个旨在创建新敌人的循环,然后将它们绘制到屏幕上,它现在可以工作,但在几秒钟后崩溃。下面是调试所经历的步骤以及最后的调用堆栈(如果它在崩溃后显示的话)。希望你能帮忙!

这是我正在关注的视频教程,我卡住了,找不到答案。一遍又一遍地检查代码。 (完整的代码在帖子的底部(代码块),但我试图在这篇文章中包含尽可能多的信息)

功能是:
level->addEnemies(3);

在主game.cpp中看起来像:

    bool Game::run(void)
    {
        level = new Level(&drawArea, 30, 20);

        drawArea.createBackgroundTile(TILE_EMPTY, ' ');
        drawArea.createBackgroundTile(TILE_WALL, 219);

        drawArea.createSprite(SPRITE_PLAYER, 1);
        drawArea.createSprite(SPRITE_ENEMY, '$');

        player = new Character(level, &drawArea, 0);

        level->draw();
        level->addPlayer(player);
        level->addEnemies(3);        <-------- SKIPS TO THIS FUNC

        char key = ' ';

        startTime = timeGetTime();
        frameCount = 0;
        lastTime = 0;

        posx = 0;

        player->move(0,0);

        while (key != 'q')
        {
            while (!getInput(&key))
            {
               timerUpdate();
            }
            level->keyPress(key);
        }
        delete player;

        return true;
    }

完整的功能如下,请注意,当我从主游戏循环中删除此 addEnemies 功能时,一切运行正常,没有崩溃,因此它与即将推出的功能有关。

    void Level::addEnemies(int num)
    {
        int i = num;

        while (i > 0)
    {
        int xpos = int(float(rand() % 100) / 100) * (width - 2) + 1;
        int ypos = int(float(rand() % 100) / 100) * (height - 2) + 1;

        if (level[xpos][ypos] != TILE_WALL)
        {
            Enemy *temp = new Enemy(this, drawArea, SPRITE_ENEMY, 
                           (float)xpos, float(ypos));

            temp->addGoal(player);

            addNPC((Sprite *)temp);

            i--;
            }
        }
    }

它通过这个函数似乎没有任何问题。

此函数返回游戏循环并正常执行后,进入计时器更新没有任何问题。下面是 timerUpdate 函数:

    void Game::timerUpdate(void)
    {

        double currentTime = timeGetTime() - lastTime;

         if (currentTime < GAME_SPEED)
            return;

        level->update();                   <--------SKIPS TO THIS FUNC

        frameCount++;


        lastTime = timeGetTime();
    }

这是 Level->Update() 函数:

    void Level::update(void)
    {
    for (Iter = npc.begin(); Iter != npc.end(); Iter++)
        {
            (*Iter)->idleUpdate();      <-------------SKIPS TO THIS FUNC

            if ((*Iter)->isAlive() == false)
            {
                Sprite *temp = *Iter;
                //kill the enemy
                Iter--;
                delete temp;
                npc.remove(temp);
            }
        }
    }

idleUpdate():

    void Enemy::idleUpdate(void)
    {
        if (goal)
            simulateAI();    <------ Goes to this func
    }

模拟AI():

    void Enemy::simulateAI(void)
    {
        vector goal_pos = goal->getPosition();
        vector direction;

        direction.x = goal_pos.x - pos.x;
        direction.y = goal_pos.y - pos.y;

        float mag = sqrt(direction.x * direction.x + direction.y * direction.y);

        direction.x = direction.x / (mag);
        direction.y = direction.y / (mag);

        if (!move(direction.x, direction.y))   <------ SKIPS TO THIS FUNC
        {
            while (!move(rand() % 3 - 1, rand() % 3 - 1))
            {

            }
        }

移动功能:

    bool Sprite::move(float x, float y)
    {

        int xpos = (int)(pos.x +x);
        int ypos = (int)(pos.y +y);

        if (isValidLevelMove(xpos,ypos))      SKIPS TO THIS FUNC
        {
            //.....rest not needed

isValidMove 函数:

    bool Sprite::isValidLevelMove(int xpos, int ypos)
    {
        if (level->level[xpos][ypos] != TILE_WALL)  <-------------THIS LINE CRASHES!!
            return true;

        return false;
    }

我真的不知道哪里出了问题,以及为什么最后调用 stakc 显示 xpos 和 ypos 的超出范围数字如此之高。

这是完整的调用堆栈:

    #0 00402920 Sprite::isValidLevelMove (this=0x791498, xpos=-2147483648, ypos=-2147483648) (sprite.cpp:95)
    #1 00000000 0x00401750 in Enemy::move (this=0x791498, x=-nan(0x400000) (enemy.cpp:21)
    #2 00401892 Enemy::simulateAI (this=0x791498) (enemy.cpp:67)
    #3 004017E5 Enemy::idleUpdate (this=0x791498) (enemy.cpp:46)
    #4 0040226E Level::update (this=0x792e90) (level.cpp:86)
    #5 00401CB8 Game::timerUpdate (this=0x28fec0) (game.cpp:93)
    #6 00401BB5 Game::run (this=0x28fec0) (game.cpp:54)
    #7 0040258D main() (main.cpp:11)

这基本上告诉我 xpos 和 ypos 已经在这个过程中的某个地方被肢解了,这肯定会导致崩溃,因为它超出了绘图引擎宽度和高度的 [30][20] int 数组的范围。

另一个编辑:

这里是 Sprite 类,如果有帮助,如果需要,将编辑更多。

    enum
    {
        SPRITE_CLASSID,
        CHARACTER_CLASSID,
        ENEMY_CLASSID
    };

    struct vector
    {
        float x;
        float y;
    };

    class Sprite
    {
    public:
        Sprite(Level *l, DrawEngine *de, int s_index, float x = 1, float y = 1, int i_lives = 1);
        ~Sprite();

        vector getPosition(void);
        float getX(void);
        float getY(void);

        virtual void addLives(int num = 1);
        int getLives(void);
        bool isAlive(void);

        virtual void idleUpdate(void);

        virtual bool move(float x, float y);

    protected:
        Level *level;
        DrawEngine *drawArea;

        vector pos;

        int spriteIndex;
        int numLives;

        int classID;

        vector facingDirection;

        void draw(float x, float y);
        void erase(float x, float y);

        bool isValidLevelMove(int xpos, int ypos);

    };

无论如何,任何帮助,我都会非常感激,我知道我一定看起来完全没用,但我真的决心学习,你们提供的任何帮助都是无价的!!!!

完整的代码文件(代码块):http://www.mediafire.com/?5xz2seadmagbetb

【问题讨论】:

  • 你真的想要 gamedev.stackexchange.com。
  • 您应该检查(并向其他人展示)整个调用堆栈,而不仅仅是一行;以及可疑堆栈帧中的所有变量,而不仅仅是函数参数;对于指针,它们指向的东西,而不仅仅是指针本身。
  • 这不会显示实际调用isValidLevelMove 的代码。 xposyposaddEnemies 的局部变量。请发布timerUpdate中调用的代码
  • 将在几分钟内编辑并添加这些详细信息,感谢您的建议。
  • 大量编辑,似乎代码块中的调试器正在传递函数(即使我一次只想走一步)完整的函数路径现在在那里,如果你想要请告诉我别的什么。

标签: c++ bounds crash


【解决方案1】:

这可能不是实际问题,但可能是相关的。在Level::addEnemies(int num) 函数中创建随机位置的代码将始终为xposypos 返回1

这是因为您应用强制转换的方式。您似乎错过了 int 的最终演员阵容的括号。我想你想要这样的东西:

int xpos = int((float(rand() % 100) / 100) * (width - 2)) + 1;

更新:

导致崩溃的代码位于您的simulateAI() 函数中。与:

float mag = sqrt(direction.x * direction.x + direction.y * direction.y);

你计算两点之间的距离,但如果两点坐标相同,则距离为0

稍后使用:direction.x = direction.x / (mag);,您将除此潜在的0,因此您的坐标将包含NaN。在您的bool Sprite::move(float x, float y) 函数中,您将这些NaNs 转换为int,这将为您提供一些未定义的数字。使用这个数字,您试图访问您的数组,这将导致访问冲突,从而使您的程序崩溃。

所以首先要做的是检查零距离并以不同的方式处理。

【讨论】:

  • 感谢这并不能防止崩溃,但会延迟它并实际上在屏幕上绘制敌人。基本上我可以四处走动,敌人确实在我身后移动,但是三个敌人中的一个消失了,大约 2 秒后,崩溃仍然发生。所以我会保留原来的问题,希望有人能在代码中发现错误。
  • 非常感谢,作为一个初学者,我真的不知道如何解决这个问题,(希望在教程中他们会继续解决这个问题。但是有了这个答案将对我将来有所帮助我确定。将完成本教程,但将其分解,看看我可以自己制作什么程序,而不希望遇到同样的问题。
猜你喜欢
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多