DirectX:Direct3D:Tutorials:VBNET:DX9:Better Game Loop
From GPWiki
[edit] A better game loopThe game loop (or message loop/pump) is the loop in which you compute data. Most game related pumps works as following:
[edit] DoEvent is Evil?Here we will be discussing some options to increase performance in the game loop. For a variety of reasons, using DoEvent's in a loop is totally unacceptable, as DoEvents does some allocations that, due to the nature of a game loop, result in allocations getting promoted and ignored by the GC. You can observe this by running the following code: Do Application.DoEvents() Loop If you run the above code and check the system tray, you'll notice that your application is consuming memory. To explain it in simple terms, DoEvents allocates resources which is not cleaned up by the garbage collector.
Application.EnableVisualStyles() Depending on the end-user system, enabling visual styles in DoEvent loops can cause memory loss of up to 1MB/5 seconds.
[edit] The solution: PeekMessageWhat is needed is an inexpensive way of checking if there are messages waiting in the queue so we can bail out of the loop and let them be processed. The PeekMessage function dispatches incoming sent messages, checks the thread message queue for a posted message, and retrieves the message (if any exist). [edit] Declaring PeekMessagePeekMessage is native Win32 API, and not an .NET function. This means that we need to define the functions location and arguments: <System.Security.SuppressUnmanagedCodeSecurity()> _ Private Declare Function PeekMessage Lib "User32.dll" Alias "PeekMessageA" ( _ ByRef msg As MessageStruct, _ ByVal hWnd As IntPtr, _ ByVal messageFilterMin As Integer, _ ByVal messageFilterMax As Integer, _ ByVal flags As Integer _ ) As Integer
We also need to create the structure MessageStruct, which is called as the argument "msg" in the function. The structure code is as following: <StructLayout(LayoutKind.Sequential)> _ Public Structure MessageStruct Public HWnd As IntPtr Public Msg As Message Public WParam As IntPtr Public LParam As IntPtr Public Time As Integer Public P As System.Drawing.Point End Structure [edit] Implementing PeekMessageNow that we have set up our definition and structure we can begin using it. First up we will create a function that returns true if messages are waiting, or false if not. Protected Function _AppIsIdle() As Boolean Dim msg As MessageStruct Return (PeekMessage(msg, IntPtr.Zero, 0, 0, 0) = 0) End Function [edit] Using the function: _AppIsIdleAbove we created a function to determine if messages are waiting. To use it, we create a simple sub that should loop a call to your game loop. Protected Sub OnApplicationIdle(ByVal sender As Object, ByVal e As EventArgs) Do While _AppIsIdle() '<-- call game loop from here - such as Private Sub Render() from the previous tutorials Loop End Sub
[edit] Handle OnApplicationIdleWe are almost done now. All that's left to do is to make your application to call "OnApplicationIdle", preferably in the sub main before executing the form. dim app as new form1 AddHandler System.Windows.Forms.Application.Idle, AddressOf app.OnApplicationIdle This should make sure that OnApplicationIdle is called when all messages have been dealt with.
[edit] Using resources rightHaving a good game loop is not just about utilizing the system resources to the max. In fact, sometimes this can be a real bother for the end-user. If your application is running in full-screen, and the user Alt-Tabs to check an IM, or in windowed mode if the user decides to pause and check mail or something - having the application stuck in the game loop can be dead waste of valuable CPU.
'We aren't the active window, so relax a bit and free up the CPU If Not ActiveForm Is Me Then Thread.Sleep(200) End If Having the above code in your game loop can reduce the CPU usage from >90% to almost null, which you can imagine boost system performance a lot when your application is minimized.
[edit] What did we learn?
Categories: VBNET | Tutorial | DirectX |


