Jump to content
  • Advertisement
Sign in to follow this  
RedKMan

Simple WIN32 Game Loop

This topic is 3012 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm going to do a simple WIN32 GDI only Connect Four game. Just wondering if the WinMain .cpp code below is OK enough for something like this. Can I make it more effecient or is it fit for the purpose? I used something similar for a Tic Tac Toe game and it worked fine just wondering if there's a better more elegant solution out there. Is it OK to organise things into the three functions initGame(), mainGame(), shutdownGame() like this?

[Source]
#include <windows.h>
#include <tchar.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>


// Windows application variables.
HWND g_hWnd = 0;
HINSTANCE g_hInstance = 0;
BOOL g_bActive = FALSE;
BOOL g_bDone = FALSE;
TCHAR g_szAppClass[] = TEXT( "Application" );
TCHAR g_szAppTitle[] = TEXT( "Connect Four" );


// Windows application function prototypes.
LRESULT WINAPI MsgProc( HWND, UINT, WPARAM, LPARAM );


// Game application function prototypes.
void initGame();

void mainGame();

void shutdownGame();


//---------------------------------------------------------------
// Name: WinMain()
// Desc: Called as soon as the Application is loaded.
//---------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
WNDCLASSEX wndclass;
HWND hWnd;
MSG msg;

// Setup the window attributes
wndclass.cbSize = sizeof( wndclass );
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
wndclass.lpfnWndProc = MsgProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
wndclass.hbrBackground = ( HBRUSH ) ( COLOR_WINDOW );
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = g_szAppClass; // Registered class name
wndclass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );

// Register the new window
if( RegisterClassEx( &wndclass ) == 0 )
exit(1);

// Create the main window. Window parameters make the main window
// 640X480 only
hWnd = CreateWindow( g_szAppClass, // Class Name
g_szAppTitle, // Name displayed on title bar
WS_OVERLAPPEDWINDOW, // Window style, using Popup
0, // X Position (Top Left)
0, // Y Position (Top Right)
640, // X Position (Bottom Right)
640, // Y Position (Bottom Left)
NULL,
NULL,
hInstance,
NULL );

// Tell windows to show the application
ShowWindow( hWnd, nCmdShow );

// Update the client by sending an initial WM_PAINT msg
UpdateWindow( hWnd );

// Save the main window handle
g_hWnd = hWnd;

// Save the main application instance
g_hInstance = hInstance;

initGame();

// Main Message Loop. Keep looping through this application until
// the user chooses to exit. When the user chooses exit by clicking
// the red X box top right of the window for example. A WM_QUIT
// message will be sent to the application which prompts the application
// to exit.

ZeroMemory( &msg, sizeof( msg ) );

while( !g_bDone )
{
while( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}

if(msg.message == WM_QUIT)
{
break;
}

if( g_bActive )
{
mainGame();
}
}

shutdownGame();

UnregisterClass( g_szAppClass, hInstance );

// Return back to Windows
return( ( int ) msg.wParam );
}


//---------------------------------------------------------------
// Name: MsgProc()
// Desc: This is the main window message handling function
//---------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
PAINTSTRUCT ps;
HDC hdc;


switch( msg )
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);

EndPaint(hWnd, &ps);
break;


case WM_ACTIVATE:
// The message WM_ACTIVE is sent whenever the application has focus.
// For example if the application is minimised then it is not in focus.
// As the application is not in focus it is pointless wasting clock
// cycles and graphics hardware to render to what cannot be seen.
g_bActive = ( BOOL ) wParam;
break;


case WM_KEYDOWN:
// Whenever a key is pressed (non-accelerated ie shift and f5, then
// this message is sent.
switch( wParam )
{
case VK_ESCAPE:
// If the user presses the Escape key then we will quit the
// application
g_bDone = TRUE;
PostMessage( g_hWnd, WM_CLOSE, 0, 0 );
return 0;
};
break;


case WM_DESTROY:
// The message WM_DESTROY is sent by the Windows Messaging System
// when our message queue recieves the WM_QUIT message from the
// application. It just cleans everything up and quits the
// application
g_bDone = TRUE;
PostQuitMessage( 0 );
return 1;
break;


default: break;
}

// If any messages reach here then it was not handled by our application.
// So we will return it back to the queue so the next Windows application
// like a background task.
return DefWindowProc( hWnd, msg, wParam, lParam );
}


//---------------------------------------------------------------
// Name: initGame()
// Desc:
//---------------------------------------------------------------
void initGame()
{
// Initialisation.
}


//---------------------------------------------------------------
// Name: mainGame()
// Desc:
//---------------------------------------------------------------
void mainGame()
{
// Game calls.
}


//---------------------------------------------------------------
// Name: shutdownGame()
// Desc:
//---------------------------------------------------------------
void shutdownGame()
{
// Cleanup.
}
[/Source]

Share this post


Link to post
Share on other sites
Advertisement
Yeah, i think it's okay! Of course you could do a lot of things in terms of abstraction and generalization, but for a game like Connect it wouldn't mean much.
I think it's important, in the process of learning, to build your game and find out what elements tend to repeat, come out over and over again and make classes for them, functions and organize them into a little framework. Don't think there's a need to over complicate yourself if you don't need to :D. Concentrate on the game and care less about building an engine, now.

Share this post


Link to post
Share on other sites
If it doesn't bother you and you can keep up with it, it should be ok. I personally do things differently from you and what matters to me is to keep it consistent so that I can find my way around the code. Make sure to make your code intuitive so that when you come back to it or someone else is looking over it, it'll be as self-explanatory as it can. As an example, I'll show you my main class for the Tetris game I'm working on at the moment:


// Windows template
// Main.cpp

#include <windows.h>

#include "Tetris.h"
#include "Constants.h"

Tetris* gTetris = 0;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
gTetris = new Tetris(GetModuleHandle(0), hWnd);

break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
break; // break just for sake of keeping uniformity
}

return 0;
}

int Run(HWND hMainWnd)
{
__int64 timerFrequency;
if(!QueryPerformanceFrequency((LARGE_INTEGER *)&timerFrequency))
{
MessageBox(0, L"Performance timer does not exist!", L"Error!", MB_OK);
return 0;
}

__int64 currCount;
__int64 oldCount;
QueryPerformanceCounter((LARGE_INTEGER *)&currCount);

double elapsedTime = 0.0f;

MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while(msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
oldCount = currCount;
QueryPerformanceCounter((LARGE_INTEGER *)&currCount);

// Find the difference in counter clicks and convert into seconds
// then add to the elapsed time
elapsedTime += (double)((currCount - oldCount) * timerFrequency);

// Update everything
gTetris->Update(elapsedTime);
}
}
return (int)msg.wParam;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdArgs, int iCmdShow)
{
WNDCLASSEX exWndClass;
char szClassName[] = "Main Window"; // I don't like "magic numbers" and so "magic strings" shouldn't exist either ;)
HWND hMainWnd;

exWndClass.cbSize = sizeof(WNDCLASSEX);
exWndClass.style = CS_HREDRAW | CS_VREDRAW;
exWndClass.lpfnWndProc = WndProc;
exWndClass.hInstance = hInstance;
exWndClass.lpszClassName = (LPCWSTR)szClassName;
exWndClass.cbWndExtra = 0;
exWndClass.cbClsExtra = 0;
exWndClass.lpszMenuName = 0;
exWndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
exWndClass.hCursor = LoadCursor(0, IDC_ARROW);
exWndClass.hIcon = LoadIcon(0, IDI_APPLICATION);
exWndClass.hIconSm = LoadIcon(0, IDI_APPLICATION);

if( !RegisterClassEx(&exWndClass) )
{
MessageBox(NULL, L"Window registration failed!", L"Error!", MB_OK | MB_ICONERROR);
return 0; // If registration fails, exit
}

hMainWnd = CreateWindowEx(WS_EX_CLIENTEDGE, (LPCWSTR)szClassName, L"Main Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
WND_WIDTH, WND_HEIGHT, NULL, NULL, hInstance, NULL);

if(hMainWnd == NULL)
{
MessageBox(0, L"Creating window failed!", L"Error!", MB_OK | MB_ICONERROR);
return 0;
}

ShowWindow(hMainWnd, iCmdShow);
UpdateWindow(hMainWnd);

return Run(hMainWnd);
}




I have minimized the amount of global variables to one, and that variable handles a lot of the main game logic (which I still have yet to implement of course :D ). Have a look. :]

Share this post


Link to post
Share on other sites
Very nice boogyman19946, given me some ideas :) Thanks Deliverance. I'm pretty happy with it and it works. I've already made some mods since my last project. It will be a process as I complete and move onto other projects.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!