• Advertisement
Sign in to follow this  

Improvements to my game engine.

This topic is 4755 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

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
Advertisement
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

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
Sign in to follow this  

  • Advertisement