Sign in to follow this  
White Scorpion

Improvements to my game engine.

Recommended Posts

Greetings ! I'm currently in the process of making a little "system engine" for a game that I don't know yet. I want to separate game logic code and rendering code from the core stuff like creating the window, going into fullscreen mode... here's what I have so far, everything's working as expected but I want to know your suggestions on what I should improve:
/*
    File: sys_engine.h
    Coder: Alexandre Prince
    
    Contains: - User-defined types/functions used throughout the game.
              - Engine class which provides system functionnalities
    
    Copyright: You may take this file and modify it as you wish but please keep
    my name in the header file as I am the maker of all this code.
*/

#ifndef _SYS_ENGINE_H_
#define _SYS_ENGINE_H_

#include <windows.h>
#include <cstdarg>
#include <cstdio>
#include <string>
#include <list>
#include <cmath>

// Message processing loop, nothing magic here
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

struct Point;
class Logger;
class SystemEngine;

extern SystemEngine MyEngine;

//
// These functions are a bunch of functions that I thought
// really missed in the Win32 API so I made these. Most of them are
// only minor modifications but they can greatly help.
//
int MsgBox(const unsigned int, const char*, const char*, ...);


// Possible states of the game
enum GAME_STATE
{
     GS_START,        // The game is still on the start screen
     GS_RUNNING,      // The game is started and running
     GS_PAUSED,       // The game is paused
     GS_MINIMIZED,    // The window is minimized (same effect as GS_PAUSED)
     GS_OVER          // The game is finished (clean & quit)
};


//
// struct: Point
// Utilities: - Representing a point on a 2D graph
//            - Give a few tools to the user (operator overloading...)
//
struct Point
{
     public:
          Point();
          Point(const unsigned int, const unsigned int);
          Point(const Point&);
          
          float Distance(const unsigned int, const unsigned int) const;
          float Distance(const Point&) const;
         
          Point& operator+(const Point&);
          Point& operator+=(const Point&);
          Point& operator=(const Point&);
          bool operator==(const Point&) const;
          bool operator!=(const Point&) const;
     public:
          unsigned int x;
          unsigned int y;
};


//
// class: Logger
// Utilities: - Hide IO code from the user
//            - Simplify error logging using C-style wildcards
//
class Logger
{
     public:
          Logger();
          
          bool Create(const char*);
          void Release();
          
          void WriteLine(const char*, ...);
     private:
          FILE* File;
};


//
// class: SystemEngine
// Utilities: - Take care of core tasks
//            - Hide lots of unrelated-to-the-game tasks
//            - Log critical operations in a systemlog.txt for easier debugging
//
// Note: This class doesn't take care of the game logic in any form !
//
class SystemEngine
{
     public:
          SystemEngine();
          
          // Core functions: Create() and Release() MUST be called
          void Create(Point, int, int, const char*, const char*);
          bool RegisterClass();
          bool WindowCreation(const unsigned int, const unsigned int);
          void MessageLoop(void(*ptr_func)());
          void Release();
          
          void CreateTimer(TIMERPROC, unsigned int);
          int RandomNumber(int, int);
          void ProcessKbd();
          
          void SetCaption(char*, ...);
          void SetWindowed(bool);
          void SetCursor(const char*);
          void SetCursor(const unsigned int);
          void SetWidth(unsigned int);
          void SetHeight(unsigned int);
          void SetPosition(int, int);
          void SetPosition(const Point&);
          void SetKey(const unsigned int, bool);
          
          HDC GetDC();
          HWND GetWindow();
          Point GetPosition();
          unsigned int GetWidth();
          unsigned int GetHeight();
          bool IsWindowed() { return Windowed; }
     protected:
          HWND         hWnd;
          HDC          MainDC;
          HDC          MemDC;
          Point        Position;
          std::list<unsigned int> Timers;
          unsigned int NEXT_TIMER_ID;
          unsigned int Width;
          unsigned int Height;
          std::string  Caption;
          std::string  WindowClass;
          bool         Windowed;
          Logger       ErrorLogger;
          bool         Keys[256];
          unsigned int Style;
};

#endif // _SYS_ENGINE_H_

/*
    File: sys_engine.cpp
    Coder: Alexandre Prince
    
    Contains: - Implementation of various useful functions absent in the Win32 API.
              - Implementation of struct/class Point and Logger.
              - Implementation of the game's core system.
              - Implementation of the message processing loop.
    
    Note: For the sake of clarity, all original Win32 functions
    are preceded by "::" to clearly identify them and avoid possible compiler errors
    
    Copyright: You may take this file and modify it as you wish but please keep
    my name in the header file as I am the maker of all this code.
*/


#include "sys_engine.h"

SystemEngine MyEngine;


//
// Modified Win32 API functions
//
int MsgBox(const unsigned int type, const char* caption, const char* fmt, ...)
{
    // Fill the buffer with the wildcards
    char buffer[255];
    va_list list;
    va_start(list, fmt);
    ::vsprintf(buffer, fmt, list);
    va_end(list);
    
    // Show the message box
    return ::MessageBox(0, buffer, caption, type);
}


//
// struct Point's implementation
//
Point::Point() : x(0), y(0)
{
}

Point::Point(const unsigned int _x, const unsigned int _y) : x(_x), y(_y)
{
}

Point::Point(const Point& copy) : x(copy.x), y(copy.y)
{
}

float Point::Distance(const unsigned int x2, const unsigned int y2) const
{
     return ::sqrt(::pow(x2-x, 2) + ::pow(y2-y, 2));
}

float Point::Distance(const Point& pt2) const
{
     return ::sqrt(::pow(pt2.x-x, 2) + ::pow(pt2.y-y, 2));
}

Point& Point::operator+(const Point& copy)
{
     return Point(*this) += copy;
}

Point& Point::operator+=(const Point& copy)
{
     x += copy.x;
     y += copy.y;
     return (*this);
}

Point& Point::operator=(const Point& copy)
{
     x = copy.x;
     y = copy.y;
     return (*this);
}

bool Point::operator==(const Point& copy) const
{
     return ((x == copy.x) && (y == copy.y));
}

bool Point::operator!=(const Point& copy) const
{
     return ((x != copy.x) || (y != copy.y));
}


//
// class Logger's implementation
//
Logger::Logger() : File(0)
{
}

bool Logger::Create(const char* filename)
{
     File = ::fopen(filename, "w+");
     return (File == NULL) ? (bool)(File = 0) : true;
}

void Logger::Release()
{
     if(File != 0)
     {
          ::fclose(File);
          File = 0;
     }
}

void Logger::WriteLine(const char* fmt, ...)
{
     va_list list;
     va_start(list, fmt);
     ::vfprintf(File, fmt, list);
     va_end(list);
}


//
// Core system's implementation
//
SystemEngine::SystemEngine()
{
     ZeroMemory(&Keys, sizeof(Keys));
}

void SystemEngine::Create(Point pos, int _width, int _height, 
                                const char* _caption, const char* window_class)
{
     srand(GetTickCount());
     
     Style = WS_SYSMENU | WS_MAXIMIZEBOX | WS_CAPTION;
     Position     = pos;
     Width        = _width;
     Height       = _height;
     Caption      = _caption;
     WindowClass  = window_class;
     ErrorLogger.Create("systemlog.txt");
     
     RECT rc;
     rc.left = 0;
     rc.right = _width;
     rc.top = 0;
     rc.bottom = _height;
     AdjustWindowRectEx(&rc, Style, 0, 0);
     
     bool Result = RegisterClass();
     ErrorLogger.WriteLine("Register class... %s\n", Result ? "ok" : "failed" );
     
     Result = WindowCreation(rc.right-rc.left, rc.bottom-rc.top);
     ErrorLogger.WriteLine("Create window... %s\n", Result ? "ok" : "failed");
     
     ::UpdateWindow(hWnd);
     ::ShowWindow(hWnd, true);
     
     MainDC = ::GetDC(hWnd);
     MemDC = ::CreateCompatibleDC(MainDC);
     NEXT_TIMER_ID = 1000;
     Windowed = true;
}

bool SystemEngine::RegisterClass()
{
     WNDCLASSEX wc;
     ::ZeroMemory(&wc, sizeof(wc));
     wc.cbSize         = sizeof(WNDCLASSEX);
     wc.hbrBackground  = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
     wc.hCursor        = ::LoadCursor(0, IDC_ARROW);
     wc.hIcon          = ::LoadIcon(0, IDI_WINLOGO);
     wc.hIconSm        = ::LoadIcon(0, IDI_WINLOGO);
     wc.hInstance      = ::GetModuleHandle(0);
     wc.lpfnWndProc    = WndProc;
     wc.lpszClassName  = WindowClass.c_str();
     return (::RegisterClassEx(&wc) != 0);
}

bool SystemEngine::WindowCreation(const unsigned int _Width, const unsigned int _Height)
{
     hWnd = ::CreateWindow(WindowClass.c_str(), Caption.c_str(), Style,
                 Position.x, Position.y, _Width, _Height, HWND_DESKTOP, 0, 0, 0);
     return (hWnd != INVALID_HANDLE_VALUE);
}

void SystemEngine::MessageLoop(void(*Execute)())
{
     MSG msg;
     while(true)
     {
          while(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0)
          {
               if(msg.message == WM_QUIT)
               {
                    break;
               }
               ::TranslateMessage(&msg);
               ::DispatchMessage(&msg);
          }
          if(msg.message == WM_QUIT)
          {
               break;
          }
          ProcessKbd();
          
          if(Execute != 0)
          {
               Execute();
          }
     }
}

void SystemEngine::Release()
{
     ::DeleteDC(MemDC);
     ::ReleaseDC(hWnd, MainDC);
     
     if(NEXT_TIMER_ID > 1000)
     {
          std::list<unsigned int>::const_iterator i;
          for(i = Timers.begin(); i != Timers.end(); i++)
          {
                ::KillTimer(hWnd, (*i));
          }
     }
     
     ::UnregisterClass(WindowClass.c_str(), 0);
}

void SystemEngine::CreateTimer(TIMERPROC Proc, unsigned int Delay)
{
     Timers.push_back(::SetTimer(hWnd, NEXT_TIMER_ID++, Delay, Proc));
}

int SystemEngine::RandomNumber(int min, int max)
{
     return ((rand() % (max-min)) + min);
}

void SystemEngine::ProcessKbd()
{
     if(Keys[VK_HOME])
     {
          SetWindowed(!Windowed);
     }
     if(Keys[VK_ESCAPE])
     {
          PostQuitMessage(0);
     }
}

void SystemEngine::SetCaption(char* fmt, ...)
{
     char buffer[256];
     va_list list;
     va_start(list, fmt);
     ::vsprintf(buffer, list, fmt);
     va_end(list);
     
     Caption = buffer;
     ::SendMessage(hWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)Caption.c_str());
}

void SystemEngine::SetWindowed(bool _windowed)
{
     Windowed = _windowed;
     if(Windowed == false)
     {
          DEVMODE DMode;
          ZeroMemory(&DMode, sizeof(DMode));
          DMode.dmSize       = sizeof(DMode);
          DMode.dmBitsPerPel = 32;
          DMode.dmPelsWidth  = Width;
          DMode.dmPelsHeight = Height;
          DMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
          if(::ChangeDisplaySettings(&DMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
          {
               MessageBox(0, "Couldn't change screen resolution", Caption.c_str(), 0);
          }
          else
          {
               ::SetWindowLong(hWnd, GWL_STYLE, (LONG)(WS_POPUP | WS_VISIBLE));
          }
     }
     else
     {
          if(::ChangeDisplaySettings(0, CDS_RESET) != DISP_CHANGE_SUCCESSFUL)
          {
               MessageBox(0, "Couldn't change screen resolution", Caption.c_str(), 0);
          }
          else
          {
               ::SetWindowLong(hWnd, GWL_STYLE, (LONG)(Style | WS_VISIBLE));
          }
     }
     ::UpdateWindow(hWnd);
}

void SystemEngine::SetKey(const unsigned int index, bool state)
{
     Keys[index] = state;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wprm, LPARAM lprm)
{
     switch(msg)
     {
          case WM_KEYDOWN:
               MyEngine.SetKey(wprm, true);
               break;
          case WM_KEYUP:
               MyEngine.SetKey(wprm, false);
               break;
          case WM_DESTROY:
               ::PostQuitMessage(0);
               break;
          default:
               return ::DefWindowProc(hWnd, msg, wprm, lprm);
     }
     return 0;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by oconnellseanm
Look at other 3d engines and see how they design theirs.
Here are a few

http://www.devlib-central.org
http://www.ogre3d.org
http://irrlicht.sourceforge.net

A few more. [smile]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this