我正在设计一个时间类,它只会在预定义的时间后执行操作,但我仍然无法找到重置时间的方法。无论如何将时间重置为零或暂时停止并恢复时间?
所以,我的目标是每次条件A遇到时重置时间,以便它不会搞砸delayTime函数,它仍然保持前一次并结束错误的时间计算。
if ( condition A )
{
if ( time.delayTime( 5.0f ) )
{
doActionA();
}
}
TimeClass.h
#ifndef _TIMECLASS_H_
#define _TIMECLASS_H_
#include <windows.h>
class TimeClass
{
public:
TimeClass();
~TimeClass();
bool delayTime( float second );
float getSecond();
void reset();
private:
float getGameTime();
float currentTime;
UINT64 ticks;
float time;
float timeAtGameStart;
UINT64 ticksPerSecond;
};
#endif
TimeClass.cpp
#include "TimeClass.h"
TimeClass::TimeClass()
{
// We need to know how often the clock is updated
if( !QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond) )
ticksPerSecond = 1000;
// If timeAtGameStart is 0 then we get the time since
// the start of the computer when we call GetGameTime()
timeAtGameStart = 0;
timeAtGameStart = getGameTime();
}
float TimeClass::getGameTime()
{
// This is the number of clock ticks since start
if( !QueryPerformanceCounter((LARGE_INTEGER *)&ticks) )
ticks = (UINT64)timeGetTime();
// Divide by frequency to get the time in seconds
time = (float)(__int64)ticks/(float)(__int64)ticksPerSecond;
// Subtract the time at game start to get
// the time since the game started
time -= timeAtGameStart;
return time;
}
bool TimeClass::delayTime( float second )
{
currentTime = getGameTime();
static float totalTime = second + getGameTime();
if ( currentTime >= totalTime )
{
totalTime = second + getGameTime();
return true;
}
else
{
return false;
}
}
float TimeClass::getSecond()
{
currentTime = getGameTime();
static float totalTime = 1 + getGameTime();
if ( currentTime >= totalTime )
{
totalTime = 1 + getGameTime();
return currentTime;
}
else
{
return currentTime;
}
}
void TimeClass::reset()
{
timeAtGameStart = 0;
timeAtGameStart = getGameTime();
}
TimeClass::~TimeClass()
{
}
答案 0 :(得分:2)
标准图书馆
如上所述,只需使用std::chrono::high_resolution_clock即可。如果使用Visual C ++编译器,则high_resolution_clock的分辨率实际为bug report,而 NOT 与QueryPerformanceCounter相同。
示例强>
auto t1 = std::chrono::high_resolution_clock::now();
// Do something
auto t2 = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);
double dt = duration.count();
<强> TimeClass 强>
您现在面临的主要问题是您使用的是静态变量。您正在寻找一种方法来重置除delayTime之外的另一个函数的静态变量。如果你要引入成员变量去除静态变量,它会使事情变得容易很多(注意:函数中的静态变量是不好的做法,因为它们保持状态=&gt;对多线程不好)。那么这样的事情呢?
class Event {
std::chrono::high_resolution_clock::time_point lastEventOccurred;
double timeBetweenEvents;
public:
Event(double timeBetweenEvents)
: timeBetweenEvents(timeBetweenEvents)
, lastEventOccurred(std::chrono::high_resolution_clock::now()) { }
bool ready() {
auto currentTime = std::chrono::high_resolution_clock::now();
auto elapsedTime = std::chrono::duration_cast<std::chrono::duration<double>>(currentTime - lastEventOccurred).count();
if(elapsedTime > timeBetweenEvents) {
reset();
return true;
} else
return false;
}
void reset() {
lastEventOccurred = std::chrono::high_resolution_clock::now();
}
};
用法:
Event evtDelay = Event(5.0);
if(condition A) {
if(evtDelay.ready()) {
doActionA();
}
} else if(condition B) {
evtDelay.reset();
}
另一种方法是使用捕获状态和更新方法。我可以看到你正在将它用于游戏,因此可以在游戏的更新方法中进行更新。假设事件将具有{Active,Inactive}状态和已用时间的成员,则每次调用update时,如果状态为Active,则添加自上次更新调用以来经过的时间。因此,就绪功能仅检查经过的时间是否大于定义的阈值。
class Event {
std::chrono::high_resolution_clock::time_point lastUpdateCall;
double timeBetweenEvents;
double elapsedTime;
bool active;
public:
Event(double timeBetweenEvents)
: timeBetweenEvents(timeBetweenEvents)
, lastUpdateCall(std::chrono::high_resolution_clock::now())
, elapsedTime(0.0)
, active(true) { }
bool ready() {
return elapsedTime >= timeBetweenEvents;
}
void reset() {
elapsedTime = 0.0;
}
void setActive(bool state) {
active = state;
}
void update() {
auto currentTime = std::chrono::high_resolution_clock::now();
if(active) {
auto dt = std::chrono::duration_cast<std::chrono::duration<double>>(currentTime - lastUpdateCall).count();
elapsedTime += dt;
}
lastUpdateCall = currentTime;
}
};
答案 1 :(得分:1)
从您的问题来看,目前还不清楚您想要实现的目标:时钟重置,暂停/恢复,间隔测量或定时触发,或所有这些。所以我将描述所有这些。 =)
不要以(毫秒)float
格式存储时间。我的精度太低了。甚至不建议使用double
。相反,将其存储为API原生格式:某种CPU滴答:让我们将其包装在struct time_point
中,并仅在用户请求时转换为float
:
struct time_point
{
LARGE_INTEGER value;
};
您需要从基础API获得的功能是:
获取当前时间的功能:让我们称之为
private:
time_point now(); // Here you wrap QueryPerformanceCounter() or `boost::chrono::...::now();` stuff
用于重新解释两个time_point
到可用单位之间的差异(持续时间)(例如纳秒long long
(毫秒)float
)
private:
float Duration(const time_point& from, const time_point& to); // Here you divide by frequence
(另外,你可以让time_point
类成为这个函数的成员)
所有其他功能都可以与API无关。
遵循此设计,您可以从用户中抽象出底层API,并使您的应用程序更具可移植性。
无论如何都要将时间重置为零
但是,等等,你已经实现了“将时间重置为零”:
void TimeClass::reset()
{
//timeAtGameStart = 0;
timeAtGameStart = getGameTime();
}
(timeAtGameStart = 0;
评论,因为它不需要)
您只是说start
为now()
,因此start
和now()
之间的差异变为零。
或暂时停止并恢复时间?
您可以通过以下方式实现“时间停止/恢复”效果
bool isPaused
成员变量(不要忘记在构造函数中将其初始化为false
)timePaused
成员变量(您的时间单位的类型:time_point
在我的情况下)getGameTime()
功能:暂停时会返回timePaused
而不是当前时间Pause()/Resume()
个功能以下是示例代码(命名与您的名称略有不同)
void Pause()
{
if (!isPaused)
{
timePaused = clock::now();
isPaused = true;
}
}
void Resume()
{
if (isPaused)
{
isPaused = false;
start -= clock::now() - timePaused;
}
}
float Now() const
{
if (isPaused)
{
return Duration(start, timePaused);
}
return Duration(start, clock::now()); // basically it is your getGameTime()
}
有时您会想知道程序中某些地方之间经过了多长时间。例如,要在游戏中测量FPS,您需要知道帧之间的增量时间。 为实现这一点,我们需要成员:
time_point prevTick; // time of previous tick
time_point currTick; // time of current tick
void Tick() // user must call it each frame
{
prevTick = currTick;
currTick = clock::now();
}
const float GetDelta() const // user must call it to know frame time
{
return Duration(prevTick, currTick);
}
现在,我们需要一些定时触发器。将此触发器与计时器分开是个好主意,所以:
所以让我们将它包装到课堂上:
class Stopwatch
{
private:
float m_Interval;
float m_Time;
float m_PrevTime;
public:
Stopwatch(float interval_ms = 1000.0f) :
m_Interval(interval_ms),
m_Time(0.0f),
m_PrevTime(m_Time)
{}
float GetRefreshInterval() const { return m_Interval; }
void SetRefreshInterval(float interval_ms) { m_Interval = interval_ms; }
// Update as frequent as possible
inline void Update(float dt)
{
m_Time += dt;
}
// Check if time interval reached
inline bool IsAboutTime()
{
if (m_Time >= m_Interval)
{
m_PrevTime = m_Time;
m_Time = 0.0f;
return true;
}
return false;
}
// exact value of last interval
inline float GetLastTime() const
{
return m_PrevTime;
}
};
用法示例:
Stopwatch stopwatch(5000.0f); // will trigger each 5 seconds
...
stopwatch.Update(timer.GetDelta()); // GetDelta() returns time difference between update frames
if ( condition A )
{
if ( stopwatch.IsAboutTime() )
{
doActionA();
}
}
设计秒表的另一种可能方法是:
clock
IsAboutTime()
,因此无需Update()
快乐的编码! =)