• 使用C++与SFML编写一个简单的撞球游戏Part6——添加弹板控制与弹球


    我们先来为游戏添加一个弹球吧!!!我们将采用以下图片ball.png

    (右键另存为,并放到images文件夹里面去)

    方法跟添加玩家弹板大同小异,将其名为GameBall.h:

    #pragma once
    #include "visiblegameobject.h"
    
    //继承自VisibleGameObject
    class GameBall :
        public VisibleGameObject
    {
    public:
        GameBall();
        virtual ~GameBall();
    };

    以及GameBall.cpp

    #include "StdAfx.h"
    #include "GameBall.h"
    
    
    GameBall::GameBall()
    {
        //assert方法作用:括号里面的表达式必须返回true,若返回false则会出现系统错误
        Load("images/ball.png");
        assert(IsLoaded());
    
        GetSprite().setOrigin(15,15);
    }
    
    
    GameBall::~GameBall()
    {
    }

    当然还有Game类也要修改,在Game.h中include GameBall头文件后,在Game.cpp的start方法里添加如下代码:

      GameBall *ball = new GameBall();
      ball->SetPosition((SCREEN_WIDTH/2),(SCREEN_HEIGHT/2)-15);
    
    _gameObjectManager.Add("Ball",ball);

    补充点:SCREEN_WIDTH跟SCREEN_HEIGHT是定义在Game.h中的,用以代替start方法中的常量的

    const static int SCREEN_WIDTH = 1024;
    const static int SCREEN_HEIGHT = 768;

    接下来就只剩下令弹板能够被玩家所控制了!!!

    首先在VisibleGameObject.h添加几个方法:

    #pragma once
    class VisibleGameObject
    {
    public:
        VisibleGameObject();
        virtual ~VisibleGameObject();
    
        virtual void Load(std::string filename);
        virtual void Draw(sf::RenderWindow & window);
        virtual void Update(float elapsedTime);
    
        virtual void SetPosition(float x, float y);
        virtual sf::Vector2f GetPosition() const;
        virtual bool IsLoaded() const;
    
        //设置成protected是为了只供继承的子类调用
    protected:
        sf::Sprite& GetSprite();
    
    private:
        sf::Sprite  _sprite; //存储图片
        sf::Texture _image;  //读取图片
        std::string _filename; //图片路径
        bool _isLoaded; //读取是否成功
    
    };

    以及其实现代码VisibleGameObject.cpp

    void VisibleGameObject::Update(float elapsedTime)
    {
    }
    
    sf::Vector2f VisibleGameObject::GetPosition() const
    {
        if(_isLoaded)
        {
            return _sprite.getPosition();
        }
        return sf::Vector2f();
    }
    
    
    sf::Sprite& VisibleGameObject::GetSprite()
    {
        return _sprite;
    }
    
    bool VisibleGameObject::IsLoaded() const
    {
        return _isLoaded;
    }

    还有给玩家弹板相应的更改,在PlayerPaddle.h里面添加

    #pragma once
    #include "VisibleGameObject.h"
    
    class PlayerPaddle :
        public VisibleGameObject
    {
    public:
        PlayerPaddle(void);
        ~PlayerPaddle(void);
    
        void Update(float elapsedTime);
        void Draw(sf::RenderWindow& rw);
    
        float GetVelocity() const;
    
    private:
        float _velocity;
        float _maxVelocity;
    };

    PlayerPaddle.cpp

    #include "StdAfx.h"
    #include "PlayerPaddle.h"
    #include "Game.h"
    
    //初始化最初速度和最大速度以及读取弹板图片并设置其初始位置
    PlayerPaddle::PlayerPaddle() :
        _velocity(0),
        _maxVelocity(600.0f)
    {
        Load("images/paddle.png");
        assert(IsLoaded());
    
        GetSprite().setOrigin(GetSprite().getLocalBounds().width /2, GetSprite().getLocalBounds().height / 2);
    
    }
    
    
    PlayerPaddle::~PlayerPaddle(void)
    {
    }
    
    
    void PlayerPaddle::Draw(sf::RenderWindow & rw)
    {
        VisibleGameObject::Draw(rw);
    }
    
    //获取弹板当前速度
    float PlayerPaddle::GetVelocity() const
    {
        return _velocity;
    }
    
    //由系统消息中判断键盘按键,并让弹板做出相应移动,elapsedTime为更新的间隔,即fps
    void PlayerPaddle::Update(float elapsedTime)
    {
    
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
        {
            _velocity-= 3.0f;
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
        {
            _velocity+= 3.0f;
        }
    
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
        {
            _velocity= 0.0f;
        }
    
        //如果弹板速度大于最大速度,就让其等于最大速度,最小速度也同理可得
        if(_velocity > _maxVelocity)
            _velocity = _maxVelocity;
    
        if(_velocity < -_maxVelocity)
            _velocity = -_maxVelocity;
    
        //获取弹板当前位置,判断其是否到达游戏窗体边界,到达则令其速度反向
        sf::Vector2f pos = this->GetPosition();
    
        if(pos.x  < GetSprite().getLocalBounds().width/2
            || pos.x > (Game::SCREEN_WIDTH - GetSprite().getLocalBounds().width/2))
        {
            _velocity = -_velocity;
        }
        //_velocity * elapsedTime为弹板移动距离
        GetSprite().move(_velocity * elapsedTime, 0);
    }

    跟着同样由GameObjectManager作统一的更新(就像DrawAll一样),对于GameObjectManager.h,在其public部分添加

    void UpdateAll();

    在private部分添加

    //用来获取fps
    sf::Clock clock;

    还有其实现部分GameObjectManager.cpp

    //调用对象各自的update方法为其更新,timeDelta可以看成是fps
    void GameObjectManager::UpdateAll()
    {
        std::map<std::string,VisibleGameObject*>::const_iterator itr = _gameObjects.begin();
        float timeDelta = clock.restart().asSeconds();
    
        while(itr != _gameObjects.end())
        {
            itr->second->Update(timeDelta);
            itr++;
        }
    
    }

    最后就是更改Game类了,对于Game.h,在start方法下面添加

    static sf::RenderWindow& GetWindow();
    const static sf::Event& GetInput();
    const static int SCREEN_WIDTH = 1024;
    const static int SCREEN_HEIGHT = 768;

    至于Game.cpp

    sf::RenderWindow& Game::GetWindow()
    {
        return _mainWindow;
    }
    
    //创建一个Event类型变量,从系统消息队列里面取出消息并放到该变量里然后返回
    const sf::Event& Game::GetInput() 
    {
        sf::Event currentEvent;
        _mainWindow.pollEvent(currentEvent);
        return currentEvent;
    }

    还要在DrawAll方法之前调用

    _gameObjectManager.UpdateAll();

    否则弹板是不会动的

    好了,现在按F5试试移动弹板吧~~~

    如果觉得上面说的很凌乱的话,,点击这里可以下载本part更改过的代码~~~

  • 相关阅读:
    uvalive 3644 X-Plosives
    uva 11997 K Smallest Sums
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) D. Sorting the Coins
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) C. Classroom Watch
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) B. Divisiblity of Differences
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) A. Trip For Meal
    1004. 成绩排名 (20)
    1003. 我要通过!(20)
    1002. 写出这个数 (20)
    1001. 害死人不偿命的(3n+1)猜想 (15)
  • 原文地址:https://www.cnblogs.com/tomboy/p/2568973.html
Copyright © 2020-2023  润新知