使用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更改过的代码~~~

posted on 2012-06-29 07:33  tomboy  阅读(1579)  评论(0编辑  收藏  举报

导航