使用C++与SFML编写一个简单的撞球游戏Part5——对象管理
这一part,我们将创建一个对象管理器来统一管理我们的对象。
在这个项目里,对象的数目寥寥无几,为什么要那么麻烦创建这个管理器呢?
这是一个关于布局的问题,如果我们正在写一个射击游戏,要管理数以百计的子弹或者敌人时,这个管理器就很有必要了。
废话就少说了,我们将这管理器名为GameObjectManager,其代码如下
GameObjectManager.h
#pragma once #include "VisibleGameObject.h" class GameObjectManager { public: GameObjectManager(); ~GameObjectManager(); void Add(std::string name, VisibleGameObject* gameObject); void Remove(std::string name); int GetObjectCount() const; VisibleGameObject* Get(std::string name) const; void DrawAll(sf::RenderWindow& renderWindow); private: //键值对关联容器map,键为对象名称,值为对象指针 std::map<std::string, VisibleGameObject*> _gameObjects; //重载操作符()来得到一个用于清理VisibleGameObject对象内存的函子(functor) //函子,简单来说是指被当成函数使用的对象,在这里是指GameObjectDeallocator() struct GameObjectDeallocator { void operator()(const std::pair<std::string,VisibleGameObject*> & p) const { delete p.second; } }; };
GameObjectManager.cpp
#include "stdafx.h" #include "GameObjectManager.h" GameObjectManager::GameObjectManager() { } GameObjectManager::~GameObjectManager() { //释放map容器里面所有VisibleGameObject对象的内存 std::for_each(_gameObjects.begin(),_gameObjects.end(),GameObjectDeallocator()); } void GameObjectManager::Add(std::string name, VisibleGameObject* gameObject) { //通过一个pair把对象名跟对象添加进容器 _gameObjects.insert(std::pair<std::string,VisibleGameObject*>(name,gameObject)); } void GameObjectManager::Remove(std::string name) { //用容器的find方法查找对象,若找到则释放其内存并清除键名 std::map<std::string, VisibleGameObject*>::iterator results = _gameObjects.find(name); if(results != _gameObjects.end() ) { delete results->second; _gameObjects.erase(results); } } VisibleGameObject* GameObjectManager::Get(std::string name) const { //find方法查找对象,找到则返回对象 std::map<std::string, VisibleGameObject*>::const_iterator results = _gameObjects.find(name); if(results == _gameObjects.end() ) return NULL; return results->second; } int GameObjectManager::GetObjectCount() const { return _gameObjects.size(); } void GameObjectManager::DrawAll(sf::RenderWindow& renderWindow) { //把对象添加进游戏场景里面 std::map<std::string,VisibleGameObject*>::const_iterator itr = _gameObjects.begin(); while(itr != _gameObjects.end()) { itr->second->Draw(renderWindow); itr++; } }
另外Game类也要做出相应的改变
Game.h
#pragma once //#include "SFML/Window.hpp" //#include "SFML/Graphics.hpp" #include "PlayerPaddle.h" #include "GameObjectManager.h" class Game { public: static void Start(); private: static bool IsExiting(); static void GameLoop(); static void ShowSplashScreen(); static void ShowMenu(); //用枚举类型来代替常量表示游戏状态 enum GameState { Uninitialized, ShowingSplash, Paused, ShowingMenu, Playing, Exiting }; static GameState _gameState; static sf::RenderWindow _mainWindow; //static PlayerPaddle _player1; static GameObjectManager _gameObjectManager; };
Game.cpp
#include "stdafx.h" #include "Game.h" #include "MainMenu.h" #include "SplashScreen.h" void Game::Start(void) { if(_gameState != Uninitialized) return; //设置窗口参数,对于像1024,768这样的常量是不应该以这种形式出现的, //在之后的文章将会更改 _mainWindow.create(sf::VideoMode(1024,768,32),"BallGame!"); //添加玩家弹板并设置其位置 PlayerPaddle *player1 = new PlayerPaddle(); player1->Load("images/paddle.png"); player1->SetPosition((1024/2)-45,700); _gameObjectManager.Add("Paddle1",player1); _gameState = Game::ShowingSplash; //游戏循环,当游戏状态为Exiting则退出游戏 while(!IsExiting()) { GameLoop(); } _mainWindow.close(); } bool Game::IsExiting() { if(_gameState == Game::Exiting) return true; else return false; } void Game::GameLoop() { sf::Event currentEvent; //从消息队列里面拿出消息 _mainWindow.pollEvent(currentEvent); switch(_gameState) { case Game::ShowingSplash: { ShowSplashScreen(); break; } case Game::ShowingMenu: { ShowMenu(); break; } case Game::Playing: { //用黑色填充游戏画面 _mainWindow.clear(sf::Color(0,0,0)); //_player1.Draw(_mainWindow); _gameObjectManager.DrawAll(_mainWindow); _mainWindow.display(); if(currentEvent.type == sf::Event::Closed) { _gameState = Game::Exiting; } if(currentEvent.type == sf::Event::KeyPressed) { if(currentEvent.key.code == sf::Keyboard::Escape) ShowMenu(); } break; } } } void Game::ShowSplashScreen() { SplashScreen splashScreen; splashScreen.Show(_mainWindow); _gameState = Game::ShowingMenu; } void Game::ShowMenu() { MainMenu mainMenu; MainMenu::MenuResult result = mainMenu.Show(_mainWindow); switch(result) { case MainMenu::Exit: _gameState = Exiting; break; case MainMenu::Play: _gameState = Playing; break; } } //此处要手动声明静态变量,不然编译器会报错 Game::GameState Game::_gameState = Uninitialized; sf::RenderWindow Game::_mainWindow; //PlayerPaddle Game::_player1; GameObjectManager Game::_gameObjectManager;
变化不大,请自行对照,最后按F5确认一下吧~~~