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; }