Sprites do not move in SFML - c++

I am working with my first small project in SFML. I made a ball (projectile) which is bouncing around on the screen and a player which is movable. The problem however, occurred when I tried to make an Objecthandler to my objects. After letting the handler taking control of the drawing and updating of the objects, the player and the ball just stopped and became unmovable. My question is why?
The ball:
#ifndef PROJECTILE_H
#define PROJECTILE_H
#include <SFML\Graphics.hpp>
using namespace std;
class Projectile : public sf::Drawable {
private:
sf::Texture texture;
sf::Sprite sprite;
public:
Projectile();
virtual ~Projectile();
sf::Sprite getSprite() const;
virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const;
};
#endif //PROJECTILE_H
#include "Projectile.h"
#include <iostream>
Projectile::Projectile() {
if (!this->texture.loadFromFile("../Resources/projectile.png")) {
cout << "Error! Projectile sprite could not be loaded!" << endl;
}
this->sprite.setPosition(sf::Vector2f(0.0f, 0.0f));
this->sprite.setTexture(this->texture);
sf::FloatRect boundingBoxProjectile = this->sprite.getGlobalBounds();
}
Projectile::~Projectile() {
}
sf::Sprite Projectile::getSprite() const{
return this->sprite;
}
void Projectile::draw(sf::RenderTarget & target, sf::RenderStates states) const {
target.draw(sprite, states);
}
The handler:
#ifndef OBJECTHANDLER_H
#define OBJECTHANDLER_H
#include "Block.h"
#include "Player.h"
#include "Projectile.h"
using namespace std;
class ObjectHandler : public sf::Drawable {
private:
Player player;
Block block;
Projectile projectile;
int hitX = 0;
int hitY = 0;
float checkX;
float checkY;
float keyFrameDuration = 0.0f;
float speed = 500.0f;
public:
ObjectHandler();
virtual ~ObjectHandler();
void updateProjectile(float dt);
void updatePlayer(float dt);
void updateBlock(float dt);
virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const;
};
#endif OBJECTHANDLER_H
#include "ObjectHandler.h"
ObjectHandler::ObjectHandler() {
this->projectile = projectile;
this->block = block;
this->player = player;
}
ObjectHandler::~ObjectHandler() {
}
void ObjectHandler::updateProjectile(float dt) {
sf::Vector2f direction;
if (hitX == 0) {
direction = sf::Vector2f(0.5f, checkY);
checkX = 0.5f;
if (this->projectile.getSprite().getPosition().x >= 700) {
hitX = 1;
}
}
else if (hitX == 1) {
direction = sf::Vector2f(-0.5f, checkY);
checkX = -0.5f;
if (this->projectile.getSprite().getPosition().x <= 0) {
hitX = 0;
}
}
if (hitY == 0) {
direction = sf::Vector2f(checkX, 0.5f);
checkY = 0.5f;
if (this->projectile.getSprite().getPosition().y >= 460) {
hitY = 1;
}
}
else if (hitY == 1) {
direction = sf::Vector2f(checkX, -0.5f);
checkY = -0.5f;
if (this->projectile.getSprite().getPosition().y <= 0) {
hitY = 0;
}
}
this->projectile.getSprite().move(direction * speed * dt);
}
void ObjectHandler::draw(sf::RenderTarget & target, sf::RenderStates states) const {
this->block.draw(target, states);
this->projectile.draw(target, states);
this->player.draw(target, states);
}
And Game:
#ifndef GAME_H
#define GAME_H
#include <SFML\Graphics.hpp>
#include "ObjectHandler.h"
class Game : public sf::Drawable {
private:
virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const;
sf::Texture backgroundTexture;
sf::Sprite backgroundSprite;
ObjectHandler object;
public:
Game();
virtual ~Game();
void update(float dt);
};
#endif // GAME_H
#include "Game.h"
#include <iostream>
using namespace std;
void Game::draw(sf::RenderTarget & target, sf::RenderStates states) const {
target.draw(backgroundSprite, states);
target.draw(this->object, states);
}
Game::Game() {
if (!backgroundTexture.loadFromFile("../Resources/levelOne.jpg")) {
cout << "The background could not be loaded!" << endl;
}
backgroundSprite.setTexture(backgroundTexture);
}
Game::~Game() {
}
void Game::update(float dt) {
this->object.updatePlayer(dt);
this->object.updateProjectile(dt);
this->object.updateBlock(dt);
}

The problem is your sf::Sprite Projectile::getSprite()const returns a copy of the actual sprite. Hence projectile.getSprite().move(...) are called by the copy.
Make a method move for your Projectile:
void Projectile::move(const sf::Vector2f& amount)
{
sprite.move(amount);
}
and call it in ObjectHandler: projectile.move(...).
You might also want to return a constant reference to your sprite in getSprite to avoid multiple copies: const sf::Sprite& Projectile::getSprite()const. It will cause an error when you try to modify it by calling projectile.getSprite().move(...) and you will see the bug faster.

Related

Why is my SFML sprite not showing texture?

I'm trying to create a game. I have a class GameObjects that many classes will inherit from. The class GameObject has a draw method that takes the window address to the display. Why does the sprite show up without the texture when displayed like this?
This is the texture, more of a placeholder. I was able to load it in other files directly creating the sprite and drawing it.
Here is my main.cpp
#include <iostream>
#include "Game.h"
int main()
{
//window setup
Game game;
//Initialize game
game.start();
return 0;
}
Here is my Game.h
#pragma once
#include "GameObject.h"
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/Audio.hpp>
#include <iostream>
class Game
{
private:
//window variables
int w_width;
int w_height;
sf::RenderWindow window;
sf::Event ev;
bool isRunning;
std::vector<GameObject> o_vector;
void initVariables();
void initWindow();
void initObjects();
void drawObjects();
public:
void start();
void run();
void input();
void update();
void render();
};
And Game.cpp
#include "Game.h"
#include "GameObject.h"
void Game::start()
{
this->initVariables();
this->initWindow();
this->initObjects();
this->run();
}
//Initializations
void Game::initVariables()
{
isRunning = true;
//window variables
w_width = 1280;
w_height = 720;
}
void Game::drawObjects()
{
for (int o_count = 0; o_count < o_vector.size(); o_count++)
{
o_vector.at(o_count).draw(window);
}
}
void Game::initWindow()
{
//window creation
window.create(sf::VideoMode(w_width, w_height), "The Dungeon Crawler", sf::Style::Titlebar | sf::Style::Close | sf::Style::Resize);
}
void Game::initObjects()
{
GameObject baseObject;
o_vector.push_back(baseObject);
}
void Game::run()
{
while (isRunning)
{
input();
update();
render();
}
}
void Game::input()
{
while (window.pollEvent(ev))
{
switch (ev.type)
{
case sf::Event::Closed:
window.close();
break;
case sf::Event::KeyPressed:
switch (ev.key.code)
{
case sf::Keyboard::Escape:
window.close();
break;
case sf::Keyboard::A:
break;
}
}
}
}
void Game::update()
{
}
void Game::render()
{
window.clear(sf::Color(0, 0, 128));
drawObjects();
window.display();
}
Here is GameObject.h
#pragma once
#include <vector>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
class GameObject
{
private:
std::string name;
std::vector<int> o_position;
std::vector<int> o_size;
std::string t_path;
sf::Sprite o_sprite;
sf::Texture o_texture;
void initVariables();
public:
//Constructors & Destructors
GameObject();
~GameObject();
//Getters
std::vector<int> getPos();
std::vector<int> getSize();
sf::Sprite getSprite();
//Setters
void setPos(std::vector<int>pos_in);
void setSize(std::vector<int> size_in);
//Graphics
void draw(sf::RenderWindow &displayWindow);
};
And GameObject.cpp
#include "GameObject.h"
GameObject::GameObject()
{
initVariables();
}
GameObject::~GameObject()
{
}
void GameObject::initVariables()
{
o_position = { 0,0 };
o_size = { 64,64 };
t_path = "Resources/EmptySquare.png";
if (!o_texture.loadFromFile(t_path))
{
std::cout << "Failed to load" << std::endl;
return;
}
o_sprite.setTexture(o_texture);
}
std::vector<int> GameObject::getPos()
{
return o_position;
}
std::vector<int> GameObject::getSize()
{
return o_size;
}
sf::Sprite GameObject::getSprite()
{
return o_sprite;
}
void GameObject::setPos(std::vector<int> pos_in)
{
o_position = pos_in;
}
void GameObject::setSize(std::vector<int> size_in)
{
o_size = size_in;
}
void GameObject::draw(sf::RenderWindow &displayWindow)
{
displayWindow.draw(o_sprite);
}
Thank you for any help!
the problem is this line in Game::initObjects()
GameObject baseObject;
o_vector.push_back(baseObject);
you creata a copy of GameObject.
so it will make a copy of o_sprite.
the o_sprite copies the texture pointer.
after this function ends, the texture pointer is no longer valid.
sf::Sprite has the member const Texture* m_texture; and when calling sf::Sprite::setTexture(const Texture& texture) this member m_texture will in fact point to the texture. That texture will be destructed after initObjects() ends, and your element at position 0 will have a o_sprite.m_texture that points to this destructed object. SFML/Sprite.hpp
you could define the correct operator=(GameObject) that implements the correct sprite copy - or in this case simply say:
void Game::initObjects()
{
o_vector.resize(1);
}
resize will call the constructor of GameObject and you will have no copies and therefore dangling pointers.
Another way would be for you to allocate game object on the heap and store a pointer to it in the vector. This way you will avoid the cost of copying.
To make these changes, declare baseObject as private member of Game class and in initObjects method allocate it on the heap.
class Game
{
private:
GameObject *baseObject;
std::vector<GameObject *> o_vector;
};
void Game::initObjects()
{
baseObject = new GameObject;
o_vector.push_back(baseObject);
}
void Game::drawObjects()
{
for (int o_count = 0; o_count < o_vector.size(); o_count++)
{
o_vector.at(o_count)->draw(window); // use -> operator to call draw
}
}
PS: Instead of raw pointer, you can also use C++11 smart pointer.

How to create a layout of bricks for Breakout game using a data/text file in C++ SFML?

I am creating a classic breakout game in C++ using SFML library. So far I have a movable paddle and ball implemented.
Currently, my goal is to create a layout of bricks. So far I have it so that a single brick is displayed. However, I want to make it so that I can draw a layout of bricks in text file using a letter (For example using letter 'B'), read that text file's brick layout and draw that layout in game.
I am not sure how to do this so any help would be great!
Here is my code so far (Note that I did not include for Paddle and Ball as I thought it was not needed for this problem):
GameObject.h
#pragma once
#include <SFML/Graphics.hpp>
class GameObject
{
protected:
sf::Vector2f position;
float speed;
sf::RenderWindow& m_window;
public:
GameObject(float startX, float startY, sf::RenderWindow& window);
virtual ~GameObject() {};
virtual void Draw() = 0;
virtual void Update() = 0;
};
GameObject.cpp
#include "GameObject.h"
GameObject::GameObject(float startX, float startY, sf::RenderWindow& window)
: position{ startX, startY }
, speed{ 0.5f }
, m_window{ window }
{
}
Brick.h
#pragma once
#include "GameObject.h"
class Brick : public GameObject
{
private:
sf::RectangleShape brickShape;
static constexpr int shapeWidth = 50;
static constexpr int shapeHeight = 20;
int color;
int strength;
public:
Brick(float startX, float startY, sf::RenderWindow& window);
sf::FloatRect getPosition();
sf::RectangleShape getShape();
int getStrength();
void setStrength(int strengthValue);
void Draw() override;
void Update() override;
};
Brick.cpp
#include "Brick.h"
Brick::Brick(float startX, float startY, sf::RenderWindow& window)
: GameObject{ startX, startY, window }
{
brickShape.setSize(sf::Vector2f(shapeWidth, shapeHeight));
brickShape.setPosition(position);
color = (rand() % 2) + 1;
if (color == 1)
{
brickShape.setFillColor(sf::Color::Yellow);
strength = 1;
}
else
{
brickShape.setFillColor(sf::Color(255, 165, 0));
strength = 2;
}
}
sf::FloatRect Brick::getPosition()
{
return brickShape.getGlobalBounds();
}
sf::RectangleShape Brick::getShape()
{
return brickShape;
}
int Brick::getStrength()
{
return strength;
}
void Brick::setStrength(int strengthValue)
{
strength = strengthValue;
}
void Brick::Draw()
{
m_window.draw(brickShape);
}
void Brick::Update()
{
}
Game.h
#pragma once
#include <SFML/Graphics.hpp>
#include "Paddle.h"
#include "Ball.h"
#include "Brick.h"
#include <algorithm>
#include <fstream>
#include <iostream>
class Game
{
private:
sf::RenderWindow& m_window;
std::unique_ptr<Paddle> player;
std::unique_ptr<Ball> ball;
std::unique_ptr<Brick> brick;
std::vector<std::unique_ptr<Brick>>bricks;
int bricksCountX;
int bricksCountY;
public:
const unsigned int m_windowWidth;
const unsigned int m_windowHeight;
public:
Game(sf::RenderWindow& window, const unsigned int& windowWidth, const unsigned int& windowHeight);
float RandomFloat(float a, float b);
void ReadFile();
void HandleCollision();
void HandleInput();
void Draw();
void Update();
void Run();
};
Game.cpp
#include "Game.h"
Game::Game(sf::RenderWindow& window, const unsigned int& windowWidth, const unsigned int& windowHeight)
: m_window{ window }
, m_windowWidth{ windowWidth }
, m_windowHeight{ windowHeight }
{
player = std::make_unique<Paddle>(m_windowWidth/2, m_windowHeight - 70, m_window);
ball = std::make_unique<Ball>(m_windowWidth / 2, m_windowHeight / 2, m_window);
ReadFile();
for (int i = 0; i < bricksCountX; i++)
for (int j = 0; j < bricksCountY; j++)
bricks.emplace_back(std::make_unique<Brick>((i + 1.5) * ((long long)brick->getShape().getSize().x + 3) + 22,
(j + 5) * (brick->getShape().getSize().y + 3), m_window));
}
float Game::RandomFloat(float a, float b)
{
return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
void Game::ReadFile()
{
// Create a text string, which is used to output the text file
std::string bricksText;
int numOfLines = 0;
// Read from the text file
std::ifstream MyReadFile("Bricks Layout.txt");
// Use a while loop together with the getline() function to read the file line by line
while (std::getline(MyReadFile, bricksText))
{
++numOfLines;
// Output the text from the file
bricksCountX = bricksText.length();
std::cout << bricksCountX;
}
bricksCountY = numOfLines;
// Close the file
MyReadFile.close();
}
void Game::HandleCollision()
{
if (ball->getShape().getPosition().x - ball->getRadius() < 0.0f)
{
ball->reboundLeft();
}
else if (ball->getShape().getPosition().x + ball->getRadius() > m_windowWidth)
{
ball->reboundRight();
}
else if (ball->getShape().getPosition().y - ball->getRadius() < 0.0f)
{
ball->reboundTop();
}
else if (ball->getShape().getPosition().y + ball->getRadius() > m_windowHeight)
{
ball->ballAngle = ball->ballAngle * -1;
}
else if (ball->getPosition().intersects(player->getPosition()))
{
ball->reboundPaddle(*player);
}
for (unsigned int i = 0; i < bricks.size(); i++)
{
if (ball->getPosition().intersects(bricks[i]->getPosition()))
{
if (bricks[i]->getStrength() == 1)
{
ball->reboundBrick(*bricks[i]);
bricks.erase(std::remove(bricks.begin(), bricks.end(), bricks[i]), bricks.end());
}
else
{
ball->reboundBrick(*bricks[i]);
bricks[i]->setStrength(1);
}
}
}
}
void Game::HandleInput()
{
player->HandleInput();
}
void Game::Draw()
{
player->Draw();
ball->Draw();
for (unsigned int i = 0; i < bricks.size(); i++)
{
bricks[i]->Draw();
}
}
void Game::Update()
{
player->Update();
ball->Update();
brick->Update();
}
void Game::Run()
{
//Game Loop
while (m_window.isOpen())
{
sf::Event event;
while (m_window.pollEvent(event))
{
if (event.type == sf::Event::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
m_window.close();
}
m_window.clear();
Draw();
HandleInput();
HandleCollision();
Update();
m_window.display();
}
}

Can't draw sf::RectangleShape s stored in vector (Tetris clone)

I am trying to storesf::RectangleShape's into thestd::vectorand then draw each of them into thesf::RenderWindow.
Single rectangle shape is representing 1x1 tetromino and i would like to store it into the vector each time it reaches the bottom of the window. Then I would like to reset the position of the current tetromino to the default position.
I think I'm not even to able store it correctly. Each time the tetromino reaches the bottom it gives me this error message:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Bellow please find my current code. I just started working on it and already got stuck.
Definitions.h
#pragma once
// Point structure
struct Point
{
int dim_x;
int dim_y;
};
// Field Dimensions
const int fieldRows = 10;
const int fieldColumns = 9;
const int pointSize = 50.f;
// For checkingEdges funntion within the Tetrnomino.h
enum Edge
{
leftEdge,
rightEdge,
noneEdge
};
Game.h
#pragma once
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include "Definitions.h"
#include "Tetromino.h"
class Game
{
public:
Game();
~Game();
// Game starter
void run();
// Accessors
bool running();
private:
// Updating and rendering the game window
void update();
void render();
// Initialization
void initVariables();
void initWindow();
void initBacgroundMusic();
// Polling
void pollEvents();
// Window logic stuff
sf::RenderWindow* _window;
sf::Event _event;
void drawStack();
// Bacground Music
sf::Music _ost;
// Tetromino + Its logic
Tetromino _T;
sf::Time delayTime = sf::milliseconds(300);
sf::Clock clock;
};
Tetromino.h
#pragma once
#include <SFML/Graphics.hpp>
#include <vector>
#include "Definitions.h"
class Tetromino
{
public:
Tetromino();
~Tetromino();
// Initialization
void initTetromino();
// Tetromonino logic
void moveTetromino();
Edge checkEdges();
// Getters & Setters
sf::RectangleShape getTetromino();
sf::RectangleShape getStackPart(int part);
int getStackSize();
void setTetromino(sf::RectangleShape &t);
private:
// The current tetromino
sf::RectangleShape _tetromino;
std::vector<sf::RectangleShape> _stack;
};
Game.cpp
#include "Game.h"
//-----Consturcotrs and Destructors-----//
Game::Game()
{
//Basic Initialization
_T.initTetromino();
initVariables();
}
Game::~Game()
{
delete _window;
}
//-----Private Functions-----//
void Game::run()
{
update();
render();
}
bool Game::running()
{
return _window->isOpen();
}
void Game::update()
{
sf::Time elapsed = clock.getElapsedTime();
pollEvents();
if (elapsed >= delayTime)
{
_T.moveTetromino();
clock.restart();
}
}
void Game::render()
{
_window->clear(sf::Color::White);
_window->draw(_T.getTetromino());
drawStack();
_window->display();
}
void Game::initVariables()
{
_window = nullptr;
initWindow();
initBacgroundMusic();
}
void Game::initWindow()
{
_window = new sf::RenderWindow(sf::VideoMode(fieldColumns * pointSize, fieldRows * pointSize), "Tetris v0.2", sf::Style::Default);
_window->setVerticalSyncEnabled(true);
_window->setFramerateLimit(60);
}
void Game::initBacgroundMusic()
{
_ost.openFromFile("../QT_SFML_Tetris/Music.ogg");
_ost.play();
_ost.setLoop(true);
_ost.setVolume(50.f);
}
void Game::pollEvents()
{
while (_window->pollEvent(_event))
{
if (_event.type == sf::Event::Closed) {_window->close();}
if (_event.type == sf::Event::KeyPressed)
{
if (_event.key.code == sf::Keyboard::Escape){_window->close();}
if (_event.key.code == sf::Keyboard::Left && _T.checkEdges() != leftEdge)
{
sf::RectangleShape t = _T.getTetromino();
t.setPosition(t.getPosition().x - pointSize, t.getPosition().y);
_T.setTetromino(t);
render();
}
if (_event.key.code == sf::Keyboard::Right && _T.checkEdges() != rightEdge)
{
sf::RectangleShape t = _T.getTetromino();
t.setPosition(t.getPosition().x + pointSize, t.getPosition().y);
_T.setTetromino(t);
render();
}
if (_event.key.code == sf::Keyboard::Down)
{
sf::RectangleShape t = _T.getTetromino();
t.setPosition(t.getPosition().x, t.getPosition().y+ pointSize);
_T.setTetromino(t);
render();
}
}
}
}
**void Game::drawStack()**
{
for (unsigned int i = _T.getStackSize(); i > 0; --i)
{
_window->draw(_T.getStackPart(i));
}
}
main.cpp
#include <Game.h>
int main()
{
Game game;
while (game.running())
{
game.run();
}
return 0;
}
Tetromino.cpp
#include "Tetromino.h"
//-----Consturcotrs and Destructors-----//
Tetromino::Tetromino()
{
}
Tetromino::~Tetromino()
{
}
//-----Public Functions-----//
void Tetromino::initTetromino()
{
_tetromino.setPosition(sf::Vector2f((fieldColumns * pointSize - pointSize) / 2, 0.f));
_tetromino.setSize(sf::Vector2f(pointSize, pointSize));
_tetromino.setFillColor(sf::Color::Red);
}
void Tetromino::moveTetromino()
{
_tetromino.move(0.f, pointSize);
if (_tetromino.getPosition().y > fieldRows * pointSize - pointSize)
{
_stack.push_back(_tetromino);
_tetromino.setPosition(sf::Vector2f((fieldColumns * pointSize - pointSize) / 2, 0.f));
}
}
Edge Tetromino::checkEdges()
{
if (_tetromino.getPosition().x == 0)
{
return leftEdge;
}
else if (_tetromino.getPosition().x == (fieldColumns * pointSize) - pointSize)
{
return rightEdge;
}
else return noneEdge;
}
sf::RectangleShape Tetromino::getTetromino()
{
return _tetromino;
}
sf::RectangleShape Tetromino::getStackPart(int part)
{
return _stack[part];
}
int Tetromino::getStackSize()
{
return _stack.size();
}
void Tetromino::setTetromino(sf::RectangleShape &t)
{
_tetromino = t;
}
I think the main issue could be within this line:
_stack.push_back(_tetromino);
In the drawStack() method you try to iterate backwards.
There is a reverse iterator doing this for you.
you have an off-by one error in your index calculation, which works only with an empty vector (exactly to prevent these errors you should use the iterator!)
You may want to read about iterators in C++ here is a small example.
According to your code it will look like (note that you need also a getStack()-method in Tetromino.hpp, returning the reference of the vector):
void Game::drawStack()
{
for (auto it = _T.getStack().rbegin(); it != _T.getStack().rend(); it++)
{
_window->draw(*it);
}
}
If you want to keep the index, I this is a fix:
void Game::drawStack()
{
for (int i = _T.getStackSize()-1; i >= 0; --i)
{
_window->draw(_T.getStackPart(i));
}
}

How to draw a custom shaped element?

I'm currently working in an app which is essentially a pong game. The game features two paddles currently in rectangular format to ease collision detection against the ball(currently square).
I'm using a "QRect" element as paddle since it provides the ".intersect" method, making it easy to check for collisions.
My implementation for a rectangular paddle is as follows:
Paddle::Paddle(int initial_x, int initial_y) {
QImage image.load(":images/paddle.png");
QRect rect = image.rect();
resetState(initial_x, initial_y);
}
I'm trying to draw an arch like paddle and hitbox, similar to what the code below provides:
QRectF rectangle(10.0, 20.0, 80.0, 60.0);
int startAngle = 30 * 16;
int spanAngle = 120 * 16;
QPainter painter(this);
painter.drawChord(rectangle, startAngle, spanAngle);
The only problem with the code above is it only works inside a paintEvent function and that won't work for me.
paddle.h
#ifndef PADDLE_H
#pragma once
#include <QImage>
#include <QRect>
class Paddle {
public:
Paddle(int, int);
~Paddle();
public:
void resetState(int, int);
void move();
void setDx(int);
void setDy(int);
QRect getRect();
QImage & getImage();
private:
QImage image;
QRect rect;
int dx;
int dy;
static const int INITIAL_X1 = 70;
static const int INITIAL_Y1 = 350;
};
#define PADDLE_H
#endif // PADDLE_H
paddle.cpp
#include <iostream>
#include "paddle.h"
Paddle::Paddle(int initial_x, int initial_y) {
dy = 0;
image.load(":images/paddle.png");
rect = image.rect();
resetState(initial_x, initial_y);
}
Paddle::~Paddle() {
std::cout << ("Paddle deleted") << std::endl;
}
void Paddle::setDy(int y) {
dy = y;
}
void Paddle::move() {
int x = rect.x();
int y = rect.top() + dy;
rect.moveTo(x, y);
}
void Paddle::resetState(int initial_x, int initial_y) {
rect.moveTo(initial_x, initial_y);
}
QRect Paddle::getRect() {
return rect;
}
QImage & Paddle::getImage() {
return image;
}
mainGame.h
#ifndef BREAKOUT_H
#pragma once
#include <QWidget>
#include <QKeyEvent>
#include <QFrame>
#include "ball.h"
#include "brick.h"
#include "paddle.h"
class Breakout : public QFrame {
Q_OBJECT
public:
Breakout(QWidget *parent = 0);
~Breakout();
signals:
void leftScoreChanged(int leftScore);
void rightScoreChanged(int rightScore);
void ballLost(int ballsLeft);
protected:
void paintEvent(QPaintEvent *);
void timerEvent(QTimerEvent *);
void keyPressEvent(QKeyEvent *);
void keyReleaseEvent(QKeyEvent *);
void drawObjects(QPainter *);
void finishGame(QPainter *, QString);
void moveObjects();
void startGame();
void pauseGame();
void stopGame();
void victory();
void validateScoreChange(int);
void checkCollision();
private:
int x;
int timerId;
int ballsLeft;
int leftScore;
int rightScore;
static const int N_OF_BRICKS = 30;
static const int DELAY = 5;
static const int TOP_EDGE = 0;
static const int LEFT_EDGE = 0;
static const int BOTTOM_EDGE = 700;
static const int RIGHT_EDGE = 1200;
Ball *ball;
Paddle *leftPaddle;
Paddle *rightPaddle;
Brick *bricks[N_OF_BRICKS];
bool gameOver;
bool gameWon;
bool gameStarted;
bool paused;
};
#define BREAKOUT_H
#endif // BREAKOUT_H
Breakout::paintEvent()
void Breakout::paintEvent(QPaintEvent *e) {
Q_UNUSED(e);
QPainter painter(this);
if (gameOver) {
finishGame(&painter, "Game lost");
} else if(gameWon) {
finishGame(&painter, "Victory");
}
else {
drawObjects(&painter);
}
QWidget::paintEvent(e);
}
From what I understand you do not want to load the QImage from a .png file but you want to draw it, if so you can use QPainter to create the image as I show below:
Paddle::Paddle(int initial_x, int initial_y) {
// draw image
QRectF rectangle(10.0, 20.0, 80.0, 60.0);
int startAngle = 30 * 16;
int spanAngle = 120 * 16;
image = QImage(QSize(100, 100), QImage::Format_ARGB32);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.drawChord(rectangle, startAngle, spanAngle);
painter.end();
dy = 0;
rect = image.rect();
resetState(initial_x, initial_y);
}

How to add collision in SFML

I am working on creating pong but I have been having trouble with Collision.How can I add a pixel accurate Collision? I've created a collision when only using a main file but I can't figure it out when using header files.Can someone write out the code for Collision and add to a Collision.h and Collision.cpp for easy storage and modification.
main.cpp
#include "stdafx.h"
#include <SFML\Graphics.hpp>
#include "Paddle.h"
#include "Ball.h"
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode::getDesktopMode(), "Pong",
sf::Style::Close| sf::Style::Resize| sf::Style::Titlebar);
Paddle paddle1;
Paddle paddle2;
Ball ball;
while (window.isOpen()) {
sf::Event evnt;
while (window.pollEvent(evnt))
{
switch (evnt.type)
{
case sf::Event::Closed:
window.close();
break;
}
}
paddle1.Update();
paddle2.Update();
ball.Update(ballDirectionX,ballDirectionY);
window.clear();
paddle1.Draw(window);
paddle2.Draw(window);
ball.Draw(window);
window.display();
}
return 0;
}
Paddle.h
#pragma once
#include <SFML\Graphics.hpp>
class Paddle
{
public:
Paddle();
~Paddle();
void Draw(sf::RenderWindow& window);
void Update();
sf::RectangleShape paddle1;
sf::RectangleShape paddle2;
private:
};
Paddle.cpp
#include "stdafx.h"
#include "Paddle.h"
Paddle::Paddle()
{
paddle1.setSize(sf::Vector2f(20.0f, 120.0f));
paddle1.setFillColor(sf::Color::Red);
paddle2.setSize(sf::Vector2f(20.0f, 120.0f));
paddle2.setFillColor(sf::Color::Green);
paddle2.setPosition(sf::Vector2f(1900.0f, 0.0f));
}
Paddle::~Paddle()
{
}
void Paddle::Draw(sf::RenderWindow& window)
{
window.draw(paddle1);
window.draw(paddle2);
}
void Paddle::Update()
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
paddle1.move(sf::Vector2f(0, -3));
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
paddle1.move(sf::Vector2f(0, 3));
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
paddle2.move(sf::Vector2f(0, -3));
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
paddle2.move(sf::Vector2f(0, 3));
}
}
Ball.h
#pragma once
#include <SFML\Graphics.hpp>
class Ball
{
public:
Ball();
~Ball();
void Draw(sf::RenderWindow& window);
void Update() {
}
sf::CircleShape ball;
private:
};
Ball.cpp
#include "stdafx.h"
#include "Ball.h"
Ball::Ball()
{
ball.setRadius(20);
ball.setPosition(sf::Vector2f(400, 540));
}
Ball::~Ball()
{
}
void Ball::Draw(sf::RenderWindow & window)
{
window.draw(ball);
}
void Ball::Update()
{
}
Since Pong is a very simple game, I suggest you to create an intersect function with a sf::CircleShape and a sf::RectangleShape as arguments, because that's how you are representing your ball and paddles respectively.
I suggest you the following implementation, but there are better ones:
bool intersects(const sf::CircleShape &c, const sf::RectangleShape &r){
sf::FloatRect fr = r.getGlobalBounds();
sf::Vector2f topLeft(fr.left, fr.top);
sf::Vector2f topRight(fr.left + fr.width, fr.top);
sf::Vector2f botLeft(fr.left, fr.top + fr.height);
sf::Vector2f botRight(fr.left + fr.width, fr.top + fr.height);
return contains(c, topLeft) ||
contains(c, topRight) ||
contains(c, botLeft) ||
contains(c, botRight);
}
This is easy, simply check if each corner of the rectangle is inside of the circle, if none of them is contained, that circle and that rectangle don't intersect.
If any of the corners are contained into the circle, they intersects.
The contains() function quite simple in fact:
bool contains(const sf::CircleShape &c, const sf::Vector2f &p){
sf::Vector2f center = c.getPosition();
float a = (p.x - center.x);
float b = (p.y - center.y);
a *= a;
b *= b;
float r = c.getRadius() * c.getRadius();
return (( a + b ) < r);
}
Is based in this question, but I've separated it in each step for better comprehension.
EDIT
Note that this method only works if rectangles are in a vertical/horizontal orientation, this is, no rotations.