首页 > 解决方案 > 如果我使用 malloc() 而不是堆栈数组,OpenGL 不会渲染对象?

问题描述

在我用 C++ 编写的 2D OpenGL 游戏项目中,我现在尝试从文件中读取“敌人的数量”,然后渲染这些敌人。每个敌人由 2 个带纹理的三角形(2D 精灵)组成。

我可以使用包含单个“敌人”数据(例如每个敌人的位置)的结构的数组声明来实现渲染,但是如果我尝试使用 malloc 根据我从文件中读取的数字动态分配内存,则不会渲染任何内容.

我究竟做错了什么?我真的很想使用 malloc ,因为敌人的数量会有所不同,而且我不想使用固定大小的数组。

关于下面的代码:基本上一个名为“gameEnemies”的类包含一个名为“Enemy”的结构;每次创建“gameEnemies”类的对象时,该对象应分配足够的内存以根据外部文件中定义的内容创建尽可能多的敌人。

  1. 这是具有固定大小数组声明的结构 - 这个正在工作。

    struct Enemy {
    
    
        Point3D center; //object attributes
        Vector3D direction; //gets updated with current direction after rotations to show where object is facing at
        Vector3D collDir; //which direction collided
    
        float deltaX;
        float deltaY;
        float prevDeltaX;
        float prevDeltaY;
        float deltaA;
        float prevDeltaA;
        float speed;
        bool collided;
    
        int qtyCollided; //with how many other objects it collided
    
        bool alive;
    
        //matrices below passed as uniforms to shader
        //rotation
        Transform4D rotateTransf{ 1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
        //moves to world position after being drawn with center at origin (0,0)
        Transform4D modelTransf{  1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
    
        //translation of texture (animation), passed as uniform to shader
        Transform4D transformTex{ 1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
    
    }enemies[MAX_TMX_ENEMIES];
    
  2. 这是不起作用的结构 - 与上面相同,但改为声明指针。

    struct Enemy {
    
    
        Point3D center; //object attributes
        Vector3D direction; //gets updated with current direction after rotations to show where object is facing at
        Vector3D collDir; //which direction collided
    
        float deltaX;
        float deltaY;
        float prevDeltaX;
        float prevDeltaY;
        float deltaA;
        float prevDeltaA;
        float speed;
        bool collided;
    
        int qtyCollided; //with how many other objects it collided
    
        bool alive;
    
        //matrices below passed as uniforms to shader
        //rotation
        Transform4D rotateTransf{ 1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
        //moves to world position after being drawn with center at origin (0,0)
        Transform4D modelTransf{  1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
    
        //translation of texture (animation), passed as uniform to shader
        Transform4D transformTex{ 1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
    
    }*enemies;
    
  3. 下面是分配内存和初始化值的循环 - 似乎可以访问数据并且在编译时和运行时都没有错误:

    enemies = (Enemy*)malloc(sizeof(Enemy) * totalObj);
    
    for (int j = 0; j < totalObj; j++) //loop objects in the group
    {
    
        enemies[j].center = mapObj.getObjects(i)[j].center;
        enemies[j].direction = Vector3D{1.0f, 0.0f, 0.0f};
        enemies[j].deltaX = 0.0f;
        enemies[j].deltaY = 0.0f;
        enemies[j].prevDeltaX = 0.0f;
        enemies[j].prevDeltaY = 0.0f;
        enemies[j].deltaA = 0.0f;
        enemies[j].prevDeltaA = 0.0f;
        enemies[j].speed = 6.0f;
        enemies[j].collided = false;
        enemies[j].collDir = Vector3D{ 0.0f, 0.0f, 0.f };
        enemies[j].qtyCollided = 0;
        enemies[j].alive = true;
    
        enemies[j].modelTransf.SetTranslation(Point3D{ enemies[j].center.x, enemies[j].center.y, 0.0f }); //initial translation to world position
        enemies[j].rotateTransf.SetRotationZ(enemies[j].deltaA); //initial rotation = 0
        enemies[j].transformTex.SetTranslation(Point3D{ 0.0f, 0.0f, 0.0f }); //no transform on texture upon object creation
    
    }
    
  4. 下面是使用数组声明时初始化值的循环 - 唯一的变化是没有预设 malloc:

    /*EXCLUDED: enemies = (Enemy*)malloc(sizeof(Enemy) * totalObj);*/
    for (int j = 0; j < totalObj; j++) //loop objects in the group
    {
    
        enemies[j].center = mapObj.getObjects(i)[j].center;
        enemies[j].direction = Vector3D{1.0f, 0.0f, 0.0f};
        enemies[j].deltaX = 0.0f;
        enemies[j].deltaY = 0.0f;
        enemies[j].prevDeltaX = 0.0f;
        enemies[j].prevDeltaY = 0.0f;
        enemies[j].deltaA = 0.0f;
        enemies[j].prevDeltaA = 0.0f;
        enemies[j].speed = 6.0f;
        enemies[j].collided = false;
        enemies[j].collDir = Vector3D{ 0.0f, 0.0f, 0.f };
        enemies[j].qtyCollided = 0;
        enemies[j].alive = true;
    
        enemies[j].modelTransf.SetTranslation(Point3D{ enemies[j].center.x, enemies[j].center.y, 0.0f }); //initial translation to world position
        enemies[j].rotateTransf.SetRotationZ(enemies[j].deltaA); //initial rotation = 0
        enemies[j].transformTex.SetTranslation(Point3D{ 0.0f, 0.0f, 0.0f }); //no transform on texture upon object creation
    
    }
    
  5. 在通用渲染函数下方:适用于数组,如果我使用 malloc,则不会渲染单个对象:

    void render()
    {
        // shader to use
        objShader.use();
        objShader.setVec4("orthoTex", orthoTex); //common to all instances
        //for texture
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glBindTexture(GL_TEXTURE_2D, texture);
    
        glBindVertexArray(VAO);
        for(int i = 0; i< totalEnemies; i++)
        {
            //pass relevant uniforms to shader before drawing each instance
            objShader.setVec4("transfTex", enemies[i].transformTex);
            objShader.setVec4("modelTransf", enemies[i].modelTransf);
            objShader.setVec4("rotateTransf", enemies[i].rotateTransf);
            //draw
            glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        }
        glBindVertexArray(0);
    }
    
  6. 结构 Enemy 位于一个名为“gameEnemies”的结构内 - 不确定这是否会改变任何东西,但以防万一。这是因为所有的“敌人”都将共享共同的属性,如 OpenGL 缓冲区、顶点、着色器等。

    struct gameEnemies {
    
    protected:
    
        //arrays with vertex data and indices
        float vertices[16]; //holds vertex + texture coordinates for VBO (order: obj.x, obj.y, tex.x, tex.y, obj.x...)
        unsigned int indices[6]; //holds triangle indices for the EBO
    
        //the OpenGL buffers
        unsigned int VBO, VAO, EBO;
    
        //object shader
        Shader objShader;
    
        //texture ID
        unsigned int texture;
    
        float width;
        float height;
    
        int totalEnemies;
        int enemyMapPos; //position in the MAP OBJECT (which group) where enemies of specicif "label" for this handler are
    
        //transform texture coordinates to world (png file) coordinates (0,0 //bottom left to 1,1//top right)
        Transform4D orthoTex;
    
        struct Enemy {
    
    
            Point3D center; //object attributes
            Vector3D direction; //gets updated with current direction after rotations to show where object is facing at
            Vector3D collDir; //which direction collided
    
            float deltaX;
            float deltaY;
            float prevDeltaX;
    

    ETC...

标签: c++openglmallocgame-engine

解决方案


在 C++ 中使用malloc是错误的,除非在非常特殊的情况下。

malloc分配内存,但不在其中构造任何对象。尝试像Enemy在其中创建实例一样使用内存会导致未定义的行为。

你需要使用new[]. 它分配内存并构造对象:

enemies = new Enemy[totalObj];

您销毁这些对象并稍后使用delete[] enemies.


但是,您不应该使用手动动态内存管理。改为使用std::vector

std::vector<Enemy> enemies;

enemies.resize(totalObj);

也很不清楚为什么您使用默认成员初始化程序初始化类定义中的一些成员,而其他成员则在外部循环中。

要么为所有成员使用默认成员初始化器,要么为您struct执行所有初始化编写适当的构造函数。

您当前的方法令人困惑且效率较低,因为内存必须迭代两次。

这也是危险的,因为如果你在构建Enemys 后忘记设置其中一个未初始化的成员,那么在使用它时你将有未定义的行为。


推荐阅读