使用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确认一下吧~~~

 

原文地址:https://www.cnblogs.com/tomboy/p/2568304.html