C ++ゲームの作成、パート2/3-状態ベースのプログラミング

C ++ゲームの作成、パート1/3-ミニフレームワークの作成

C ++でゲームを書く、パート3/3-ジャンルの古典



こんにちは、Habrahabr!



最初のレッスンを読んでおめでとうございます! 彼は十分に大きいです。 コードを減らし、結果を増やすことを約束します:)



この部分は何についてですか?







次の投稿では、自然なゲームがあります:)









2.1。 州



これで、ゲームが実際に何を構成しているのかを理解できたらうれしいです。



多くのメニュー、レベル、その他の「状態」があるゲームがあるとします。 どうやって彼らと対話できますか? 次のようなコードであることは明らかです。

void Update() { switch(state) { case State::MENU: // 100  case State::SETTINGS: // 200  case State::LEVEL1: //   } }
      
      





利便性の面で激しい失敗を引き起こします。



Screenなどの名前を持つクラスの各状態を独自の子孫にして、ゲームで使用するのはどうですか?



Screen.hを作成します

 #ifndef SCREEN_H #define SCREEN_H #include "Project.h" #include "Game.h" class Game; class Screen { protected: Game* game; public: void SetController(Game* game); virtual void Start(); virtual void Update(); virtual void Destroy(); }; #endif
      
      





このクラスにはGameのインスタンスがあり、継承者はGraphicsとInputへのポインターを取得します。

相続人のための仮想機能:





Screen.cpp

 #include "Screen.h" void Screen::SetController(Game* game) { this->game = game; } void Screen::Start() { } void Screen::Update() { } void Screen::Destroy() { }
      
      







Game.hおよびGame.cppの更新

 #ifndef _GAME_H_ #define _GAME_H_ #include "Project.h" #include "Graphics.h" class Graphics; #include "Input.h" class Input; #include "Screen.h" class Screen; class Game { private: bool run; Graphics* graphics; Input* input; Screen* screen; public: Game(); int Execute(Screen* startscreen, int width, int height); Graphics* GetGraphics(); Input* GetInput(); Screen* GetScreen(); void SetScreen(Screen* screen); void Exit(); }; #endif
      
      





ScreenオブジェクトはGameクラスに含まれ、Execute関数が変更されます。main.cppからScreen相続人のオブジェクトを渡します。



Game.cpp

 #include "Game.h" Game::Game() { run = true; } int Game::Execute(Screen* startscreen, int width, int height) { graphics = new Graphics(width,height); input = new Input(); screen = startscreen; screen->SetController(this); this->screen->Start(); while(run) { input->Update(); screen->Update(); } screen->Destroy(); delete graphics; delete input; delete screen; SDL_Quit(); return 0; } Graphics* Game::GetGraphics() { return graphics; } Input* Game::GetInput() { return input; } Screen* Game::GetScreen() { return screen; } void Game::SetScreen(Screen* screen) { this->screen->Destroy(); delete this->screen; this->screen = screen; this->screen->SetController(this); this->screen->Start(); } void Game::Exit() { run = false; }
      
      





Executeメソッドは重要な変更を受けます-現在の状態を処理します

SetScreenは新しい状態を設定し、古い状態をリセットします。

私の意見では、GetScreenはほとんど役に立たない-このようなレベルをリロードすることを除いて

 SetScreen(GetScreen());
      
      





しかし、すべてのリソースをリロードするのは愚かなことです。 一般的に、自分で決めてください:)



2.2。 コンパイル! コンパイル!



少し遊びましょうか?

main.cppファイルを開き、この状態に変更します。

 #include "Project.h" class MyScreen : public Screen { public: void Start() { MessageBox(0,"Hello, HabraHabr!","Message",MB_OK); } }; int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) { Game game; return game.Execute(new MyScreen(),500,350); }
      
      





彼がしていることは、標準のWindowsメッセージを印刷することだけです。



注意深いユーザーは、赤いXをクリックしてもウィンドウが閉じないことに注意し、ウィンドウのタイトルもウィンドウを削除するのに役立ちます。 問題ありません-仕事を引き受けます:

 #include "Project.h" class MyScreen : public Screen { private: Input* input; public: void Start() { input = game->GetInput(); SDL_WM_SetCaption("Hello, HabraHabr!",0); MessageBox(0,"Hello, HabraHabr!","Message",MB_OK); } void Update() { if(input->IsKeyDown('w') || input->IsExit()) game->Exit(); } }; int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) { Game game; return game.Execute(new MyScreen(),500,350); }
      
      





私たちは黒い窓を使いたくありません。何かを描きましょうか?



 #include "Project.h" class MyScreen : public Screen { private: Input* input; Graphics* graphics; Image* test; public: void Start() { input = game->GetInput(); graphics = game->GetGraphics(); SDL_WM_SetCaption("Hello, HabraHabr!",0); test = graphics->NewImage("habr.bmp"); } void Update() { if(input->IsExit()) game->Exit(); graphics->DrawImage(test,0,0); graphics->Flip(); } }; int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) { Game game; return game.Execute(new MyScreen(),300,225); }
      
      







パフォーマンスの点でより知識のあるプログラマーは、位置を変えなければ、サイクルごとに絵を描くのは無意味であることにすぐに気付くでしょう。 本当に-ライン

  graphics->DrawImage(test,0,0); graphics->Flip();
      
      





Update()からStart()の最後に移動する必要があります



2.3。 まとめ



私はあなたが感動し、多くを学んだことを願っています:)

その後、間違いなく3番目のレッスンに進みます



すべての質問については、PMに連絡してください。ハブに登録できない場合は、メールizarizar@mail.ruにご連絡ください。






All Articles