SDL始めました

試しに自作のフレームワークを公開してみる。
まだ全然作りかけですが…(´Д`;
 
なにが凄いかというと(まあ、フレームワークとしては当たり前ですが)
CSDLManager::Run()を呼ぶと、勝手にゲームループがぐるぐる回ってくれるので、
ISceneを継承して、各シーンを実装すればよい、という
「制御の逆転」(シーンが呼ばれる)を実現しているところです。(えっへん)
 
すべてを管理する、CSDLManager.h/.cpp

#pragma once

#include <./SDL.h>

#include "SDLGraphics.h"
#include "SDLLogger.h"
#include "ISceneManager.h"

/**
 * すべてを管理するクラス
 */
class CSDLManager
{
private:
	int m_width;
	int m_height;
	int m_bpp;
	int m_vFlag;
	// スクリーンサーフェイス
	SDL_Surface *m_surface;

	CSDLGraphics m_graphics;
	CSDLLogger m_logger;
	ISceneManager *m_sceneManger;

public:
	CSDLManager(void)
	{
		m_surface = NULL;
		m_width   = 0;
		m_height  = 0;
		m_bpp     = 0;
		m_vFlag   = 0;
		m_sceneManger = NULL;
	}
	~CSDLManager(void) {SDL_Quit();}

	// 初期化
	void Init(int width=640, int height=480, int bpp=16, int vFlag=SDL_SWSURFACE, int flag=SDL_INIT_VIDEO);
	// 実行
	void Run();

	void SetSceneManger(ISceneManager *manager) {m_sceneManger = manager;}
	void InitScene() {m_sceneManger->GetScene()->Init();}
	void ChangeScene(int key) {m_sceneManger->ChangeScene(key);}
};
#include ".\sdlmanager.h"

/**
 * 初期化
 */
void CSDLManager::Init(int width, int height, int bpp, int vFlag, int flag)
{
	if(SDL_Init(flag)!= 0)
	{
		// エラー処理
		m_logger.Error("SDL_Initにて失敗:%s", SDL_GetError());
		throw "Error";
	}

    m_surface = SDL_SetVideoMode(width, height, bpp, vFlag);
	if(m_surface == NULL)
	{
		// エラー処理
		m_logger.Error("スクリーン初期化失敗:%s", SDL_GetError());
		throw "Error";
	}
	m_width  = width;
	m_height = height;
	m_bpp    = bpp;
	m_vFlag  = vFlag;

	m_graphics.SetSurface(m_surface);

	// シーンの生成
	std::map<int, IScene*> *sceneMap = m_sceneManger->GetSceneMap();
	std::map<int, IScene*>::iterator iter;
	for(iter = sceneMap->begin(); iter != sceneMap->end(); ++iter)
	{
		iter->second->Create(&m_graphics);
	}
}

/**
 * 実行
 */
void CSDLManager::Run()
{
    bool bDone = false;
    while(!bDone)
	{
		SDL_FillRect(m_surface, NULL, SDL_MapRGB(m_surface->format, 0, 0, 0));
		// 画面の初期化。黒に塗りつぶしている。
		SDL_Event event;
		while(SDL_PollEvent(&event))
		{
			// イベント処理
			switch(event.type)
			{
			case SDL_QUIT:
				bDone = true;
				break;
			case SDL_KEYDOWN:
				if(event.key.keysym.sym == SDLK_ESCAPE)
				{
					// ESCキーでも終了する。
					bDone = true;
				}
				break;
			}
		}
		// シーン更新
		m_sceneManger->GetScene()->Update();

		// 描画をウインドウ画面に反映する。
		SDL_Flip(m_surface);
		// ウエイト
		SDL_Delay(10);
	}
}

 
描画機能を管理する、CSDLGraphics.h/.cpp
(といっても矩形描画機能しか、まだないですが(´∀`;

#pragma once

#include <./SDL.h>

/**
 * 描画クラス
 */
class CSDLGraphics
{
private:
	SDL_Surface *m_surface;
public:
	CSDLGraphics(void) 
	{
		m_surface = NULL;
	}
	~CSDLGraphics(void){}

	void SetSurface(SDL_Surface *surface) {m_surface = surface;}

	void FillRect(int x, int y, int w, int h, int r, int g, int b);
private:
	void _FillRect(SDL_Surface *dest, int x, int y, int w, int h, int r, int g, int b);
};
#include ".\sdlgraphics.h"

void CSDLGraphics::FillRect(int x, int y, int w, int h, int r, int g, int b)
{
	_FillRect(m_surface, x, y, w, h, r, g, b);
}

void CSDLGraphics::_FillRect(SDL_Surface *dest, int x, int y, int w, int h, int r, int g, int b)
{
  if(w < 0 || h < 0) return;
  if(r < 0 || 255 < r || g < 0 || 255 < g || b < 0 || 255 < b) return;

  SDL_Rect rect = {x, y, w, h};
  SDL_FillRect(dest, &rect, SDL_MapRGB(dest->format, r, g, b));
}

 
ログ・エラー出力機能を持った、CSDLLogger.h/.cpp

#pragma once

#ifdef WIN32
	#include <windows.h>
#endif
#include <stdarg.h>
#include <cstdio>
#include <fstream>
#include <string>

/**
 * ログ・エラー出力クラス
 */
class CSDLLogger
{
private:
	std::ofstream m_log; 
public:
	CSDLLogger(void)
	{
		m_log.open("execute.log");
	}
	~CSDLLogger(void)
	{
		m_log.close();
	}

	void Error(char *buf, ...);
	void Write(const char *str);
	void WriteString(std::string str);
};
#include ".\sdllogger.h"

#include <iostream>

void CSDLLogger::Error(char *buf, ...)
{
	char message[256];
	vsprintf(message, buf, (char*)(&buf + 1));

#ifdef WIN32
    MessageBox(NULL, message, "Error", MB_OK);
#else
    std::cerr<< "Error:" << message << std::endl;
#endif
	std::string str = "Error:";
	str += message;
	WriteString(str);
}

void CSDLLogger::WriteString(std::string str)
{
	Write(str.c_str());
}

void CSDLLogger::Write(const char *str)
{
	m_log << str << std::endl;
	m_log.flush();
}

 
シーン遷移を管理する、ISceneManager.h/.cpp

#pragma once

#include <map>

#include "IScene.h"

/**
 * シーン管理クラス
 */
class ISceneManager
{
private:
	std::map<int, IScene*> m_sceneMap;
	IScene *m_currentScene;
public:
	ISceneManager(void)
	{
		m_currentScene = NULL;
	}
	virtual ~ISceneManager(void){}

	void Regist(int key, IScene *scene);
	void ChangeScene(int key);
	IScene* GetScene() {return m_currentScene;}
	std::map<int, IScene*>* GetSceneMap() {return &m_sceneMap;}
};
#include ".\iscenemanager.h"

void ISceneManager::Regist(int key, IScene *scene)
{
	m_sceneMap.insert(std::pair<int, IScene*>(key, scene));
}

void ISceneManager::ChangeScene(int key)
{
	std::map<int, IScene*>::iterator iter = m_sceneMap.find(key);
	m_currentScene = iter->second;
}

 
シーンの基底クラス、IScene.h/.cpp

#pragma once

#include "SDLGraphics.h"

/**
 * シーン基底クラス
 */
class IScene
{
protected:
	CSDLGraphics *m_g;
public:
	IScene(void)
	{
		m_g = NULL;
	}
	virtual ~IScene(void) {}

	void Create(CSDLGraphics *sdl);
	virtual void Init() = 0;
	virtual void Update() = 0;
};
#include ".\iscene.h"

void IScene::Create(CSDLGraphics *g)
{
	m_g = g;
}

 
ここからがサンプルです。
シーンの実装サンプル。CSceneMain.h/.cpp

#pragma once
#include "iscene.h"

/**
 * ISceneの実装サンプル
 */
class CSceneMain : public IScene
{
public:
	CSceneMain(void) {};
	~CSceneMain(void){};

	void Init();
	void Update();
};
#include ".\scenemain.h"

#include <stdlib.h>

void CSceneMain::Init()
{
	// シーンの初期化処理を入れる
}

void CSceneMain::Update()
{
	// 矩形のランダム描画
	m_g->FillRect(
		rand()%640,
		rand()%480,
		rand()%640,
		rand()%480,
		0,
		rand()%255,
		0);
}

 
エントリポイント。main.cpp

#include "SDLManager.h"
#include "SceneMain.h"

int main(int argc, char* argv[])
{
	CSDLManager sdl;
	ISceneManager mgr;
	CSceneMain main;

	// シーン登録
	mgr.Regist(0, &main);
	// シーンマネージャー登録
	sdl.SetSceneManger(&mgr);
	// SDL初期化
	sdl.Init();

	// シーン遷移
	sdl.ChangeScene(0);
	// 実行
	sdl.Run();

	return 0;
}