【问题标题】:SDL2 OpenGL C++ moving a sprite drawn with VBO and FBOSDL2 OpenGL C++ 移动使用 VBO 和 FBO 绘制的精灵
【发布时间】:2016-08-08 22:11:30
【问题描述】:

我使用 fbo 和 vbo 在我的 Sprite.cpp 中绑定并绘制了一个由两个三角形组成的矩形,这是我的 init 方法

void Sprite::init(float x, float y, float width, float height) {

_x = x;
_y = y;
_width = width;
_height = height;

if (_vboID == 0) {

    glGenBuffers(1, &_vboID);

}



vertexData[0] = x + width;
vertexData[1] = y + height;

vertexData[2] = x;
vertexData[3] = y + height;

vertexData[4] = x;
vertexData[5] = y;

vertexData[6] = x + width;
vertexData[7] = y + height;

vertexData[8] = x;
vertexData[9] = y;

vertexData[10] = x + width;
vertexData[11] = y;


glBindBuffer(GL_ARRAY_BUFFER, _vboID);

glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_DYNAMIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, 0);

}

这里是draw方法

void Sprite::draw() {

glBindBuffer(GL_ARRAY_BUFFER, _vboID);
glEnableVertexAttribArray(0);


glVertexAttribPointer(0, 2, 0x1406, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);

glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);

}

我显然错过了一些非常明显的概念,因为我似乎无法在任何地方找到解决方案,我的问题是当我按下 s 时,我的矩形不会向下移动。 (因为我使用的是 WASD 移动)这是输入处理程序的代码

void InputHandler::handleInput(SDL_Event* event, Sprite *toMove) {

switch (event->type) {

case SDL_KEYDOWN:
{
    if (event->key.keysym.sym == SDLK_a) {
        toMove->setMovementBooleans(MovementTuples::LEFT, true);
        std::cout << "Set left ";
    }
    if (event->key.keysym.sym == SDLK_d) {
        toMove->setMovementBooleans(MovementTuples::RIGHT, true);
        std::cout << "Set right ";
    }
    if (event->key.keysym.sym == SDLK_s) {
        toMove->setMovementBooleans(MovementTuples::DOWN, true);
        std::cout << "Set down ";
    }
    if (event->key.keysym.sym == SDLK_w) {
        toMove->setMovementBooleans(MovementTuples::UP, true);
        std::cout << "Set up ";
    }
    break;

}

case SDL_KEYUP:
{
    if (event->key.keysym.sym == SDLK_a) {
        toMove->setMovementBooleans(MovementTuples::LEFT, false);
    }
    if (event->key.keysym.sym == SDLK_d) {
        toMove->setMovementBooleans(MovementTuples::RIGHT, false);
    }
    if (event->key.keysym.sym == SDLK_s) {
        toMove->setMovementBooleans(MovementTuples::DOWN, false);
    }
    if (event->key.keysym.sym == SDLK_w) {
        toMove->setMovementBooleans(MovementTuples::UP, false);
    }
}

}

}

此方法是静态访问的。这是在我的精灵 cpp 中单击 s 键时向下移动精灵的代码

void Sprite::update() {

if (movementBooleans[MovementTuples::DOWN]) {
    _x -= .1f;
    init(_x, _y, _width, _height);
    std::cout << "Moved to: (" << _x << ", " << _y  << ")"<<  std::endl;
}

当我向下单击时,我的矩形完全消失,_x 值保持不变。我测试了输入,它完全按照我想要的方式工作,我似乎无法让矩形移动。谁能帮我弄清楚如何移动我的 Sprite,谢谢!

【问题讨论】:

    标签: c++ opengl sdl-2


    【解决方案1】:

    我正在使用 OpenGL。虽然我没有使用 SDL,因为我使用的是用户实现的输入处理程序,但概念应该是相同的。

    我当前使用的游戏引擎有一个游戏类对象,它继承自一个引擎类对象,其中引擎类是一个单例对象。由于这个游戏引擎的结构; Engine 类需要 Game 类来实现虚拟键盘输入功能。这是原型的样子

    引擎类

    class Engine : public  Singleton {
    protected:
        // Protected Members
    private:
        // Private Members
    
    public:
        // virtual destructor & public functions
    protected:
        // explicit protected Constructor & protected functions
    private:
        bool messageHandler( unsigned uMsg, WPARAM wParam, LPARAM lParam );
    
        virtual void keyboardInput( unsigned vkCode, bool isPressed ) = 0;
    
        // Other Private Functions
    
    }; // Engine
    

    游戏类

    class Game sealed : public Engine {
    private:
        // private members here
    
    public:
        // Constructor and virtual Destructor
    
    private:
       virtual void keyBoardInput( unsigned vkCode, bool isPressed ) override;
    }; // Game
    

    这里是 Windows 的 messageHandler() 函数

    // ----------------------------------------------------------------------------
    // messageHandler()
    bool Engine::messageHandler( unsigned uMsg, WPARAM wParam, LPARAM lParam ) {
        switch( uMsg ) {
            case WM_CLOSE: {
                PostQuitMessage( 0 );
                return true;
            }
            case WM_SYSKEYDOWN : {
                if ( ( VK_MENU == wParam ) && ( lParam & 0x1000000 ) ) {
                    wParam = VK_RMENU; // Alt Key
                }
                // Fall Through
            }
            case WM_KEYDOWN: {
                if ( ( VK_RETURN == wParam ) && ( lParam & 0x1000000 ) ) {
                    wParam = VK_SEPARATOR;
    
                } else if ( ( VK_CONTROL == wParam ) && ( lParam & 0x1000000 ) ) {
                    wParam = VK_RCONTROL;
                }
    
                if ( 0 == ( lParam & 0x40000000 ) ) { // Supress Key Repeats
                    keyboardInput( wParam, true );
                }
                return true;
            }
            case WM_SYSKEYUP: {
                if ( ( VK_MENU == wParam ) && ( lParam & 0x1000000 ) ) {
                    wParam = VK_RMENU; // Alt Key
                }
                // Fall Through
            }
            case WM_KEYUP: {
                if ( ( VK_RETURN == wParam ) && ( lParam & 0x1000000 ) ) {
                    wParam = VK_SEPARATOR;
    
                } else if ( ( VK_CONTROL == wParam ) && ( lParam & 0x1000000 ) ) {
                    wParam = VK_RCONTROL;
                }
    
                keyboardInput( wParam, false );
    
                return true;
            }
            case WM_MOUSEMOVE: {
                // Mouse Motion Detected, Coordinates Are WRT Window Therefore
                // 0,0 Is The Coordinate Of The Top Left Corner Of The Window
                m_mouseState.position = glm::ivec2( LOWORD( lParam ), HIWORD( lParam ) );
                mouseInput();
                return true;
            }
            case WM_LBUTTONDOWN: {
                m_mouseState.isButtonPressed[MOUSE_LEFT_BUTTON] = true;
                mouseInput();
                return true;
            }
            case WM_LBUTTONUP: {
                m_mouseState.isButtonPressed[MOUSE_LEFT_BUTTON] = false;
                mouseInput();
                return true;
            }
            case WM_RBUTTONDOWN: {
                m_mouseState.isButtonPressed[MOUSE_RIGHT_BUTTON] = true;
                mouseInput();
                return true;
            }
            case WM_RBUTTONUP: {
                m_mouseState.isButtonPressed[MOUSE_RIGHT_BUTTON] = false;
                mouseInput();
                return true;
            }
            case WM_MBUTTONDOWN: {
                m_mouseState.isButtonPressed[MOUSE_MIDDLE_BUTTON] = true;
                mouseInput();
                return true;
            }
            case WM_MBUTTONUP: {
                m_mouseState.isButtonPressed[MOUSE_MIDDLE_BUTTON] = false;
                mouseInput();
                return true;
            }
            case WM_MOUSEWHEEL: {
                // Mouse Wheel Moved
                // wParam Contains How Much It Was Moved
                return true;
            }
            default: {
                return false; // Did Not Handle The Message
            }
        }
    } // messageHandler
    

    最后这是keyboardInput()函数

    // ----------------------------------------------------------------------------
    // keyboardInput()
    void Game::keyboardInput( unsigned vkCode, bool isPressed ) {
        std::ostringstream strStream;
        strStream << "Key 0" << std::hex << vkCode << " was " << ( isPressed ? "Pressed" : "Released" );
        Logger::log( strStream );
    
        if ( VK_ESCAPE == vkCode ) {
            PostQuitMessage( 0 );
        }
    
        static bool keyPressed[256] = { 0 };
        if ( vkCode < 256 ) {
            keyPressed[vkCode] = isPressed;
        }
    
        if ( isPressed ) {
            return;
        }
    
        switch ( vkCode ) {
            case VK_DOWN:
            case 'S' : {
                // do logic here
                break;
            }
            case VK_LEFT:
            case 'A' : {
                // do logic here
                break;
            }
            case VK_RIGHT:
            case 'D' : {
                // do logic here
                break;
            }
            case VK_UP: 
            case 'W' : {
                // do logic here
                break;
            }
        }
    
    } // handleKeyboard
    

    当您仔细查看代码时;我不是在轮询以查看何时按下该键,而是在查询或等待查看何时释放该键。这种逻辑的原因是这样的;当你按下一个键时,它可以重复按下而不会达到向上状态。这就像在任何文本编辑器中按住相同的键,您将看到相同的键显示在屏幕上。解决此问题或避免此行为;我们做相反的逻辑。

    我们查找密钥的释放时间。该键只能释放一次,必须再次按下才能再次进入释放状态。这样,您每次按键都会发生一次程序动作,然后释放。

    现在,如果您注意到我们确实会检查该键是否处于按下状态,如果是则我们返回;这很重要,因为如果您不这样做,您的程序将自动执行消息处理程序中的操作,因为默认情况下按键状态已经处于释放状态。因此,这里发生的情况是在调用Game::keyboardInput()Engine::messageHandler() 函数时渲染帧或更新帧期间,如果它检测到按键已将其状态更改为true,则它会从函数返回并再次连续调用直到您释放密钥;一旦键被释放并且状态变回释放它然后跳过 if 语句并直接转到您正在处理的键的 switch 语句。

    【讨论】:

    • +1 表示努力,但这实际上与我的问题无关,是的,我明白你在做什么,但我的问题是如何移动我的精灵......我的输入有效。跨度>
    • 根据您向我描述的内容:“..., my problem is when I press s my rectangle does not move down. ...”然后您展示了您的 inputHandler() 的逻辑然后您继续说“When I click down, my rectangle completely disappear and the _x value stays the same; ...”并且行为听起来好像是关键被反复按下。在您的Sprite::update() 中尝试使用从0.1f0.05f 的较小值,而不是修改_x 变量,用_y 替换它。如果你想垂直移动它,增加和减少你的向量的 Y 分量。
    • 您也没有显示调用这些函数的代码。
    • 我希望它像那样连续发射,我把它设置为 0.00001f 并且它做了同样的事情
    • 在我的 messageHandler 中让我执行重复的关键操作,我所要做的就是注释掉这段代码:if ( 0 == ( lParam &amp; 0x40000000 ) ) { // Supress Key Repeats keyboardInput( wParam, true ); } ,因为这会抑制多个关键操作。
    【解决方案2】:

    如果你想移动 OpenGL 形状,你真的应该做矩阵变换。

    我个人使用 GLM 为我完成所有繁重的工作,所以我所要做的就是在转换完成后将矩阵传递给 GLSL。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多