我一直在将我的游戏从C ++转换为C#。我很好奇计时器是如何使用C#缺少QueryPerformanceFrequency()和QueryPerformanceCounter()的,因为我需要总时间和delta。如何使用我以前的函数将代码转换为C#?
我将逐节介绍这一部分:
我正在使用这个用于C ++的计时器代码:
#include "HPTimer.h"
/// <summary>
/// HP Timer constructor
/// </summary>
HPTimer::HPTimer()
{
init();
}
/// <summary>
/// Initializes the timer
/// </summary>
void HPTimer::init()
{
LARGE_INTEGER t;
QueryPerformanceFrequency(&t);
m_frequency = t.QuadPart;
reset();
}
/// <summary>
/// Sets the current time.
/// </summary>
void HPTimer::reset()
{
LARGE_INTEGER t;
QueryPerformanceCounter(&t);
m_startTime = t.QuadPart;
m_currentCallToUpdate = t.QuadPart;
m_lastCallToUpdate = t.QuadPart;
}
/// <summary>
/// Updates the timer so it's current.
/// </summary>
void HPTimer::update()
{
LARGE_INTEGER t;
m_lastCallToUpdate = m_currentCallToUpdate;
QueryPerformanceCounter(&t);
m_currentCallToUpdate = t.QuadPart;
}
/// <summary>
/// Gets the total time since reset was called.
/// </summary>
/// <returns>Returns the total time.</returns>
double HPTimer::getTimeTotal()
{
double d;
d = m_currentCallToUpdate - m_startTime;
return d / m_frequency;
}
/// <summary>
/// Gets the difference between two calls of update.
/// </summary>
/// <returns>Returns the delta time.</returns>
double HPTimer::getTimeDelta()
{
double d;
d = m_currentCallToUpdate - m_lastCallToUpdate;
return d / m_frequency;
}
Microsoft的解决方案如下: https://msdn.microsoft.com/en-us/library/ff650674.aspx
// QueryPerfCounter.cs
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
public class QueryPerfCounter
{
[DllImport("KERNEL32")]
private static extern bool QueryPerformanceCounter(
out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
private long start;
private long stop;
private long frequency;
Decimal multiplier = new Decimal(1.0e9);
public QueryPerfCounter()
{
if (QueryPerformanceFrequency(out frequency) == false)
{
// Frequency not supported
throw new Win32Exception();
}
}
public void Start()
{
QueryPerformanceCounter(out start);
}
public void Stop()
{
QueryPerformanceCounter(out stop);
}
public double Duration(int iterations)
{
return ((((double)(stop - start)* (double) multiplier) / (double) frequency)/iterations);
}
}
虽然这看起来很有效,但它缺少我之前使用的一些部分:LARGE_INTEGER,QuadPart,获取总时间,并获得时间增量。在微软的代码中,他们有这个'迭代'的论点,我很困惑。有没有一种方法可以在使用我之前的函数时转换我的代码?
编辑: 我很好奇LARGE_INTEGER / QuadPart。我去了这里: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383713(v=vs.85).aspx 我猜LARGE_INTEGER在C#的世界中确实很长(64位)。所以t.QuadPart被视为out long值,对吗?
更新: 在查看答案后,我进行了以下转换(但仍需要确认)
public class HPTimer
{
private long m_startTime;
private long m_lastCallUpdate;
private long m_currentCallToUpdate;
private long m_frequency;
private Stopwatch m_stopWatch;
/// <summary>
/// HP Timer constructor
/// </summary>
public HPTimer()
{
Init();
}
/// <summary>
/// Initializes the timer
/// </summary>
public void Init()
{
m_stopWatch = Stopwatch.StartNew();
m_frequency = Stopwatch.Frequency;
Reset();
}
/// <summary>
/// Resets the current time.
/// </summary>
public void Reset()
{
m_startTime = Stopwatch.GetTimestamp();
m_currentCallToUpdate = Stopwatch.GetTimestamp();
m_lastCallUpdate = Stopwatch.GetTimestamp();
}
/// <summary>
/// Updates the timer so it's current.
/// </summary>
public void Update()
{
m_lastCallUpdate = m_currentCallToUpdate;
m_currentCallToUpdate = Stopwatch.GetTimestamp();
}
/// <summary>
/// Gets the total time since reset was called.
/// </summary>
/// <returns>Returns the total time.</returns>
public double GetTotalTime()
{
double d;
d = m_currentCallToUpdate - m_startTime;
return d / m_frequency;
}
/// <summary>
/// Gets the difference between two calls of update.
/// </summary>
/// <returns>Returns the delta time.</returns>
public double GetTimeDelta()
{
double d;
d = m_currentCallToUpdate - m_lastCallUpdate;
return d / m_frequency;
}
}
答案 0 :(得分:2)
你有什么理由不能使用Stopwatch
吗?它通常会使用高性能计数器(有static field告诉你它是否使用高性能计数器)。
您只需创建一个Stopwatch
,然后在每次更新时记录其Elapsed
属性。它的类型TimeSpan
会超载减法,因此您可以轻松获得增量。
答案 1 :(得分:1)
您可以使用Stopwatch
代替非托管Win32 API来记录时间。示例:
//Equivalent to:
//Stopwatch stopWatch = new Stopwatch();
//stopWatch.Start();
Stopwatch stopWatch = Stopwatch.StartNew();
//Operation you want to measure
stopWatch.Stop();
//Timespan is a struct to hold time related info..
//e.g: Days, Hours, Seconds, Milliseconds, Ticks and TotalDays... etc
Timespan ts = stopWatch.Elapsed;
//Or you can simply get the time elapsed in milliseconds like this
long elapsed = stopWatch.ElapsedMilliseconds;
//QueryPerformanceFrequency
long frequency = Stopwatch.Frequency;
//QueryPerformanceCounter
long ticks = Stopwatch.GetTimestamp();
关于LARGE_INTEGER的其他问题。根据{{3}},它的C#等价物应该是:
//Specify struct size and field offsets by ourselves
[StructLayout(LayoutKind.Explicit, Size = 8)]
struct LARGE_INTEGER
{
[FieldOffset(0)]
public uint LowPart;
[FieldOffset(4)]
public int HighPart;
[FieldOffset(0)]
public long QuadPart;
}