C++ 时间类问题
我正在设计一个时间类,它只在预定义的时间之后执行一个操作,但我仍然无法找到重置时间的方法。这是将时间重置为零还是暂时停止并恢复时间 所以,我的目标是每次满足条件A时重置时间,这样它就不会破坏delayTime函数,因为它仍然保留以前的时间,并最终导致错误的时间计算C++ 时间类问题,c++,winapi,timer,C++,Winapi,Timer,我正在设计一个时间类,它只在预定义的时间之后执行一个操作,但我仍然无法找到重置时间的方法。这是将时间重置为零还是暂时停止并恢复时间 所以,我的目标是每次满足条件A时重置时间,这样它就不会破坏delayTime函数,因为它仍然保留以前的时间,并最终导致错误的时间计算 if ( condition A ) { if ( time.delayTime( 5.0f ) ) { doActionA(); } } TimeClass.h #if
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
标准库 如前所述,只需使用。如果使用Visual C++编译器,则在HealSyrasePrimeCalk的分辨率上是实际的,它的强> > < /强>与QueRealExcCeCurter相同。 示例
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();
另一种方法是使用捕获状态和更新方法。正如我所看到的,你正在将其用于游戏,因此更新可以在游戏的更新方法中完成。假设事件具有类似{Active,Inactive}的状态,并且在经过的时间内有一个成员,那么每次调用update时,如果状态为Active,则添加自上次更新调用以来经过的时间。因此,ready函数只检查经过的时间是否大于定义的阈值
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;
}
};
类事件{
std::chrono::高分辨率时钟::时间点lastUpdateCall;
双时差;
双延时;
布尔活跃;
公众:
事件(双时间间隔事件)
:timeBetweenEvents(timeBetweenEvents)
,lastUpdateCall(std::chrono::high_resolution_clock::now())
,elapsedTime(0.0)
,活动(真){}
bool ready(){
return elapsedTime>=事件之间的时间;
}
无效重置(){
elapsedTime=0.0;
}
无效设置活动(布尔状态){
活动=状态;
}
无效更新(){
auto currentTime=std::chrono::高分辨率时钟::now();
如果(活动){
auto dt=std::chrono::duration_cast(currentTime-lastUpdateCall).count();
elapsedTime+=dt;
}
lastUpdateCall=当前时间;
}
};
从您的问题来看,不太清楚您到底想要实现什么:时钟重置、暂停/恢复、间隔测量或定时触发器,或者所有这些。因此,我将描述所有这些
我只是想说清楚
- 不要在成员函数(方法)中使用静态变量,这会使代码更难理解且容易出错。而是使用类成员变量(字段)
- 不要以(毫秒)秒
格式存储时间。我的精确度太低了。不建议使用双倍float
。相反,以API本机格式存储它:某种CPU标记:让我们将其包装在double
中,并仅在用户要求时转换为struct time\u point
:float
struct time_point { LARGE_INTEGER value; };
- 获取当前时间的函数:让我们调用它
private: time_point now(); // Here you wrap QueryPerformanceCounter() or `boost::chrono::...::now();` stuff
- 用于将两个
时间点之间的差异(持续时间)重新解释为可用单位的函数(例如纳秒
的(毫秒)秒长
)浮点
时间点
设为类,并将此函数设为成员)
所有其他函数都可以是API不可知的
按照此设计,您可以从用户抽象出底层API,并使您的应用程序更具可移植性
重置
还是要把时间重置为零
但是,等等,您已经实现了“将时间重置为零”:
(timeAtGameStart=0;
注释为不需要)
您刚才说的start
是now()
,所以start
和now()
之间的差异变为零
停止和恢复
还是暂时停止并恢复时间
您可以通过以下方式实现“时间停止/恢复”效果:
- 添加
成员变量(不要忘记在构造函数中将其初始化为bool isPaused
)false
- 添加
成员变量(时间单位类型:timePaused
,在我的例子中)time\u point
- 更改
函数:暂停时,它将返回getGameTime()
,而不是当前时间timePaused
- 当然,还引入了
函数Pause()/Resume()
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();
}
}
设计秒表的另一种可能方法是:
- 从
时钟继承
- 将当前时间传递给
以便无需IsAboutTime()
Update()
快乐编码!=) 有一个标准的
标题,您正在使用。您可以添加暂停/播放功能。暂停保留暂停时间,播放添加(播放按时间-暂停时间)开始时间您能告诉我如何设计暂停和播放时间功能吗?我仍然不熟悉Windows API。你有Windows API解决方案吗?谢谢。你想用Windows API替换哪个部分?其中大部分是纯逻辑的,与API无关。只有通过直接使用QueryPerformanceCounter才能完成时间测量,就像您已经完成的那样。当然,您可以使用,但这主要是为在线程之间使用而设计的,因此不是作为
private:
float Duration(const time_point& from, const time_point& to); // Here you divide by frequence
void TimeClass::reset()
{
//timeAtGameStart = 0;
timeAtGameStart = getGameTime();
}
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()
}
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();
}
}