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