【问题标题】:SetTimer does not change time intervalSetTimer 不改变时间间隔
【发布时间】:2013-05-11 01:59:25
【问题描述】:

我正在使用SetTimer在我的游戏中放置一个计时器,计时器将每1000毫秒触发一次,一段时间后,我想更改计时器的时间间隔,所以我再次使用相同的timerId调用SetTimer(根据到 MSDN,这将用新的超时替换旧的计时器),但它似乎不起作用,计时器没有被触发。

这是我的代码,这是一个典型的游戏循环。

INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR szCmdLine, int iCmdShow)
{
    WNDCLASSEX winClass ;

    winClass.lpszClassName = L"RotationBySetTimer";
    winClass.cbSize        = sizeof(WNDCLASSEX);
    winClass.style         = CS_HREDRAW | CS_VREDRAW;
    winClass.lpfnWndProc   = MsgProc;
    winClass.hInstance     = hInstance;
    winClass.hIcon         = NULL ;
    winClass.hIconSm       = NULL ;
    winClass.hCursor       = LoadCursor(NULL, IDC_ARROW) ;
    winClass.hbrBackground = NULL ;
    winClass.lpszMenuName  = NULL ;
    winClass.cbClsExtra    = 0;
    winClass.cbWndExtra    = 0;

    RegisterClassEx (&winClass) ;  

    HWND hWnd = CreateWindowEx(NULL,  
        winClass.lpszClassName,     // window class name
        L"RotationBySetTimer",                  // window caption
        WS_OVERLAPPEDWINDOW,        // window style
        32,                         // initial x position
        32,                         // initial y position
        600,                        // initial window width
        600,                        // initial window height
        NULL,                       // parent window handle
        NULL,                       // window menu handle
        hInstance,                  // program instance handle
        NULL) ;                     // creation parameters

    **SetTimer(hWnd, 1, 1000, NULL);**

    // Initialize Direct3D
    if( SUCCEEDED(InitD3D(hWnd)))
    { 
        // Show the window
        ShowWindow( hWnd, SW_SHOWDEFAULT );
        UpdateWindow( hWnd );

        MSG msg ; 
        ZeroMemory( &msg, sizeof(msg) );
        PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );

        // Get last time
        static DWORD lastTime = timeGetTime();

        while (msg.message != WM_QUIT)  
        {
            if(PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0)
            {
                TranslateMessage (&msg) ;
                DispatchMessage (&msg) ;
            }
            else // Render the game if there is no message to process
            {
                // Get current time
                DWORD currTime  = timeGetTime();

                // Calculate time elapsed
                float timeDelta = (currTime - lastTime) * 0.001f;

                // Render
                Render(hWnd, timeDelta) ;

                // Update last time to current
                lastTime = currTime;
            }
        }
    }

    UnregisterClass(winClass.lpszClassName, hInstance) ;
    return 0;
}

我在 Render 函数中再次调用 SetTimer 来更改时间间隔。

void Render(HWND hWnd, float timeDelta)
{
    **SetTimer(hWnd, 1, 2000, NULL);**

    if (!g_bActive)
    {
        Sleep(50) ;
    }

    SetupMatrix() ;

    // Clear the back-buffer to a RED color
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

    // Begin the scene
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
        // Draw teapot 
        g_pTeapotMesh->DrawSubset(0) ;

        // End the scene
        g_pd3dDevice->EndScene();
    }

    // Present the back-buffer contents to the display
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

在我在Render函数中再次调用SetTimer之前代码运行良好,但添加此行后停止运行,为什么?

【问题讨论】:

  • 为了让您接收WM_TIMER 消息,您的代码必须抽出消息循环。如果您陷入计算密集型渲染,并且不会定期停止以泵送消息循环,那么无论计时器的间隔如何,您都不会收到WM_TIMER 消息。如果您注释掉对SetTimer 的第二次调用,您是否真的每1000 毫秒收到一次WM_TIMER 消息?
  • 是的,当我注释掉对 SetTimer 的第二次调用时,它可以工作。

标签: windows winapi timer message


【解决方案1】:

按照您的编码方式,您一遍又一遍地高速调用 SetTimer()。不断重置计时器,因此永远不会有足够的时间来传递 WM_TIMER 消息。

显然,您需要找到更好的触发器来更新计时器。也许只有在间隔值实际需要更改时才调用 SetTimer 。由于它没有明显的触发条件,因此从发布的代码中不清楚如何最好地做到这一点。

【讨论】:

  • 不是这样,我把时间间隔改成500ms,还是不行。
  • 我贴的代码只是一个例子,真正的逻辑是当用户得分超过20时,游戏速度会发生变化,所以当得分达到20时触发计时器。
  • 我想我明白了,渲染函数每帧都会被调用,并且每帧都会重置计时器,如果帧速率大于时间间隔,它将永远不会触发。
  • 我用静态变量更新了我的代码,它现在可以工作了,非常感谢! if( gameScore >= 1 ) { static bool isUpdate = false; if(!isUpdate) { SetTimer(this->hWnd, 123, 500, NULL); isUpdate = true; } }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-23
  • 2020-06-21
  • 2019-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多