Windows — 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* ) &current_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* ) &current_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;
}

0

Решение

Я уже отвечал на это раньше, но вы проигнорировали мои комментарии. Вы не должны звонить InvalidateRect от WM_PAINT, Вы должны удалить InvalidateRect от OnPaint,

Ваш OnPaint функция даже не вызывается. Вы должны добавить эту строку:

case WM_PAINT:
OnPaint();
return 0;

Вы делаете странные вещи внутри основного цикла сообщений. Это очень опасно. Просто удали HandleMessages в целом. Замените его простым циклом сообщений:

int APIENTRY WinMain(HINSTANCE h_instance, HINSTANCE, LPSTR, int)
{
ChildWindow child_window(h_instance, TEXT("Child Window"));
BaseWindow base_window(TEXT("Base Window"), child_window.ClassName());

//main message loop
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return 0;
}

Оставьте основной цикл сообщений в покое. Позже вы можете обрабатывать ускорители внутри цикла сообщений, но это все.

Теперь допустим, что вы хотите добавить анимацию. Во-первых, давайте начнем с простой анимации. Объявить глобальную переменную int g_counter = 0; Тогда поменяй PaintManager вот так:

bool BaseWindow::PaintManager()
{
HBRUSH brush = (HBRUSH)(GetStockObject(WHITE_BRUSH));
SelectObject(back_buffer_, brush);      // Select Brush
Rectangle(back_buffer_, 200, 200, 500, 500);
DeleteObject(brush);

TCHAR buf[100];
wsprintf(buf, TEXT("%d"), g_counter);
TextOut(back_buffer_, 0, 0, buf, strlen(buf));

return true;
}

Добавьте что-то для анимации сигнала:

case WM_LBUTTONDOWN:
animate();
return 0;

Сделать анимацию функцией:

void BaseWindow::animate()
{
for (int i = 0; i < 10000; i++)
{
g_counter++;
InvalidateRect(hwnd_, 0, FALSE);

//this code allows window to refresh itself, use it as is
//don't mess around with it
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
PostQuitMessage(0);
return;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}

Вы можете установить таймер внутри for цикл, чтобы замедлить его … Вы также можете посмотреть на WM_TIMER если вам не нужны высокоточные таймеры.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]