C#GDI游戏循环(FPS计数器)

时间:2016-11-28 03:38:38

标签: c# gdi+ gdi game-loop

我目前正在使用C#,GDI制作2D游戏引擎并设置了简单的框架上限。游戏只能渲染60fps。

据我所知,代码没有任何问题,我只想更清晰地渲染60fps,而不是更多。

这是我的代码,任何帮助都会很棒

# sample Examples as CSV

Get-ADUser MyUser01 -properties * | select-object name, samaccountname, surname, enabled, @{"name"="proxyaddresses";"expression"={$_.proxyaddresses}} | Export-Csv ProxyAddress.csv

Get-ADUser -Filter * -SearchBase 'ou=TestOU,dc=domain,dc=com' -Properties proxyaddresses | select name, @{L='ProxyAddress_1'; E={$_.proxyaddresses[0]}}, @{L='ProxyAddress_2';E={$_.ProxyAddresses[1]}} | Export-Csv ProxyAddress.csv –NoTypeInformation

# Will find any active directory object that has an exact match to the e-mail address you place in the filter ie. email@yourdomain.com  

Get-ADObject -Properties mail, proxyAddresses -Filter {mail -eq "email@yourdomain.com" -or proxyAddresses -eq "smtp:email@yourdomain.com"}

# This filter (Using wildcards) will also grab not only smtp addresses but other types such as x500: eum: sip: etc.

Get-ADObject -Properties mail, proxyAddresses -Filter {mail -like "*emailportion*" -or proxyAddresses -like "*emailportion*"}

# Using a LDAP query to find the matching object
Get-ADObject -LDAPFilter "(|(mail=email@yourdomain.com)(proxyAddresses=smtp:email@yourdomain.com))"

# LDAP with wildcards

Get-ADObject -LDAPFilter "(|(mail=*emailportion*)(proxyAddresses=*emailportion*))"

# Using SIP 

Get-ADObject -Properties proxyAddresses -Filter {proxyAddresses -eq "sip:email@yourdomain.com"}

1 个答案:

答案 0 :(得分:0)

在你的场景中,你可以简单地睡几毫秒来限制你的FPS,而不是跟踪经过的时间,渲染帧等等,例如:

public void Run()
{
    window.Show();
    window.Focus();

    Initialize();

    isRunning = true;

    while (isRunning)
    {
        if (window.Focused)
        {
            Update();
            LateUpdate();
            Render();
            Thread.Sleep(16); // hard cap
        }
    }
}

然而,问题在于,直到睡眠,其余代码可能需要超过16毫秒;对此,您可以进行一些性能测量,并执行类似10ms的操作。

另一种方法是,让计时器保持活动状态如下:

public void Run()
{
    window.Show();
    window.Focus();

    Initialize();

    isRunning = true;

    long limit = 1000 / 60;

    while (isRunning)
    {
        if (window.Focused)
        {
            timer.Restart();
            Update();
            LateUpdate();
            Render();
            while (timer.ElapsedMilliseconds < limit) {
                Thread.Sleep(0);
            }
        }
    }
}

这避免了“硬”上限,同时还考虑到所有代码到睡眠时间超过16毫秒的事实,因此如果必要的时间已经过去,则不会进入“等待”循环。

此外,您要发布的代码需要考虑几点注意事项:

首先,如果您没有使用任何Windows窗体元素(例如PictureBoxButtonTextBox等),而是将所有元素绘制为自己(例如调用类似于Graphics.DrawLine等),您无需拨打Application.DoEvents;这样做会导致调用线程等待,直到处理完所有其他Windows窗体消息,从而减慢了渲染循环。如果确实需要致电Application.DoEvents,最好在Render()之后执行此操作,以便在您的帧限制中包含该函数调用时间。

最后,在非实时Windows系统上指定Thread.Sleep小于approximately 20 milliseconds的任何内容时,Sleep可能会因为时间而实际上睡眠时间更长专用于Windows系统上的线程的片。因此Thread.Sleep(1) 可能睡眠1毫秒, OR 它可能会睡眠6毫秒;如果时间上限已经是14毫秒,那么6毫秒的睡眠会使你的总时间超过20毫秒,从而降低你的帧速率。

指定0毫秒的休眠时,将调用线程的剩余时间片释放到另一个准备运行的优先级相同的线程;如果没有其他线程准备好,则调用线程继续(所以0-1毫秒的等待,而不是6+)。您也可以使用Thread.Yield,但这与内核级别的Sleep大不相同。

希望可以提供帮助。