【Game Engine】第三节:Clock帧计时器 && DLL链接 && 键盘按键事件

本文详细介绍了在游戏开发中如何使用自定义的Clock类来优化帧同步,避免画面卡顿,通过精确计算每帧时间差,实现平滑的游戏画面更新。文章深入探讨了Clock类的实现原理,包括如何利用LARGE_INTEGER类型和系统API如QueryPerformanceFrequency和QueryPerformanceCounter来获取系统时钟周期,以及如何计算帧间的时间差。

Clock帧计时器

  • 目的

    • 使用Qtime循环调用myUpdate来刷新帧画面时,帧数非固定,若每两帧之间的计算量相差较大,会出现两帧之间卡顿,使得画面停滞,需要利用帧计时来优化计算
  • 原理

    • 统计连续两帧之间的时钟周期数量,除以当前的每秒时钟周期数,可获得相邻两帧的差时
  • Clock类

#include <Windows.h>
namespace Time {
	class __declspec(dllexport) Clock {			//生成lib文件
	private:
		LARGE_INTEGER lastFrameCounter;			//上一帧周期数
		LARGE_INTEGER deltaCounter;				//差值周期数
		float deltaTime;						//差值时间
	public:
		LARGE_INTEGER nowPerformanceFrequency;	//每秒周期数
		bool clockInitialize();					//clock初始化
		bool clockGetNewFrame();				//获取新一帧
		float clockTimeLastFrame();				//获取帧差值时间
		bool clockShutdown();					//clock关闭
	};
}
  • API

    • LARGE_INTEGER
      • 大整数Union,64位整数,一位符号位
      • LargeInteger.QuadPart:__int64
    • bool QueryPerformanceFrequency(LARGE_INTEGER *frequncy)
      • 查询当前系统每秒周期数
      • 成功返回1,系统无法查询返回0,存在于frequncy
    • bool QueryPerformanceCounter(LARGE_INTEGER *performanceCount)
      • 查询当前指令所在周期数
      • 成功返回1,系统无法查询返回0,存在于performanceCount
  • 实现

#include "Clock.h"
namespace Time {

	bool Clock::clockInitialize() {
		bool errorCode = QueryPerformanceFrequency(&nowPerformanceFrequency);
		deltaTime = 0;
		lastFrameCounter.QuadPart = 0;
		return errorCode;
	}

	bool Clock::clockGetNewFrame() {
		LARGE_INTEGER nowFrameCounter;
		bool errorCode = QueryPerformanceCounter(&nowFrameCounter);
		if (!errorCode) return false;
		deltaCounter.QuadPart = nowFrameCounter.QuadPart - lastFrameCounter.QuadPart;
		if (lastFrameCounter.QuadPart != 0) 
			deltaTime = ((float)deltaCounter.QuadPart) / nowPerformanceFrequency.QuadPart;
		lastFrameCounter.QuadPart = nowFrameCounter.QuadPart;
		return true;
	}

	float Clock::clockTimeLastFrame() {
		return deltaTime;
	}

	bool Clock::clockShutdown() {
		return true;
	}
}
  • 应用

void MyGlWindow::myUpdate() {
	myClock.clockGetNewFrame();
	float frameTime = myClock.clockTimeLastFrame();
	Velocity = Vector2D(0.1f,0.1f);
	shipPosition = shipPosition + frameTime*Velocity;  
	repaint();
}

//myTimer.start(17);  六十帧每秒

DLL链接

  • 目的

    • Vector2D实现使用的是包含inl文件,实质上只有.h,不存在编译问题
    • Clock中使用了.cpp,需要对engine项目进行编译生成,需要生成动态链接库给其他项目
  • 实现

    • 解决方案属性->设置项目依赖
    • engine属性->配置类型:dll
    • sandbox属性:配置lib与include目录
    • sandbox添加生成事件,将engine.dll拷贝到sandbox的debug目录中

键盘按键事件

  • QT键盘事件

    • 不易处理同时按下两按键
  • Windows键盘事件

    • API
      • short GetAsyncKeyState(int vKey)
        • 返回值非空为按vKey键信号
        • vKey为VK_按键名
    • 实现
void MyGlWindow::myCheckKeyState() {
	const float ACCERALATION = 0.08f * myClock.clockTimeLastFrame();
	if (GetAsyncKeyState(VK_UP))
		shipVelocity.y += ACCERALATION;
	if (GetAsyncKeyState(VK_DOWN))
		shipVelocity.y -= ACCERALATION;
	if (GetAsyncKeyState(VK_RIGHT))
		shipVelocity.x += ACCERALATION;
	if (GetAsyncKeyState(VK_LEFT))
		shipVelocity.x -= ACCERALATION;
	if (GetAsyncKeyState(VK_SPACE))
		shipVelocity.x = 0, shipVelocity.y = 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值