2013-05-11 88 views
0

我正在使用SetTimer在我的遊戲中放置一個定時器,定時器會每1000毫秒觸發一段時間後,我想改變定時器的時間間隔,所以我再次調用SetTimer與相同的timerId(根據MSDN,這將取代舊超時計時器),但它似乎不起作用,計時器沒有被解僱。SetTimer不改變時間間隔

這是我的代碼,這是一個典型的遊戲循環。

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); 
} 

代碼工作好之前,我在SetTimer的再次調用渲染功能,但加入這一行,爲什麼後停止工作?

+0

爲了讓您收到'WM_TIMER'消息,您的代碼必須抽取消息循環。如果您陷入計算密集的渲染中,並不會定期停止抽取消息循環,則無論計時器的間隔如何,都不會收到「WM_TIMER」消息。如果你註釋掉第二次調用SetTimer,你實際上是否每1000毫秒收到一次WM_TIMER消息? – 2013-05-11 08:26:36

+0

是的,當我將第二個調用註釋到SetTimer時,它就可以工作。 – zdd 2013-05-11 11:47:31

回答

3

您編寫它的方式,您一次又一次地高速調用SetTimer()。不斷重置計時器,因此永遠不會讓WM_TIMER消息有足夠的時間傳遞以便發佈。

顯然你需要找到一個更好的觸發器來更新計時器。也許只有在間隔值實際需要改變時才調用SetTimer。由於它沒有明顯的觸發條件,所以不太清楚如何從發佈的代碼中做到最好。

+0

情況並非如此,我將時間間隔更改爲500毫秒,但仍然無效。 – zdd 2013-05-11 11:48:00

+0

我發佈的代碼僅僅是一個例子,真正的邏輯是當用戶得分超過20時,遊戲速度會改變,所以定時器在得分達到20時觸發。 – zdd 2013-05-11 11:49:28

+0

我想我得到了你,渲染函數被稱爲每幀,並且定時器每幀被重置,如果幀速率大於時間間隔,它將永遠不會被觸發。 – zdd 2013-05-11 11:53:57