我正在嘗試爲我的程序(C++ Win32)實現FPS和DeltaTime。以下是我現有的代碼。 FPS和DeltaTime應該以正確的方式實施。如果沒有,請告訴我如何解決我的問題。C++ Win32 FPS和DeltaTime實現
我面臨的當前問題是我應該如何使用DeltaTime。這是更新和渲染。是的,我確實使用了一個包裝類。 在我實現這個之前,我使用WindowProcedure來處理我的消息,我沒有問題。但是現在,試圖實現這一點正在讓我傾斜。所以在我使用後臺緩衝區和WM_PAINT進行繪製之前,我必須在hwnd中繪製。並且通過來自WindowProcedure的輸入進行更新,該輸入必須接受像LPARAM和WPARAM這樣的參數。但在閱讀了關於此主題的文章和論壇之後。更新和渲染是必要的,但他們並不需要在渲染方法中使用hwnd。至於更新,他們並沒有採取。
所以基本上我只想知道如何編寫更新和渲染方法?
bool BaseWindow::HandleMessages() {
// Counts Per Second
INT64 counts_per_sec = 0;
QueryPerformanceFrequency((LARGE_INTEGER*) &counts_per_sec);
// Seconds Per Count
float sec_per_count = 1.0f/(float) counts_per_sec;
// Pervious Time
INT64 prev_time = 0;
QueryPerformanceCounter((LARGE_INTEGER*) &prev_time);
MSG message = { 0 };
if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&message);
DispatchMessage(&message);
if (message.message == WM_QUIT) {
OnDestroy();
return false;
}
}
else {
// Get current count
INT64 current_time = 0;
QueryPerformanceCounter((LARGE_INTEGER*) ¤t_time);
// DeltaTime
float delta_time = (current_time - prev_time) * sec_per_count;
// Update
// Render
}
return true;
}
更新 Main.cpp的
#include "BaseWindow.h"
#include "ChildWindow.h"
int APIENTRY WinMain(HINSTANCE h_instance, HINSTANCE h_prev_instance, LPSTR lp_cmd_line, int n_cmd_show) {
ChildWindow child_window(h_instance, TEXT("Child Window"));
BaseWindow base_window(TEXT("Base Window"), child_window.ClassName());
while (base_window.HandleMessages());
return 0;
}
AbstractWindow.h
#ifndef __ABSTRACTWINDOW_H__
#define __ABSTRACTWINDOW_H__
#pragma once
#include <Windows.h>
class AbstractWindow {
#pragma region Methods
public:
AbstractWindow();
~AbstractWindow();
virtual bool Create();
static LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);
protected:
virtual LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM) = 0;
#pragma endregion
#pragma region Variables
protected:
HWND hwnd_;
DWORD style_ex_;
LPCTSTR class_name_;
LPCTSTR window_name_;
DWORD style_;
int x_;
int y_;
int width_;
int height_;
HWND parent_;
HMENU menu_;
HINSTANCE instance_;
#pragma endregion
};
#endif // !__ABSTRACTWINDOW_H__
AbstractWindow.cpp
#include "AbstractWindow.h"
AbstractWindow::AbstractWindow() {}
AbstractWindow::~AbstractWindow() {}
bool AbstractWindow::Create() {
// Default Create Method
hwnd_ = CreateWindowEx(
style_ex_,
class_name_,
window_name_,
style_,
x_,
y_,
width_,
height_,
parent_,
menu_,
instance_,
this
);
return (hwnd_ ? true : false);
}
LRESULT CALLBACK AbstractWindow::MessageHandler(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param) {
AbstractWindow* abstract_window = 0;
if (message == WM_NCCREATE) {
abstract_window = (AbstractWindow*) ((LPCREATESTRUCT(l_param))->lpCreateParams);
SetWindowLong(hwnd, GWL_USERDATA, long(abstract_window));
}
abstract_window = (AbstractWindow *) (GetWindowLong(hwnd, GWL_USERDATA));
if (abstract_window) {
return abstract_window->WindowProcedure(hwnd, message, w_param, l_param);
}
else {
return DefWindowProc(hwnd, message, w_param, l_param);
}
}
BaseWindow.h
#ifndef __BASEWINDOW_H__
#define __BASEWINDOW_H__
#pragma once
#include "AbstractWindow.h"
#include "ChildWindow.h"
class BaseWindow : public AbstractWindow {
#pragma region Test Methods
private:
void Update();
void Render();
#pragma endregion
#pragma region Methods
public:
BaseWindow();
~BaseWindow();
bool HandleMessages();
BaseWindow(const TCHAR*, const TCHAR*);
void Show();
virtual LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
#pragma region Handles
private:
bool CreateBackBuffer(HWND);
bool OnPaint(HWND);
bool PaintManager();
bool OnDestroy();
#pragma endregion
#pragma endregion
#pragma region Variables
private:
RECT window_rect_; // Structure for window width and height
int client_width_;
int client_height_;
POINT mouse_pos_;
#pragma region Back Buffer
HDC hdc_; // Handle to Device Context
HDC back_buffer_; // Back Buffer
HBITMAP bitmap_; // Current bitmap
#pragma endregion
#pragma endregion
};
#endif // !__BASEWINDOW_H__
BaseWindow.cpp
#include "BaseWindow.h"
BaseWindow::BaseWindow() {}
BaseWindow::~BaseWindow() {}
BaseWindow::BaseWindow(const TCHAR* window_name, const TCHAR* class_name) {
style_ex_ = NULL;
class_name_ = class_name;
window_name_ = window_name;
style_ = WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
x_ = CW_USEDEFAULT;
y_ = CW_USEDEFAULT; CW_USEDEFAULT;
width_ = CW_USEDEFAULT;
height_ = CW_USEDEFAULT;
parent_ = NULL;
menu_ = NULL;
instance_ = GetModuleHandle(NULL);
Create();
Show();
}
void BaseWindow::Show() {
ShowWindow(hwnd_, SW_SHOW);
UpdateWindow(hwnd_);
}
LRESULT CALLBACK BaseWindow::WindowProcedure(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param) {
switch (message) {
case WM_CREATE:
CreateBackBuffer(hwnd);
return true;
case WM_ERASEBKGND:
return true;
case WM_DESTROY:
return OnDestroy();
default:
return DefWindowProc(hwnd, message, w_param, l_param);
}
}
bool BaseWindow::HandleMessages() {
// Counts Per Second
INT64 counts_per_sec = 0;
QueryPerformanceFrequency((LARGE_INTEGER*) &counts_per_sec);
// Seconds Per Count
float sec_per_count = 1.0f/(float) counts_per_sec;
// Pervious Time
INT64 prev_time = 0;
QueryPerformanceCounter((LARGE_INTEGER*) &prev_time);
MSG message = { 0 };
if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&message);
DispatchMessage(&message);
if (message.message == WM_QUIT) {
OnDestroy();
return false;
}
}
else {
// Get current count
INT64 current_time = 0;
QueryPerformanceCounter((LARGE_INTEGER*) ¤t_time);
// DeltaTime
float delta_time = (current_time - prev_time) * sec_per_count;
// Update
// Render
// I need to call for OnPaint()
// I need to take in hwnd
// But how ?
// Or do i not take in hwnd ?
// But hoe ?
}
return true;
}
#pragma region Handles
bool BaseWindow::CreateBackBuffer(HWND hwnd) {
GetClientRect(hwnd, &window_rect_);
client_width_ = window_rect_.right;
client_height_ = window_rect_.bottom;
back_buffer_ = CreateCompatibleDC(NULL); // Create Back Buffer
hdc_ = GetDC(hwnd); // Get the Device Context
bitmap_ = CreateCompatibleBitmap(hdc_, client_width_, client_height_); // Create Bitmap
SelectObject(back_buffer_, bitmap_); // Select Bitmap
ReleaseDC(hwnd, hdc_); // Release
return true;
}
bool BaseWindow::OnPaint(HWND hwnd) {
PAINTSTRUCT paint_struct;
hdc_ = BeginPaint(hwnd_, &paint_struct); // Get the Device Context
BitBlt(back_buffer_, 0, 0, client_width_, client_height_, NULL, NULL, NULL, WHITENESS);
// Paint
PaintManager();
BitBlt(hdc_, 0, 0, client_width_, client_height_, back_buffer_, 0, 0, SRCCOPY); // Display the back buff
InvalidateRect(hwnd, NULL, true); // Repaint the screen
EndPaint(hwnd, &paint_struct);
return true;
}
bool BaseWindow::PaintManager() {
HBRUSH brush = (HBRUSH) (GetStockObject(WHITE_BRUSH));
SelectObject(back_buffer_, brush); // Select Brush
Rectangle(back_buffer_, 200, 200, 500, 500);
DeleteObject(brush);
return true;
}
bool BaseWindow::OnDestroy() {
PostQuitMessage(0);
return true;
}
#pragma endregion
ChildWindow.h
#ifndef __CHILDWINDOW_H__
#define __CHILDWINDOW_H__
#pragma once
#include "AbstractWindow.h"
#include "BaseWindow.h"
class ChildWindow : protected WNDCLASSEX {
#pragma region Methods
public:
ChildWindow();
~ChildWindow();
ChildWindow(HINSTANCE, const TCHAR*);
bool Register();
const TCHAR* ClassName() const;
#pragma endregion
};
#endif // !__CHILDWINDOW_H__
ChildWindow.cpp
#include "ChildWindow.h"
ChildWindow::ChildWindow() {}
ChildWindow::~ChildWindow() {}
ChildWindow::ChildWindow(HINSTANCE h_instance, const TCHAR* class_name) {
cbSize = sizeof(WNDCLASSEX);
style = NULL;
lpfnWndProc = AbstractWindow::MessageHandler;
cbClsExtra = NULL;
cbWndExtra = NULL;
hInstance = h_instance;
hIcon = LoadIcon(NULL, IDI_APPLICATION);
hCursor = LoadCursor(NULL, IDC_ARROW);
//hbrBackground = (HBRUSH) (GetStockObject(DKGRAY_BRUSH));
hbrBackground = (HBRUSH) NULL;
lpszMenuName = NULL;
lpszClassName = class_name;
hIconSm = LoadIcon(NULL, IDI_APPLICATION);
Register();
}
bool ChildWindow::Register() {
return ((RegisterClassEx(this)) ? true : false);
}
const TCHAR* ChildWindow::ClassName() const {
return lpszClassName;
}