Results 1 to 3 of 3

Thread: [Vb.Net] Managed Game Loop

  1. #1

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,712

    [Vb.Net] Managed Game Loop

    Description
    Some people want the ease of use from a timer but want the accuracy from a game loop. Well this code here does just that. Use it like a timer, but expect high precision accuracy that automatically matches the computer monitor's refresh rate.

    Prerequisites
    Simply add the System.Management DLL to your references. If you computer does not support the QueryPerformance API's then an exception will be thrown.

    Code
    Code:
    Option Strict On
    Option Explicit On
    <System.ComponentModel.DefaultEvent("Tick")> _
    Public Class GameLoop
        Inherits System.ComponentModel.Component
    
        Private frequency As Long
        Private waitThread As Threading.Thread
    
    #Region "Api"
    
        Private Declare Function QueryPerformanceCounter Lib "kernel32" (ByRef lpPerformanceCount As Long) As Integer
        Private Declare Function QueryPerformanceFrequency Lib "kernel32" (ByRef lpFrequency As Long) As Integer
    
    #End Region
    
    #Region "Events"
    
        Public Event Tick(ByVal sender As Object, ByVal e As EventArgs)
    
    #End Region
    
    #Region "Methods"
    
        Private Sub CheckCompatibility()
            Dim test As Long
            If Not CBool(QueryPerformanceCounter(test)) Then
                Throw New Exception("High-resolution counter is not supported for this computer.")
            End If
        End Sub
    
        Private Function GetRefreshRate() As Double
            Dim query As System.Management.SelectQuery = New System.Management.SelectQuery("Win32_VideoController")
    
            For Each mo As System.Management.ManagementObject In New System.Management.ManagementObjectSearcher(query).Get
                Dim currentRate As Object = mo("CurrentRefreshRate")
                If currentRate IsNot Nothing Then
                    Return CDbl(currentRate)
                End If
            Next
    
            Return Nothing
        End Function
    
        Public Sub Start()
            pEnabled = True
            waitThread = New Threading.Thread(AddressOf Wait)
            waitThread.IsBackground = True
            waitThread.Start()
        End Sub
    
        Public Sub [Stop]()
            Me.Enabled = False
        End Sub
    
        Private Sub Wait()
            Dim counter1, counter2 As Long
            QueryPerformanceCounter(counter1)
    
            Do
                QueryPerformanceCounter(counter2)
            Loop Until (counter2 - counter1) / (frequency / 1000) >= 1000 / rate
    
            RaiseEvent Tick(Me, EventArgs.Empty)
    
            Console.WriteLine((counter2 - counter1) / (frequency / 1000))
    
            If pEnabled Then
                waitThread = New Threading.Thread(AddressOf Wait)
                waitThread.IsBackground = True
                waitThread.Start()
            End If
    
        End Sub
    
    #End Region
    
    #Region "New Constructor"
    
        Sub New()
            Call CheckCompatibility()
            QueryPerformanceFrequency(frequency)
            rate = GetRefreshRate()
        End Sub
    
    #End Region
    
    #Region "Properties"
    
        Private pEnabled As Boolean
        <System.ComponentModel.Description("Gets or sets a value indicating whether the GameLoop should raise the Tick event.")> _
        Public Property Enabled() As Boolean
            Get
                Return pEnabled
            End Get
            Set(ByVal value As Boolean)
                If pEnabled <> value Then
                    pEnabled = value
                    If pEnabled Then RaiseEvent Tick(Me, EventArgs.Empty)
                End If
            End Set
        End Property
    
        Private rate As Double
        <System.ComponentModel.Description("Gets or sets a value indicating the refresh rate of the computer's monitor.")> _
        Public ReadOnly Property RefreshRate() As Double
            Get
                Return rate
            End Get
        End Property
    
    #End Region
    
    End Class
    Acknowledgements
    Jacob Roman - Showing me the QueryPerformance API's
    TnTinMN - Helping with getting the refresh rate of the monitor
    Last edited by dday9; Jul 17th, 2014 at 01:58 PM. Reason: Added Acknowledgements
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

  2. #2
    PowerPoster boops boops's Avatar
    Join Date
    Nov 2008
    Location
    Holland/France
    Posts
    3,201

    Re: [Vb.Net] Managed Game Loop

    Hi dday,
    This would be a really useful timer but I can't get it to work as described. To test it, I dragged a GameLoop component onto a form with a button, and coded the form as follows:
    Code:
    	Private sw As Stopwatch
    	Dim prevMilliseconds As Integer
    
    	Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    		With GameLoop1
    			Console.WriteLine(.RefreshRate)
    			sw = Stopwatch.StartNew
    			.Start()
    		End With
    	End Sub
    
    	Private Sub GameLoop1_Tick(sender As Object, e As System.EventArgs) Handles GameLoop1.Tick
    		Dim s As Integer = CInt(sw.ElapsedMilliseconds)
    		Console.WriteLine(s - prevMilliseconds)
    		prevMilliseconds = s
    	End Sub
    The output shows the Tick interval alternating between an exact-looking 16.66... milliseconds and a rather random interval of somewhere between 20 and 120 milliseconds, for example:
    Code:
    16,6667161647157
    24
    16,6666973679882
    88
    16,6669718002096
    44
    17,9118978585828
    64
    16,6671447301025
    53
    16,6669417254456
    (excusez le decimal comma)
    Of course, this could conceivably be due to my somewhat antiquated hardware (with WinXP no less) or maybe I have made a mistake somewhere. What result do you get when you run the same test?

    BB

  3. #3

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,712

    Re: [Vb.Net] Managed Game Loop

    What I have found is that the QueryPerformance API's are very hardware intensive, so if you do not have up-to-date hardware then it can run sporadically.

    Another thing that I noticed is that if you're running a dual monitor, then you'll get optimal results by running the program on the primary screen.
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width