SDL事件处理延迟
SDL Event Handling Delay
按键之间有一个主要(1-2秒)延迟
下面是main.cpp(滞后输入处理):#include <iostream>
#include "src/Input/InputManager.h"
#include "src/Graphics/Display.h"
#define LOG(x) std::cout << x << std::endl;
using namespace Rambug;
int main(int arc, char** argv)
{
Graphics::Display display(900, 600, "Rambug Engine Tester", true);
display.createDisplay();
SDL_Event event;
Input::InputManager inputManager;
// "Game" Loop
while (!display.isClosed())
{
display.update();
glClearColor(0.0f, 0.02f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
while (SDL_PollEvent(&event))
{
if (event.type == SDL_KEYDOWN)
{
std::cout << "Keydowner" << std::endl;
}
if (event.type == SDL_KEYUP)
{
std::cout << "Keyupper" << std::endl;
}
}
// inputManager.update();
}
display.destroyDisplay();
system("PAUSE");
return 0;
}
这是Display.cpp,当我运行相同的代码(SDL_KEYDOWN, SDL_KEYUP)时,它运行完美,没有任何延迟,我只是在那里运行SDL_QUIT。
#include "Display.h"
namespace Rambug
{
namespace Graphics
{
Display::Display(int width, int height, std::string title, bool log)
{
m_displayWidth = width;
m_displayHeight = height;
m_displayTitle = title;
m_log = log;
m_window = nullptr;
}
Display::Display()
{
}
Display::~Display()
{
}
void Display::createDisplay()
{
// Initialize SDL
SDL_Init(SDL_INIT_EVERYTHING);
// Setting attributes to our window
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// Create window
m_window = SDL_CreateWindow((m_displayTitle.c_str()), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_displayWidth, m_displayHeight, SDL_WINDOW_OPENGL);
// Error Check Window
if (m_window == nullptr)
{
if (m_log)
std::cerr << "Window could not be created!" << std::endl;
}
else
{
if (m_log)
std::cout << "Window Created Successfully With SDL!" << std::endl;
}
// Create OpenGL Context
m_glContext = SDL_GL_CreateContext(m_window);
// Initialize GLEW
glewExperimental = GL_TRUE;
GLenum status = glewInit();
if (glewExperimental)
{
if (m_log)
std::cout << "Glew Experimental: On" << std::endl;
}
// Error Check GLEW
if (status != GLEW_OK)
{
if (m_log)
{
std::cerr << "GLEW could not be initialized!" << std::endl;
}
}
else
{
if (m_log)
{
std::cout << "GLEW Was Initilized Successfully!" << std::endl;
}
}
// Log OpenGL Version Number
if (m_log)
{
std::cout << "Using OpenGL Version: " << glGetString(GL_VERSION) << std::endl;
}
m_closed = false;
}
void Display::destroyDisplay()
{
SDL_GL_DeleteContext(m_glContext);
SDL_DestroyWindow(m_window);
SDL_Quit();
}
void Display::update()
{
SDL_GL_SwapWindow(m_window);
// Check for Input
while (SDL_PollEvent(&m_sdlEvent))
{
if (m_sdlEvent.type == SDL_QUIT)
{
m_closed = true;
}
}
}
bool Display::isClosed()
{
return m_closed;
}
}
}
我还尝试了一个Input管理器类,但这是同样的问题:延迟。更新方法就是我在main.cpp中调用的方法(我相信它被注释掉了)
#include "InputManager.h"
#include <iostream>
#define LOG(x) std::cout << x << std::endl;
namespace Rambug
{
namespace Input
{
InputManager::InputManager()
{
}
InputManager::~InputManager()
{
}
void InputManager::keyPressed(unsigned int keyCode)
{
m_keyMap[keyCode] = true;
}
void InputManager::keyReleased(unsigned int keyCode)
{
m_keyMap[keyCode] = false;
}
bool InputManager::isKeyDown(unsigned int keyCode)
{
auto it = m_keyMap.find(keyCode);
if (it != m_keyMap.end())
{
return it->second;
}
else
{
return false;
}
}
void InputManager::update()
{
while (SDL_PollEvent(&m_event))
{
switch (m_event.type)
{
case SDL_KEYDOWN:
LOG("SDL_KEYDOWN");
keyPressed(m_event.key.keysym.sym);
break;
case SDL_KEYUP:
LOG("SDL_KEYUP");
keyReleased(m_event.key.keysym.sym);
break;
}
}
}
}
}
所以InputManager和main.cpp有很大的延迟,而Display.cpp运行得很好。是因为我不能运行SDL_PollEvents两次吗?
是因为我不能运行SDL_PollEvents两次吗?
你的问题不是我所期望的,但是,是的,运行SDL_PollEvents
两次是个坏主意。SDL保留一个事件堆栈,在程序运行时添加到该堆栈中。SDL_PollEvents
从堆栈中弹出事件,直到它为空。因此,运行两个轮询循环,其中一个将删除另一个将看不到的事件。盲目的运气(或执行瓶颈)将决定哪个循环更有可能看到任何特定事件发生。(见http://wiki.libsdl.org/SDL_PollEvent)。
如果您真的想运行两个轮询循环,您可以在默认情况下存储未处理的事件,并在每个循环后使用SDL_PushEvent
推回事件列表:http://wiki.libsdl.org/SDL_PushEvent
这就是说,我很惊讶你的事件在一段时间后"通过":我希望它们消失。你在按键吗?然后,您的操作系统键重复延迟可能是您所看到的,之后事件队列在每个循环之间被淹没。您可能需要检查键事件的重复标志:http://wiki.libsdl.org/SDL_KeyboardEvent
我认为这是一个设计问题。你应该问自己,为什么Display委托游戏结束?把这一事实连同其他一切事情一起通知展览不是更明智吗?
SDL保留一个事件堆栈,该堆栈在程序运行时添加。SDL_PollEvents从堆栈中弹出事件,直到它为空。
我很确定它不是堆栈,而是队列。SDL_PushEvent
的名字有点误导人;它真正做的是将事件从"错误"端推回队列。(它可以在内部实现作为堆栈,但它的行为是队列的行为。)
不过,Qualia的答案是正确的。
然而,我并不认为拥有多个事件循环是件坏事——它们可能非常有用。两个场景:
1)在主事件循环中捕获类似resize事件的东西。如果后续操作非常耗时,那么只要用户继续调整窗口大小,事件队列就会被更多的调整大小事件淹没。
在这种情况下,on可以在耗时的重绘之后有一个单独的事件循环,它只是循环直到找到第一个非resize事件,然后将它看到的最后两个事件推回队列,并将控制权返回给主循环。这样就可以丢弃累积的调整大小事件。(使用SDL_PeepEvents
函数可以更优雅地完成,特别是在队列中有大量事件堆积的情况下。)
2)程序在捕获特定事件后采取的操作将触发其他事件,例如使用SDL_RaiseWindow
时,可能会触发大量焦点和窗口相关的后续事件,特别是如果您有多个SDL窗口。在这里,可以使用单独的事件循环来处理这些触发的事件,特别是在应该抑制对这些事件的响应的情况下。
关于延迟的问题,我也遇到了SDL_KEYDOWN
事件的各种奇怪行为,通常事件被触发多次,绝对与OS键重复无关。这似乎只发生在使用SDL_PollEvent
时;SDL_WaitEventTimeout
,即使超时延迟设置为'1',似乎也会抑制这种奇怪的行为。有趣的是,SDL_KEYUP
事件没有表现出这种行为。
- 给定顺序中的事件处理
- C++事件系统 - 多态事件和事件处理程序
- wxWidgets 拖放文件事件处理程序初始化问题(无效static_cast)
- 更好的事件处理机制?
- 如何将IEnumerable与Process.Start的输出事件处理程序一起使用?
- "动态创建的事件处理程序"复选框
- Wxwidgets - 如何添加调整大小事件处理程序以使"X"绘图随窗口调整大小?
- Qt 键按事件处理程序仅在按下 ctrl、alt 或 shift 键时做出反应
- 类成员作为 C++ 中 C 样式事件的事件处理程序
- C 设计事件处理程序类
- 将托管事件处理程序传递给 Linux 中的非托管代码
- 如何在 c++ linux 中创建事件处理程序
- 解除 lambda 事件处理程序的绑定
- 这是MFC C 中单个选择的ComboBox的事件处理程序
- 审核的实时事件处理 C/C++
- 指纹读取器 - 从 C# 代码创建事件处理程序到C++的问题
- 为什么我的Windows控制台关闭事件处理程序超时
- 无法让 matplotlib 事件处理程序与 Boost.Python 一起工作
- 事件处理程序是Embarcadero C++Builder中的重入程序吗
- SDL事件处理延迟