使用 C++ Win32 实现重力翻转机制
Implementing gravity flipping mechanics using C++ Win32
我正在尝试想出一种将重力翻转机制实施到我的 C++ Win32 游戏中的有效方法。虽然我的语言不是很流利,所以我来问一下。
我有:
- 一个class,它存储播放器的属性(例如位置和大小,以及一些功能)。
- 一个消息路由器,接收从用户(和其他来源)发送的消息。
- 这些消息包括玩家输入。我处理消息路由器中的输入,然后调用播放器上的函数 class.
我被困在如何实现重力翻转机制上。这是一款免费的跑酷游戏。玩家向 window 的右侧奔跑,轻按一个键后,玩家角色将在正常(向下)重力或反转(向上)重力之间切换。
我考虑的方法是使用 do-while。这样做的问题是用户必须等到 do-while 完成。也就是说,如果玩家没有到达屏幕顶部,请继续向上移动(反重力)。
我考虑过其他方法,但我认为它们不值得尝试。它只会导致其他一些麻烦。
有什么建议吗?
提前致谢:)
更新
这是我一直在处理的代码,我必须解决的当前问题是一旦玩家到达屏幕底部或顶部。我似乎无法改变重力。但它允许我在玩家触及顶部或底部 window 边缘之前执行此操作。
这是为什么?
随时批评我的代码并告诉我如何改进我。
Main.cpp
#include "BaseWindow.h"
#include "GameWindow.h"
int APIENTRY WinMain ( HINSTANCE h_instance, HINSTANCE h_prev_instance, LPSTR lp_cmd_line, int n_cmd_show ) {
// Create the Game Window
GameWindow game_window ( h_instance, TEXT ( "GameWindow" ) );
game_window.Register ();
// Create the Base Window
BaseWindow base_window ( TEXT ( "BaseWindow" ), game_window.ClassName () );
base_window.Create ();
base_window.Show ();
// Pump Messages
MSG messages;
int status;
while ( ( status = GetMessage ( &messages, 0, 0, 0 ) ) != 0 ) {
if ( status == -1 ) {
// Break;
break;
}
TranslateMessage ( &messages );
DispatchMessage ( &messages );
}
return messages.wParam;
}
AbstractWindow.h
#pragma once
#ifndef __ABSTRACT_WINDOW_H__
#define __ABSTRACT_WINDOW_H__
#include <Windows.h>
class AbstractWindow {
public:
AbstractWindow ();
~AbstractWindow ();
virtual bool Create ();
static LRESULT CALLBACK MessageRouter ( HWND, UINT, WPARAM, LPARAM );
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 h_instance_;
LPVOID param_;
// Bitmap Variables - Start
// Stucture for thw Window width and height
RECT rect_;
// Handle to Device Context
HDC hdc_;
// Handle to Device Context - Back Buffer
HDC back_buffer_;
// Bitmap - Front
HBITMAP bitmap_; // Bitmap
// Bitmap Variables - End
// Default Handlers
virtual bool OnCreate ( HWND ) = 0;
virtual bool OnCommand ( int, int ) = 0;
virtual bool OnDestroy () = 0;
virtual bool OnPaint ( HWND, WPARAM ) = 0;
// Player Handlers
virtual bool UpdatePlayerPosition( HWND, WPARAM ) = 0;
};
#endif // !__ABSTRACT_WINDOW_H__
AbstractWindow.cpp
#include "AbstractWindow.h"
AbstractWindow::AbstractWindow () {}
AbstractWindow::~AbstractWindow () {}
bool AbstractWindow::Create () {
hwnd_ = CreateWindowEx (
style_ex_,
class_name_,
window_name_,
style_,
x_,
y_,
width_,
height_,
parent_,
menu_,
h_instance_,
this // Pointer to this class instance
);
if ( hwnd_ ) {
OnCreate(hwnd_);
return true;
}
return false;
}
LRESULT CALLBACK AbstractWindow::MessageRouter ( HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param ) {
AbstractWindow* abstract_window = 0;
static bool move = false;
if ( message == WM_NCCREATE ) {
abstract_window = ( AbstractWindow* ) ( ( LPCREATESTRUCT ( l_param ) )->lpCreateParams );
SetWindowLong ( hwnd, GWL_USERDATA, long ( abstract_window ) );
return DefWindowProc ( hwnd, message, w_param, l_param );
}
else {
abstract_window = ( AbstractWindow* ) ( GetWindowLong ( hwnd, GWL_USERDATA ) );
if ( abstract_window ) {
switch ( message ) {
case WM_COMMAND:
return abstract_window->OnCommand ( LOWORD ( w_param ), HIWORD ( w_param ) );
case WM_DESTROY:
return abstract_window->OnDestroy ();
case WM_PAINT:
return abstract_window->OnPaint ( hwnd, w_param);
case WM_KEYDOWN:
return abstract_window->UpdatePlayerPosition( hwnd, w_param );
default:
return DefWindowProc ( hwnd, message, w_param, l_param );
}
}
else {
return DefWindowProc ( hwnd, message, w_param, l_param );
}
}
}
**BaseWindow.h**
#pragma once
#ifndef __BASE_WINDOW_H__
#define __BASE_WINDOW_H__
#include <Windows.h>
#include "AbstractWindow.h"
#include "Player.h"
class BaseWindow : public AbstractWindow {
public:
BaseWindow ();
~BaseWindow ();
BaseWindow ( const TCHAR*, const TCHAR* );
// Display the window onto the screen while updating the client area
void Show ();
private:
// Player Object
Player player;
// Handlers
virtual bool OnCreate ( HWND );
virtual bool OnCommand ( int, int );
virtual bool OnDestroy ();
virtual bool OnPaint( HWND, WPARAM );
// Player Handlers
virtual bool UpdatePlayerPosition( HWND, WPARAM );
};
#endif // !__BASE_WINDOW_H__
BaseWindow.cpp
#include "BaseWindow.h"
#pragma region Constructor and Destructor
BaseWindow::BaseWindow() {}
BaseWindow::~BaseWindow() {}
BaseWindow::BaseWindow( const TCHAR* window_name, const TCHAR* class_name ) : AbstractWindow() {
// Member variables are declaried in AbstractWindow as Protected
window_name_ = window_name;
class_name_ = class_name;
// Get the module handle for the window currently running
h_instance_ = GetModuleHandle( NULL );
style_ = ( WS_OVERLAPPED| WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX );
x_ = CW_USEDEFAULT;
y_ = CW_USEDEFAULT;
width_ = CW_USEDEFAULT;
height_ = CW_USEDEFAULT;
parent_ = NULL;
menu_ = NULL;
}
#pragma endregion
#pragma region Functions
void BaseWindow::Show() {
// hwnd_ is from AbstractWindow Class
ShowWindow( hwnd_, SW_SHOW );
UpdateWindow( hwnd_ );
}
#pragma endregion
#pragma region Basic Handlers
bool BaseWindow::OnCreate( HWND hwnd ) {
MessageBox( hwnd, TEXT( "[BaseWindow] Window has been successfully created!" ), TEXT( "SUCCESS" ), MB_OK );
GetClientRect( hwnd, &rect_ );
width_ = rect_.right;
height_ = rect_.bottom;
// Create the back buffer
back_buffer_ = CreateCompatibleDC( NULL );
// Get the Device Context
hdc_ = GetDC( hwnd );
// Create the Bitmap
bitmap_ = CreateCompatibleBitmap( hdc_, width_, height_ );
// Select the Bitmap
SelectObject( back_buffer_, bitmap_ );
// Release
ReleaseDC( hwnd, hdc_ );
return true;
}
bool BaseWindow::OnCommand( int ctrl_id, int notify_code ) {
// Lower 16 bits specifies the element the mouse was used on
// Upper 16 bits specifies the mouse properties
// ctrl_id = Lower
// notify_code = Upper
return true;
}
bool BaseWindow::OnDestroy() {
PostQuitMessage( 0 );
return true;
}
#pragma endregion
#pragma region Other Handlers
bool BaseWindow::OnPaint( HWND hwnd, WPARAM w_param ) {
PAINTSTRUCT paint_struct;
// Get the Device Context
hdc_ = BeginPaint( hwnd, &paint_struct );
BitBlt( back_buffer_, 0, 0, width_, height_, NULL, NULL, NULL, WHITENESS );
if ( player.WithinTopBounds() && player.WithinBottomBounds(height_) ) {
player.GravityMovement();
}
// Select the Rectangle Brush
SelectObject( back_buffer_, CreateSolidBrush( RGB( player.SpecializerRed(), player.SpecializerGreen(), player.SpecializerBlue() ) ) );
// Draw the Rectangle on the back buffer
Rectangle( back_buffer_,
player.X() - player.Width() / 2,
player.Y() - player.Height() / 2,
player.X() + player.Width() / 2,
player.Y() + player.Height() / 2);
// Display the back buffer
BitBlt( hdc_, 0, 0, width_, height_, back_buffer_, 0, 0, SRCCOPY );
// Repaint the screen
InvalidateRect( hwnd, NULL, false );
EndPaint( hwnd, &paint_struct );
return true;
}
#pragma region Player
bool BaseWindow::UpdatePlayerPosition(HWND hwnd, WPARAM w_param ) {
if ( w_param == VK_RIGHT ) {
if ( player.withinRightBounds( width_ ) ) {
// Movement to the right
player.RightMovement();
}
}
if ( w_param == VK_LEFT ) {
if ( player.WithinLeftBounds() ) {
// Movement to right left
player.LeftMovement();
}
}
if ( w_param == VK_UP ) {
// Movement upwards
if ( !player.WithinTopBounds() ) {
player.SetInverted( false );
}
player.SetInverted( true );
}
if ( w_param == VK_DOWN ) {
if ( !player.WithinBottomBounds( height_ ) ) {
player.SetInverted( true );
}
// Movement downwards
player.SetInverted( false );
}
return true;
}
#pragma endregion
#pragma endregions
GameWindow.h
#pragma once
#ifndef __GAME_WINDOW_H__
#define __GAME_WINDOW_H__
#include <Windows.h>
#include "AbstractWindow.h"
class GameWindow : protected WNDCLASSEX {
public:
GameWindow ();
~GameWindow ();
GameWindow ( HINSTANCE, const TCHAR* );
virtual bool Register ();
virtual const TCHAR* ClassName () const;
protected:
UINT cb_size_;
UINT style_;
WNDPROC lpfn_wnd_proc_;
int cb_cls_extra_;
int cb_wnd_extra_;
HINSTANCE h_instance_;
HICON h_icon_;
HCURSOR h_cursor_;
HBRUSH hbr_background_;
LPCTSTR lpsz_menu_name_;
LPCTSTR lpsz_class_name_;
HICON h_icon_sm_;
};
#endif // !__GAME_WINDOW_H__
**GameWindow.cpp**
#include "GameWindow.h"
GameWindow::GameWindow () {}
GameWindow::~GameWindow () {}
GameWindow::GameWindow ( HINSTANCE h_instance, const TCHAR* class_name ) {
// All messages belonging to this Window Class will get sent to MsgRouter
hInstance = h_instance;
lpszClassName = class_name;
lpfnWndProc = AbstractWindow::MessageRouter;
lpszMenuName = NULL;
cbSize = sizeof ( WNDCLASSEX );
cbClsExtra = NULL;
cbWndExtra = NULL;
// Prevent Window from Redrawing
style = 0;
hIcon = LoadIcon ( NULL, IDI_APPLICATION );
hIconSm = LoadIcon ( NULL, IDI_APPLICATION );
hCursor = LoadCursor ( NULL, IDC_HAND );
hbrBackground = CreateSolidBrush ( RGB ( 125, 255, 255 ) );
}
const TCHAR* GameWindow::ClassName () const {
return lpszClassName;
}
bool GameWindow::Register () {
return ( ( RegisterClassEx ( this ) ) ? true : false );
}
Player.h
#pragma once
#ifndef __PLAYER_H__
#define __PLAYER_H__
#include <Windows.h>
#include <algorithm>
#include <string>
using namespace std;
class Player {
public:
Player ();
~Player ();
// Mutator
void SetX ( float );
void SetY ( float );
void SetPlayerSpeed ( float );
void SetSpecializerState ( string );
void SetInverted( bool );
// Accessor
float X () const;
float Y () const;
int Width () const;
int Height () const;
int SpecializerRed () const;
int SpecializerGreen () const;
int SpecializerBlue () const;
string SpecializerState () const;
bool Inverted() const;
// Player Functionality
void RightMovement ();
void LeftMovement ();
void GravityMovement();
// Within Bounds Detection
bool WithinLeftBounds();
bool withinRightBounds(int);
bool WithinTopBounds();
bool WithinBottomBounds(int);
private:
// General Information
float x_;
float y_;
int width_;
int height_;
float speed_;
float gravity_;
bool inverted_;
// Player States
int specializer_state_;
// RGB
int specializer_red_;
int specializer_green_;
int specializer_blue_;
void SetSpecializerColor (int);
};
#endif // !__PLAYER_H__
Player.cpp
#include "Player.h"
#pragma region Constructor and Destructor
Player::Player () {
x_ = 200;
y_ = 200;
width_ = 50;
height_ = 50;
speed_ = 5.0f;
gravity_ = 0.2f;
inverted_ = false;
// Specializer
// Set to Default Specializer State
specializer_state_ = 0;
specializer_red_ = 0;
specializer_green_ = 0;
specializer_blue_ = 0;
SetSpecializerColor ( specializer_state_ );
}
Player::~Player () {}
#pragma endregion
#pragma region Mutator
#pragma region Position Properties
void Player::SetX ( float x ) {
x_ = x;
}
void Player::SetY ( float y ) {
y_ = y;
}
#pragma endregion
void Player::SetInverted( bool inverted ) {
inverted_ = inverted;
}
#pragma region Specializer Properties
void Player::SetSpecializerState ( string input_state ) {
if ( input_state == "NORMAL" ) {
specializer_state_ = 0;
}
else if ( input_state == "SHIELD" ) {
specializer_state_ = 1;
}
else if ( input_state == "SPEED" ) {
specializer_state_ = 2;
}
else if ( input_state == "PROJECTILE" ) {
specializer_state_ = 3;
}
else if ( input_state == "MULTIPLIER" ) {
specializer_state_ = 4;
}
SetSpecializerColor ( specializer_state_ );
}
void Player::SetSpecializerColor ( int state ) {
if ( specializer_state_ == 0 ) {
// NORMAL - White
specializer_red_ = 255;
specializer_green_ = 255;
specializer_blue_ = 255;
}
else if ( specializer_state_ == 1 ) {
// SHIELD - Green
specializer_red_ = 255;
specializer_green_ = 153;
specializer_blue_ = 76;
}
else if ( specializer_state_ == 2 ) {
// SPEED - Blue
specializer_red_ = 0;
specializer_green_ = 0;
specializer_blue_ = 102;
}
else if ( specializer_state_ == 3 ) {
// PROJECTILE - Yellow
specializer_red_ = 255;
specializer_green_ = 255;
specializer_blue_ = 0;
}
else if ( specializer_state_ == 4 ) {
// MULTIPLIER - Red
specializer_red_ = 204;
specializer_green_ = 0;
specializer_blue_ = 0;
}
}
#pragma endregion
#pragma endregion
#pragma region Accessor
#pragma region Position Properties
float Player::X () const {
return x_;
}
float Player::Y () const {
return y_;
}
int Player::Width () const {
return width_;
}
int Player::Height () const {
return height_;
}
bool Player::Inverted() const {
return inverted_;
}
#pragma endregion
#pragma region Specializer Properties
int Player::SpecializerRed () const {
return specializer_red_;
}
int Player::SpecializerGreen () const {
return specializer_green_;
}
int Player::SpecializerBlue () const {
return specializer_blue_;
}
string Player::SpecializerState () const {
string specializer_state = "";
if ( specializer_state_ == 0 ) {
specializer_state = "NORMAL";
}
else if ( specializer_state_ == 1 ) {
specializer_state = "SHIELD";
}
else if ( specializer_state_ == 2 ) {
specializer_state = "SPEED";
}
else if ( specializer_state_ == 3 ) {
specializer_state = "PROJECTILE";
}
else if ( specializer_state_ == 4 ) {
specializer_state = "MULTIPLIER";
}
return specializer_state;
}
#pragma endregion
#pragma endregion
#pragma region Functionality
#pragma region Movement
void Player::RightMovement() {
x_ += speed_;
}
void Player::LeftMovement() {
x_ -= speed_;
}
void Player::GravityMovement() {
if ( inverted_ ) {
// Upwards
if ( min( 0.0f, gravity_ ) == 0.0f ) {
gravity_ = -gravity_;
}
y_ += gravity_;
}
else {
// Downwards
if ( max( 0.0f, gravity_ ) == 0.0f ) {
gravity_ = -gravity_;
}
y_ += gravity_;
}
}
#pragma endregion
#pragma region Within Window Bounds
bool Player::WithinLeftBounds() {
if ( x_ - ( width_ / 2 ) > 0 ) {
return true;
}
return false;
}
bool Player::withinRightBounds( int width ) {
if ( x_ + (width_ / 2) < width ) {
return true;
}
return false;
}
bool Player::WithinTopBounds() {
if ( y_ - ( height_ / 2 ) > 0 ) {
return true;
}
return false;
}
bool Player::WithinBottomBounds( int height ) {
if ( y_ + ( height_ / 2 ) < height ) {
return true;
}
return false;
}
#pragma endregion
#pragma endregion
您的游戏应该有 game loop.
通常,(非常基本的)游戏循环如下所示:
while (playing) {
accept_input()
update_game_logic()
render()
}
在您的 update_game_logic()
函数中,您将有一个更新玩家位置的部分。玩家的位置更新步骤通常看起来像是以下的混合:
// 1. sum up forces on the player (i.e. running to the right)
// 2. add current_gravity (normal or inverted)
// 3. check for any collision and add an opposing force
// (if touching the ground add a force directly opposite the ground, equal to the force the object is pushing down with)
// 4. resolve position using some form of integration
// e.g. add force (* deltatime) to acceleration, add acceleration (* deltatime) to velocity, add velocity (* deltatime) to position.
因为您是根据每个刻度的力来调整玩家的位置,所以您可以在更新游戏逻辑的同时继续接受输入和渲染屏幕。
我正在尝试想出一种将重力翻转机制实施到我的 C++ Win32 游戏中的有效方法。虽然我的语言不是很流利,所以我来问一下。
我有:
- 一个class,它存储播放器的属性(例如位置和大小,以及一些功能)。
- 一个消息路由器,接收从用户(和其他来源)发送的消息。
- 这些消息包括玩家输入。我处理消息路由器中的输入,然后调用播放器上的函数 class.
我被困在如何实现重力翻转机制上。这是一款免费的跑酷游戏。玩家向 window 的右侧奔跑,轻按一个键后,玩家角色将在正常(向下)重力或反转(向上)重力之间切换。
我考虑的方法是使用 do-while。这样做的问题是用户必须等到 do-while 完成。也就是说,如果玩家没有到达屏幕顶部,请继续向上移动(反重力)。
我考虑过其他方法,但我认为它们不值得尝试。它只会导致其他一些麻烦。
有什么建议吗?
提前致谢:)
更新
这是我一直在处理的代码,我必须解决的当前问题是一旦玩家到达屏幕底部或顶部。我似乎无法改变重力。但它允许我在玩家触及顶部或底部 window 边缘之前执行此操作。 这是为什么?
随时批评我的代码并告诉我如何改进我。
Main.cpp
#include "BaseWindow.h"
#include "GameWindow.h"
int APIENTRY WinMain ( HINSTANCE h_instance, HINSTANCE h_prev_instance, LPSTR lp_cmd_line, int n_cmd_show ) {
// Create the Game Window
GameWindow game_window ( h_instance, TEXT ( "GameWindow" ) );
game_window.Register ();
// Create the Base Window
BaseWindow base_window ( TEXT ( "BaseWindow" ), game_window.ClassName () );
base_window.Create ();
base_window.Show ();
// Pump Messages
MSG messages;
int status;
while ( ( status = GetMessage ( &messages, 0, 0, 0 ) ) != 0 ) {
if ( status == -1 ) {
// Break;
break;
}
TranslateMessage ( &messages );
DispatchMessage ( &messages );
}
return messages.wParam;
}
AbstractWindow.h
#pragma once
#ifndef __ABSTRACT_WINDOW_H__
#define __ABSTRACT_WINDOW_H__
#include <Windows.h>
class AbstractWindow {
public:
AbstractWindow ();
~AbstractWindow ();
virtual bool Create ();
static LRESULT CALLBACK MessageRouter ( HWND, UINT, WPARAM, LPARAM );
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 h_instance_;
LPVOID param_;
// Bitmap Variables - Start
// Stucture for thw Window width and height
RECT rect_;
// Handle to Device Context
HDC hdc_;
// Handle to Device Context - Back Buffer
HDC back_buffer_;
// Bitmap - Front
HBITMAP bitmap_; // Bitmap
// Bitmap Variables - End
// Default Handlers
virtual bool OnCreate ( HWND ) = 0;
virtual bool OnCommand ( int, int ) = 0;
virtual bool OnDestroy () = 0;
virtual bool OnPaint ( HWND, WPARAM ) = 0;
// Player Handlers
virtual bool UpdatePlayerPosition( HWND, WPARAM ) = 0;
};
#endif // !__ABSTRACT_WINDOW_H__
AbstractWindow.cpp
#include "AbstractWindow.h"
AbstractWindow::AbstractWindow () {}
AbstractWindow::~AbstractWindow () {}
bool AbstractWindow::Create () {
hwnd_ = CreateWindowEx (
style_ex_,
class_name_,
window_name_,
style_,
x_,
y_,
width_,
height_,
parent_,
menu_,
h_instance_,
this // Pointer to this class instance
);
if ( hwnd_ ) {
OnCreate(hwnd_);
return true;
}
return false;
}
LRESULT CALLBACK AbstractWindow::MessageRouter ( HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param ) {
AbstractWindow* abstract_window = 0;
static bool move = false;
if ( message == WM_NCCREATE ) {
abstract_window = ( AbstractWindow* ) ( ( LPCREATESTRUCT ( l_param ) )->lpCreateParams );
SetWindowLong ( hwnd, GWL_USERDATA, long ( abstract_window ) );
return DefWindowProc ( hwnd, message, w_param, l_param );
}
else {
abstract_window = ( AbstractWindow* ) ( GetWindowLong ( hwnd, GWL_USERDATA ) );
if ( abstract_window ) {
switch ( message ) {
case WM_COMMAND:
return abstract_window->OnCommand ( LOWORD ( w_param ), HIWORD ( w_param ) );
case WM_DESTROY:
return abstract_window->OnDestroy ();
case WM_PAINT:
return abstract_window->OnPaint ( hwnd, w_param);
case WM_KEYDOWN:
return abstract_window->UpdatePlayerPosition( hwnd, w_param );
default:
return DefWindowProc ( hwnd, message, w_param, l_param );
}
}
else {
return DefWindowProc ( hwnd, message, w_param, l_param );
}
}
}
**BaseWindow.h**
#pragma once
#ifndef __BASE_WINDOW_H__
#define __BASE_WINDOW_H__
#include <Windows.h>
#include "AbstractWindow.h"
#include "Player.h"
class BaseWindow : public AbstractWindow {
public:
BaseWindow ();
~BaseWindow ();
BaseWindow ( const TCHAR*, const TCHAR* );
// Display the window onto the screen while updating the client area
void Show ();
private:
// Player Object
Player player;
// Handlers
virtual bool OnCreate ( HWND );
virtual bool OnCommand ( int, int );
virtual bool OnDestroy ();
virtual bool OnPaint( HWND, WPARAM );
// Player Handlers
virtual bool UpdatePlayerPosition( HWND, WPARAM );
};
#endif // !__BASE_WINDOW_H__
BaseWindow.cpp
#include "BaseWindow.h"
#pragma region Constructor and Destructor
BaseWindow::BaseWindow() {}
BaseWindow::~BaseWindow() {}
BaseWindow::BaseWindow( const TCHAR* window_name, const TCHAR* class_name ) : AbstractWindow() {
// Member variables are declaried in AbstractWindow as Protected
window_name_ = window_name;
class_name_ = class_name;
// Get the module handle for the window currently running
h_instance_ = GetModuleHandle( NULL );
style_ = ( WS_OVERLAPPED| WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX );
x_ = CW_USEDEFAULT;
y_ = CW_USEDEFAULT;
width_ = CW_USEDEFAULT;
height_ = CW_USEDEFAULT;
parent_ = NULL;
menu_ = NULL;
}
#pragma endregion
#pragma region Functions
void BaseWindow::Show() {
// hwnd_ is from AbstractWindow Class
ShowWindow( hwnd_, SW_SHOW );
UpdateWindow( hwnd_ );
}
#pragma endregion
#pragma region Basic Handlers
bool BaseWindow::OnCreate( HWND hwnd ) {
MessageBox( hwnd, TEXT( "[BaseWindow] Window has been successfully created!" ), TEXT( "SUCCESS" ), MB_OK );
GetClientRect( hwnd, &rect_ );
width_ = rect_.right;
height_ = rect_.bottom;
// Create the back buffer
back_buffer_ = CreateCompatibleDC( NULL );
// Get the Device Context
hdc_ = GetDC( hwnd );
// Create the Bitmap
bitmap_ = CreateCompatibleBitmap( hdc_, width_, height_ );
// Select the Bitmap
SelectObject( back_buffer_, bitmap_ );
// Release
ReleaseDC( hwnd, hdc_ );
return true;
}
bool BaseWindow::OnCommand( int ctrl_id, int notify_code ) {
// Lower 16 bits specifies the element the mouse was used on
// Upper 16 bits specifies the mouse properties
// ctrl_id = Lower
// notify_code = Upper
return true;
}
bool BaseWindow::OnDestroy() {
PostQuitMessage( 0 );
return true;
}
#pragma endregion
#pragma region Other Handlers
bool BaseWindow::OnPaint( HWND hwnd, WPARAM w_param ) {
PAINTSTRUCT paint_struct;
// Get the Device Context
hdc_ = BeginPaint( hwnd, &paint_struct );
BitBlt( back_buffer_, 0, 0, width_, height_, NULL, NULL, NULL, WHITENESS );
if ( player.WithinTopBounds() && player.WithinBottomBounds(height_) ) {
player.GravityMovement();
}
// Select the Rectangle Brush
SelectObject( back_buffer_, CreateSolidBrush( RGB( player.SpecializerRed(), player.SpecializerGreen(), player.SpecializerBlue() ) ) );
// Draw the Rectangle on the back buffer
Rectangle( back_buffer_,
player.X() - player.Width() / 2,
player.Y() - player.Height() / 2,
player.X() + player.Width() / 2,
player.Y() + player.Height() / 2);
// Display the back buffer
BitBlt( hdc_, 0, 0, width_, height_, back_buffer_, 0, 0, SRCCOPY );
// Repaint the screen
InvalidateRect( hwnd, NULL, false );
EndPaint( hwnd, &paint_struct );
return true;
}
#pragma region Player
bool BaseWindow::UpdatePlayerPosition(HWND hwnd, WPARAM w_param ) {
if ( w_param == VK_RIGHT ) {
if ( player.withinRightBounds( width_ ) ) {
// Movement to the right
player.RightMovement();
}
}
if ( w_param == VK_LEFT ) {
if ( player.WithinLeftBounds() ) {
// Movement to right left
player.LeftMovement();
}
}
if ( w_param == VK_UP ) {
// Movement upwards
if ( !player.WithinTopBounds() ) {
player.SetInverted( false );
}
player.SetInverted( true );
}
if ( w_param == VK_DOWN ) {
if ( !player.WithinBottomBounds( height_ ) ) {
player.SetInverted( true );
}
// Movement downwards
player.SetInverted( false );
}
return true;
}
#pragma endregion
#pragma endregions
GameWindow.h
#pragma once
#ifndef __GAME_WINDOW_H__
#define __GAME_WINDOW_H__
#include <Windows.h>
#include "AbstractWindow.h"
class GameWindow : protected WNDCLASSEX {
public:
GameWindow ();
~GameWindow ();
GameWindow ( HINSTANCE, const TCHAR* );
virtual bool Register ();
virtual const TCHAR* ClassName () const;
protected:
UINT cb_size_;
UINT style_;
WNDPROC lpfn_wnd_proc_;
int cb_cls_extra_;
int cb_wnd_extra_;
HINSTANCE h_instance_;
HICON h_icon_;
HCURSOR h_cursor_;
HBRUSH hbr_background_;
LPCTSTR lpsz_menu_name_;
LPCTSTR lpsz_class_name_;
HICON h_icon_sm_;
};
#endif // !__GAME_WINDOW_H__
**GameWindow.cpp**
#include "GameWindow.h"
GameWindow::GameWindow () {}
GameWindow::~GameWindow () {}
GameWindow::GameWindow ( HINSTANCE h_instance, const TCHAR* class_name ) {
// All messages belonging to this Window Class will get sent to MsgRouter
hInstance = h_instance;
lpszClassName = class_name;
lpfnWndProc = AbstractWindow::MessageRouter;
lpszMenuName = NULL;
cbSize = sizeof ( WNDCLASSEX );
cbClsExtra = NULL;
cbWndExtra = NULL;
// Prevent Window from Redrawing
style = 0;
hIcon = LoadIcon ( NULL, IDI_APPLICATION );
hIconSm = LoadIcon ( NULL, IDI_APPLICATION );
hCursor = LoadCursor ( NULL, IDC_HAND );
hbrBackground = CreateSolidBrush ( RGB ( 125, 255, 255 ) );
}
const TCHAR* GameWindow::ClassName () const {
return lpszClassName;
}
bool GameWindow::Register () {
return ( ( RegisterClassEx ( this ) ) ? true : false );
}
Player.h
#pragma once
#ifndef __PLAYER_H__
#define __PLAYER_H__
#include <Windows.h>
#include <algorithm>
#include <string>
using namespace std;
class Player {
public:
Player ();
~Player ();
// Mutator
void SetX ( float );
void SetY ( float );
void SetPlayerSpeed ( float );
void SetSpecializerState ( string );
void SetInverted( bool );
// Accessor
float X () const;
float Y () const;
int Width () const;
int Height () const;
int SpecializerRed () const;
int SpecializerGreen () const;
int SpecializerBlue () const;
string SpecializerState () const;
bool Inverted() const;
// Player Functionality
void RightMovement ();
void LeftMovement ();
void GravityMovement();
// Within Bounds Detection
bool WithinLeftBounds();
bool withinRightBounds(int);
bool WithinTopBounds();
bool WithinBottomBounds(int);
private:
// General Information
float x_;
float y_;
int width_;
int height_;
float speed_;
float gravity_;
bool inverted_;
// Player States
int specializer_state_;
// RGB
int specializer_red_;
int specializer_green_;
int specializer_blue_;
void SetSpecializerColor (int);
};
#endif // !__PLAYER_H__
Player.cpp
#include "Player.h"
#pragma region Constructor and Destructor
Player::Player () {
x_ = 200;
y_ = 200;
width_ = 50;
height_ = 50;
speed_ = 5.0f;
gravity_ = 0.2f;
inverted_ = false;
// Specializer
// Set to Default Specializer State
specializer_state_ = 0;
specializer_red_ = 0;
specializer_green_ = 0;
specializer_blue_ = 0;
SetSpecializerColor ( specializer_state_ );
}
Player::~Player () {}
#pragma endregion
#pragma region Mutator
#pragma region Position Properties
void Player::SetX ( float x ) {
x_ = x;
}
void Player::SetY ( float y ) {
y_ = y;
}
#pragma endregion
void Player::SetInverted( bool inverted ) {
inverted_ = inverted;
}
#pragma region Specializer Properties
void Player::SetSpecializerState ( string input_state ) {
if ( input_state == "NORMAL" ) {
specializer_state_ = 0;
}
else if ( input_state == "SHIELD" ) {
specializer_state_ = 1;
}
else if ( input_state == "SPEED" ) {
specializer_state_ = 2;
}
else if ( input_state == "PROJECTILE" ) {
specializer_state_ = 3;
}
else if ( input_state == "MULTIPLIER" ) {
specializer_state_ = 4;
}
SetSpecializerColor ( specializer_state_ );
}
void Player::SetSpecializerColor ( int state ) {
if ( specializer_state_ == 0 ) {
// NORMAL - White
specializer_red_ = 255;
specializer_green_ = 255;
specializer_blue_ = 255;
}
else if ( specializer_state_ == 1 ) {
// SHIELD - Green
specializer_red_ = 255;
specializer_green_ = 153;
specializer_blue_ = 76;
}
else if ( specializer_state_ == 2 ) {
// SPEED - Blue
specializer_red_ = 0;
specializer_green_ = 0;
specializer_blue_ = 102;
}
else if ( specializer_state_ == 3 ) {
// PROJECTILE - Yellow
specializer_red_ = 255;
specializer_green_ = 255;
specializer_blue_ = 0;
}
else if ( specializer_state_ == 4 ) {
// MULTIPLIER - Red
specializer_red_ = 204;
specializer_green_ = 0;
specializer_blue_ = 0;
}
}
#pragma endregion
#pragma endregion
#pragma region Accessor
#pragma region Position Properties
float Player::X () const {
return x_;
}
float Player::Y () const {
return y_;
}
int Player::Width () const {
return width_;
}
int Player::Height () const {
return height_;
}
bool Player::Inverted() const {
return inverted_;
}
#pragma endregion
#pragma region Specializer Properties
int Player::SpecializerRed () const {
return specializer_red_;
}
int Player::SpecializerGreen () const {
return specializer_green_;
}
int Player::SpecializerBlue () const {
return specializer_blue_;
}
string Player::SpecializerState () const {
string specializer_state = "";
if ( specializer_state_ == 0 ) {
specializer_state = "NORMAL";
}
else if ( specializer_state_ == 1 ) {
specializer_state = "SHIELD";
}
else if ( specializer_state_ == 2 ) {
specializer_state = "SPEED";
}
else if ( specializer_state_ == 3 ) {
specializer_state = "PROJECTILE";
}
else if ( specializer_state_ == 4 ) {
specializer_state = "MULTIPLIER";
}
return specializer_state;
}
#pragma endregion
#pragma endregion
#pragma region Functionality
#pragma region Movement
void Player::RightMovement() {
x_ += speed_;
}
void Player::LeftMovement() {
x_ -= speed_;
}
void Player::GravityMovement() {
if ( inverted_ ) {
// Upwards
if ( min( 0.0f, gravity_ ) == 0.0f ) {
gravity_ = -gravity_;
}
y_ += gravity_;
}
else {
// Downwards
if ( max( 0.0f, gravity_ ) == 0.0f ) {
gravity_ = -gravity_;
}
y_ += gravity_;
}
}
#pragma endregion
#pragma region Within Window Bounds
bool Player::WithinLeftBounds() {
if ( x_ - ( width_ / 2 ) > 0 ) {
return true;
}
return false;
}
bool Player::withinRightBounds( int width ) {
if ( x_ + (width_ / 2) < width ) {
return true;
}
return false;
}
bool Player::WithinTopBounds() {
if ( y_ - ( height_ / 2 ) > 0 ) {
return true;
}
return false;
}
bool Player::WithinBottomBounds( int height ) {
if ( y_ + ( height_ / 2 ) < height ) {
return true;
}
return false;
}
#pragma endregion
#pragma endregion
您的游戏应该有 game loop.
通常,(非常基本的)游戏循环如下所示:
while (playing) {
accept_input()
update_game_logic()
render()
}
在您的 update_game_logic()
函数中,您将有一个更新玩家位置的部分。玩家的位置更新步骤通常看起来像是以下的混合:
// 1. sum up forces on the player (i.e. running to the right)
// 2. add current_gravity (normal or inverted)
// 3. check for any collision and add an opposing force
// (if touching the ground add a force directly opposite the ground, equal to the force the object is pushing down with)
// 4. resolve position using some form of integration
// e.g. add force (* deltatime) to acceleration, add acceleration (* deltatime) to velocity, add velocity (* deltatime) to position.
因为您是根据每个刻度的力来调整玩家的位置,所以您可以在更新游戏逻辑的同时继续接受输入和渲染屏幕。