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

     

  • 相关阅读:
    Pass360[最新].cpp
    在任意的远程桌面的session中运行指定的程序
    C++内存泄露的检测(三)
    在release模式下debug
    [转]VC Studio 使用技巧大全
    C++内存泄露的检测(一)
    获取系统用户所对应的配置路径
    关于Debug和Release之本质区别的讨论
    GDB 的使用
    struct termios
  • 原文地址:https://www.cnblogs.com/tomboy/p/2568304.html
Copyright © 2020-2023  润新知