I'm trying duplicate the RectangleShape rect1 every time I pressed the space button, but instead of doing that, it just seems to delete my rect1 object in the vector Vec as soon as I release the space key. I can't figure out why, anybody help me please?
here is my code:
int main() {
class shape {
public:
RectangleShape rect1;
};
shape getShape;
getShape.rect1.setSize(Vector2f(100, 100));
getShape.rect1.setFillColor(Color(0, 255, 50, 30));
RenderWindow window(sf::VideoMode(800, 600), "SFML Game");
window.setFramerateLimit(60);
window.setKeyRepeatEnabled(false);
bool play = true;
Event event;
while (play == true) {
while (window.pollEvent(event)) {
if (event.type == Event::Closed) {
play = false;
}
}
window.clear();
vector <shape> Vec;
if (Keyboard::isKeyPressed(Keyboard::Space)) {
Vec.push_back(getShape);
}
for (int i = 0; i < Vec.size(); ++i) {
window.draw(Vec[i].rect1);
}
window.display();
}
window.close();
return 0;
}
You need to place the vector outside the loop, otherwise you create a new empty one every time:
int main() {
// If you need to use this class in something other than main,
// you will need to move it outside of main.
class shape {
public:
RectangleShape rect1;
};
// But in this particular case you don't even need a class,
// why not just use RectangleShape?
shape getShape;
getShape.rect1.setSize(Vector2f(100, 100));
getShape.rect1.setFillColor(Color(0, 255, 50, 30));
RenderWindow window(sf::VideoMode(800, 600), "SFML Game");
window.setFramerateLimit(60);
window.setKeyRepeatEnabled(false);
bool play = true;
Event event;
std::vector<shape> Vec; // Put your vector here!
// play is already a bool, so you don't need == true
while (play) {
while (window.pollEvent(event)) {
if (event.type == Event::Closed) {
play = false;
}
}
window.clear();
if (Keyboard::isKeyPressed(Keyboard::Space)) {
Vec.push_back(getShape);
}
for (int i = 0; i < Vec.size(); ++i) {
window.draw(Vec[i].rect1);
}
window.display();
}
window.close();
return 0;
}
Related
I have this error at my project with threads and I dont know how to solve it. I tryed std::thread and sf::Thread. Could someone help please?
Im creating Animation object inside main class and through function runThread() I am trying to launch thread inside the Animation class.
Error log:
Failed to activate the window's context
Failed to activate OpenGL context
My solution
Main class
int main()
{
bool launchThreads = true;
sf::RenderWindow window(sf::VideoMode( 800, 600), "Title" );
Animation* anima = new Animation(window);
sf::Event event;
while(window.isOpen())
{
while (window.pollEvent(event))
{
anima->handleEvent(event);
if (event.type == sf::Event::Closed)
{
delete anima;
anima = nullptr;
window.close();
}
}
window.clear(sf::Color::Black);
here I am trying to launch that thread:
if (launchThreads)
{
anima->runThread();
launchThreads = false;
}
window.display();
}
return 0;
}
Animation.h :
class Animation
{
private:
sf::RenderWindow& window;
sf::RectangleShape* rectPtr;
sf::Vector2f mousePos;
sf::Thread thread;
public:
Animation(sf::RenderWindow& window);
void handleEvent(sf::Event event);
void runThread();
void handleDraw();
~Animation();
};
and Animation.cpp :
Animation::Animation(sf::RenderWindow& window) : thread(&Animation::handleDraw, this), window(window),rectPtr(nullptr), mousePos()
{
//sf::Thread thea(&handleDraw);
//thread = thea;
rectPtr = new sf::RectangleShape;
rectPtr->setSize(sf::Vector2f(100, 100));
rectPtr->setFillColor(sf::Color::Red);
}
void Animation::handleEvent(sf::Event event)
{
switch (event.type)
{
case sf::Event::MouseMoved:
mousePos = window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y));
break;
}
}
void Animation::runThread()
{
thread.launch();
}
void Animation::handleDraw()
{
for (size_t i = 0; i < 10; i++)
{
rectPtr->setPosition(i*110, 10);
if (rectPtr->getGlobalBounds().contains(mousePos))
{
rectPtr->setFillColor(sf::Color::Yellow);
}
else rectPtr->setFillColor(sf::Color::Red);
window.draw(*rectPtr);
}
}
Animation::~Animation()
{
thread.terminate();
delete rectPtr;
rectPtr = nullptr;
}
Solution:
Solved with moving function window.display(); inside handleDraw() and moving context there too by window.setActive(); App shows what it have to. But inside console there are still same errors.. Think I can Ignore them.
I have a question to sfml.
I am relative new to C++ and sfml.
I am trying to create a Space Invaders type of game.
I currently have some problems with collision,
between the enemy's bullets and the rocket,
I'm talking about line 145. This line:
if (collide(rocket, enemy_bullets[i]))
{
window.close();
}
Can you create something like a collision box?,
because I don't want to collide with the whole rocket sprite,
I only want to collide with parts of it, e.g not the transparent parts.
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <chrono>
void print(std::string string)
{
std::cout << string << std::endl;
}
sf::CircleShape create_bullet(sf::Vector2f possition, sf::Int16 offset)
{
sf::CircleShape circel;
circel.setRadius(10);
circel.setPosition(possition.x + offset, possition.y);
return circel;
}
bool collide(sf::Sprite a, sf::CircleShape b)
{
return a.getGlobalBounds().intersects(b.getGlobalBounds());
}
int main()
{
int speed;
speed = 25;
sf::RenderWindow window(sf::VideoMode(1200, 800), "Space Invaders", sf::Style::Titlebar | sf::Style::Close);
sf::Texture rocket_texture;
if (!rocket_texture.loadFromFile("data/rocket.png"))
{
print("Problem with loding file data/rocket.png");
exit(-1);
}
sf::Texture enemy_texture;
if (!enemy_texture.loadFromFile("data/enemy.png"))
{
print("Problem with loding file data/enemy.png");
exit(-1);
}
sf::Sprite rocket;
sf::Sprite enemy;
std::chrono::milliseconds couldown = std::chrono::milliseconds(0);
std::chrono::milliseconds time;
std::chrono::milliseconds enemy_couldown = std::chrono::milliseconds(0);
bool enemy_fire = false;
float bulletspeed = 0.02;
// sf::CircleShape test = create_bullet();
int changex;
rocket.setTexture(rocket_texture);
rocket.setPosition(500, 650);
rocket.scale(0.5, 0.5);
std::vector<sf::Sprite> enemy_list;
std::vector<sf::CircleShape> player_bullets;
std::vector<sf::CircleShape> enemy_bullets;
enemy.setTexture(enemy_texture);
enemy.scale(0.2, 0.2);
for (int i =0; i<8; i++)
{
enemy.setPosition(i * 150, 400);
enemy_list.push_back(enemy);
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
changex = 0;
switch (event.type)
{
// window closed
case sf::Event::Closed:
window.close();
break;
// key pressed
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::A)
{
if (rocket.getPosition().x >= 0 )
{
changex = changex - speed;
}
}
else if (event.key.code == sf::Keyboard::D)
{
if (rocket.getPosition().x <= 1100)
{
changex = changex + speed;
}
}
else if (event.key.code == sf::Keyboard::Space)
{
time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
if (couldown < time - std::chrono::milliseconds(100)){
couldown = time;
player_bullets.push_back(create_bullet(rocket.getPosition(), 47));
}
}
break;
default:
break;
}
rocket.move(changex, 0);
}
window.clear();
window.draw(rocket);
//swindow.draw(test);
for (int i=0; i<player_bullets.size();i++)
{
player_bullets[i].move(0,-bulletspeed);
window.draw(player_bullets[i]);
if (player_bullets[i].getPosition().y < 0)
{
player_bullets.erase(player_bullets.begin()+i);
}
}
for (int i = 0; i < enemy_bullets.size(); i++)
{
enemy_bullets[i].move(0, bulletspeed);
window.draw(enemy_bullets[i]);
if (enemy_bullets[i].getPosition().y > 800)
{
enemy_bullets.erase(enemy_bullets.begin() + i);
}
if (collide(rocket, enemy_bullets[i]))
{
window.close();
}
}
time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
if (enemy_couldown < time - std::chrono::milliseconds(2000))
{
enemy_couldown = time;
enemy_fire = true;
}
// Draw all Enemys
for (int i = 0; i < enemy_list.size(); i++)
{
for (int j = 0; j < player_bullets.size(); j++)
{
if (collide(enemy_list[i], player_bullets[j]))
{
enemy_list.erase(enemy_list.begin() + i);
}
}
if (enemy_fire)
{
enemy_couldown = time;
// ADD: Move enemys
enemy_bullets.push_back(create_bullet(enemy_list[i].getPosition(), 13));
}
window.draw(enemy_list[i]);
}
enemy_fire = false;
window.display();
}
return 0;
}
If you have any idea how to do that,
I would like to hear it.
Thanks, in advance
You can make a class that derives from sf::Sprite that has a sf::FloatRect for a hitbox, you will need to make a function to set the hitbox.
class Sprite : public sf::Sprite {
sf::FloatRect hitbox;
}
You can move the hitbox to the sprites location with:
getTransform().transformRect(hitbox);
I have used this in the past for hitboxes with SFML.
Edit, Here is an full example program:
#include <SFML/Graphics.hpp>
/// custom sprite class with hitbox
class HitboxSprite : public sf::Sprite {
public:
/// sets the hitbox
void setHitbox(const sf::FloatRect& hitbox) {
m_hitbox = hitbox;
}
/// gets the hitbox (use this instead of getGlobalBounds())
sf::FloatRect getGlobalHitbox() const {
return getTransform().transformRect(m_hitbox);
}
private:
sf::FloatRect m_hitbox;
};
int main() {
sf::RenderWindow window(sf::VideoMode(256, 128), "Example");
// create two sprites, player and enemy
HitboxSprite player;
player.setPosition({ 64.f, 64.f });
HitboxSprite enemy;
enemy.setPosition({ 128.f, 64.f });
enemy.setColor(sf::Color::Red);
// create sprite texture and apply to sprites
sf::Texture square_texture;
square_texture.loadFromFile("32x32square.png");
player.setTexture(square_texture);
enemy.setTexture(square_texture);
// set custom hitboxes
// (this one starts (8, 8) pixels from the top left and has a size of (16, 16)
// (this means the hitbox will be 1/2 of the square in the middle)
player.setHitbox({ 8.f, 8.f, 16.f, 16.f });
enemy.setHitbox({ 8.f, 8.f, 16.f, 16.f });
sf::Clock clock;
while (window.isOpen()) {
// process events
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
const float dt = clock.restart().asSeconds();
constexpr float player_speed = 128.f;
// move player with arrow keys
player.move({
player_speed * dt * (sf::Keyboard::isKeyPressed(sf::Keyboard::Right) - sf::Keyboard::isKeyPressed(sf::Keyboard::Left)),
player_speed * dt * (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) - sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
});
// check for collision
const bool colliding = player.getGlobalHitbox().intersects(enemy.getGlobalHitbox());
// set background color based on collision
window.clear(colliding ? sf::Color::Green : sf::Color::Blue);
// draw sprites
window.draw(enemy);
window.draw(player);
// display
window.display();
}
return 0;
}
If you need any part explained let me know.
Here is the translucent png I made with the center part being the hitbox:
My problem is that the function don't do what I want.
This "CreateWindow" function has the main loop. In the main loop I want a fixed background and, every time I press the H button, I want to draw a Card (sprite) on the background.
What's the problem here? My function draw the cards but when I press H the previous card is deleted and the next card is drawn.
This is something about the event I think, because every time an event happens (I move the mouse, I press an other key etc) the previous card is deleted...
I'm using sfml 2.0
Here is my implementation of the Graphic class
#include "Graphic.h"
#include "SFML/Graphics.hpp"
#include <iostream>
#include <string>
#include "Card.h"
#include <string>
#include <sstream>
Graphic::Graphic(int offset)
{
this->offset = offset;
}
Graphic::~Graphic()
{
//dtor
}
int Graphic::CreateWindow(sf::RenderWindow& window, Deck &deck0)
{
sf::Vector2i screenDimensions(800, 600);
//Dimensioni della window
window.create(sf::VideoMode(screenDimensions.x, screenDimensions.y), "BlackJack", sf::Style::Titlebar | sf::Style::Close);
int index = 0;
window.setKeyRepeatEnabled(false);
//settare il background
sf::Texture bTexture;
sf::Sprite bImage;
if(!bTexture.loadFromFile("Background.png"))
std::cout << "Error" << std::endl;
bImage.setTexture(bTexture);
bImage.setScale(1.0, (float)screenDimensions.y / bTexture.getSize().y);
//MAIN LOOP----------------------
while(window.isOpen())
{
sf::Event Event;
while(window.pollEvent(Event))
{
window.clear();
window.draw(bImage); // this is the function which draw the background
if (Event.type == sf::Event::Closed)
{
window.close();
}
if(Event.key.code == sf::Keyboard::H)
{
Card * y = deck0.dealFirst();
drawCard(window,y->graphNumber,y->getSeed(),offset);
offset = offset + 50;
}
window.display();
}
}
}
int Graphic::drawCard(sf::RenderWindow &window, int graphNumber, string seed, int offset)
{
std::ostringstream oss;
oss << graphNumber << seed << ".png";
std::string var = oss.str();
sf::Texture QHTexture;
sf::Sprite QHImage;
if(!QHTexture.loadFromFile(var))
std::cout<< "Error" <<std::endl;
QHImage.setTexture(QHTexture);
QHImage.setScale(0.5, 0.5);
QHImage.setPosition(offset + 100, 400);
window.draw(QHImage); //this is the function which draw the card's sprite
return 0;
}
Alright you shouldn't be drawing inside of your while(window.pollEvent()) loop, you should be drawing something like this:
while(window.isOpen())
{
sf::Event Event;
while(window.pollEvent(Event))
{
if (Event.type == sf::Event::Closed)
{
window.close();
}
if(Event.key.code == sf::Keyboard::H)
{
Card * y = deck0.dealFirst();
drawCard(window,y->graphNumber,y->getSeed(),offset);
offset = offset + 50;
}
}
window.clear();
window.draw(bImage); // this is the function which draw the background
window.display();
}
The way you were drawing your draw call will only happen if there is an SFML event, and will only ever clear if there is an sfml event(Which is ok if you dont want it to constantly render every frame... and aren't planning any kind of animations...).
So when you hit H an sfml event was being triggers that called your draw card function, however since your card is a local variable to the function you wrote, at the end of the function it is cleared out. You need to store your cards somewhere, such as a vector or list of sf::Sprite. So an example would be:
#include "Graphic.h"
#include "SFML/Graphics.hpp"
#include <iostream>
#include <string>
#include "Card.h"
#include <string>
#include <sstream>
Graphic::Graphic(int offset)
{
this->offset = offset;
}
Graphic::~Graphic()
{
//dtor
}
int Graphic::CreateWindow(sf::RenderWindow& window, Deck &deck0)
{
sf::Vector2i screenDimensions(800, 600);
//Dimensioni della window
window.create(sf::VideoMode(screenDimensions.x, screenDimensions.y), "BlackJack", sf::Style::Titlebar | sf::Style::Close);
int index = 0;
window.setKeyRepeatEnabled(false);
//settare il background
sf::Texture bTexture;
sf::Sprite bImage;
if(!bTexture.loadFromFile("Background.png"))
std::cout << "Error" << std::endl;
bImage.setTexture(bTexture);
bImage.setScale(1.0, (float)screenDimensions.y / bTexture.getSize().y);
//MAIN LOOP----------------------
while(window.isOpen())
{
sf::Event Event;
while(window.pollEvent(Event))
{
if (Event.type == sf::Event::Closed)
{
window.close();
}
if(Event.key.code == sf::Keyboard::H)
{
Card * y = deck0.dealFirst();
drawCard(window,y->graphNumber,y->getSeed(),offset);
offset = offset + 50;
}
}
window.clear();
window.draw(bImage); // this is the function which draw the background
for(int i = 0; i < cardList.size(); ++i)
{
window.draw(cardList[i]);
}
window.display();
}
}
int Graphic::drawCard(sf::RenderWindow &window, int graphNumber, string seed, int offset)
{
std::ostringstream oss;
oss << graphNumber << seed << ".png";
std::string var = oss.str();
sf::Texture QHTexture;
sf::Sprite QHImage;
if(!QHTexture.loadFromFile(var))
std::cout<< "Error" <<std::endl;
QHImage.setTexture(QHTexture);
QHImage.setScale(0.5, 0.5);
QHImage.setPosition(offset + 100, 400);
cardList.push_back(QHImage); //this adds the sprite to our list
return 0;
}
I'm doing a game in c++ with SFML. I've written a code for move the player, but when the game start the player, moves but when i leave the button the player return at its original position.Can you help me, please?
The main:
#include <iostream>
#include <SFML/Graphics.hpp>
int main() {
sf::RenderWindow window(sf::VideoMode(1320, 840), "Window");
window.setPosition(sf::Vector2i(150, 50));
window.setSize(sf::Vector2u(1320, 840));
window.getPosition();
window.setVerticalSyncEnabled(true);
window.setFramerateLimit(5);
window.getSize();
while (window.isOpen()) {
window.clear(sf::Color::White);
//texture
sf::Texture texture;
if (!texture.loadFromFile("/users/gaetanodonnarumma/desktop/background1.png", sf::IntRect(0, 0, 1320, 840))) {
return -1;
}
sf::Texture playerTexture;
if (!playerTexture.loadFromFile("/users/gaetanodonnarumma/desktop/quadrato-giallo.jpg", sf::IntRect(0, 0, 70, 70))) {
return -1;
}
//sprite
sf::Sprite backgroud;
backgroud.setTexture(texture);
sf::Sprite player;
double pX = 0;
double pY = 770;
player.setTexture(playerTexture);
player.setPosition(sf::Vector2f(pX, pY));
player.getPosition();
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::D) {
player.move(10.f, 0.f);
}
}
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::D) {
player.setPosition(pX + 10, 770);
}
}
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::A) {
player.move(-5.f, 0.f);
}
}
}
//draw
window.draw(backgroud);
window.draw(player);
window.display();
}
return 0;
}
All your initialization code is running on every frame. This means that on every frame, you are creating (and destroying) a new player, setting its texture, and setting its position to [0, 770].
Move all the initialization to before the main draw loop begins (before while (window.isOpen())).
This is my code :
t_game_elements *initializeEnvironnement(sf::RenderWindow *window)
{
t_game_elements *gameElements;
playerBat playerBatOne(0, 200);
playerBat playerBatTwo(790, 200);
gameElements = (t_game_elements *)malloc(1000);
gameElements->playerOne = playerBatOne;
gameElements->playerTwo = playerBatTwo;
*gameElements->playerOne.getShape();
window->draw(*playerBatOne.getShape()); // this line don't segfault
window->draw(*gameElements->playerOne.getShape()); // this line segfault
return (gameElements);
}
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 500), "Pong", sf::Style::Default);
t_game_elements *elements;
elements = initializeEnvironnement(&window);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Escape)
{
window.close();
}
}
if (event.type == sf::Event::Closed)
window.close();
}
// window.clear();
// window.draw(*elements->playerOne.getShape());
// window.draw(*elements.playerTwo->getShape());
window.display();
}
return 0;
}
class playerBat
{
public:
playerBat(int x, int y);
sf::RectangleShape *getShape();
void setShape(sf::RectangleShape *Shape);
int test = 10;
private:
sf::RectangleShape shapeBat;
};
typedef struct s_game_elements
{
playerBat playerOne;
playerBat playerTwo;
} t_game_elements;
playerBat::playerBat(int x, int y)
{
sf::RectangleShape rectangle(sf::Vector2f(120, 50));
rectangle.setSize(sf::Vector2f(10, 100));
rectangle.setPosition(x, y);
rectangle.setFillColor(sf::Color::Green);
shapeBat = rectangle;
}
void playerBat::setShape(sf::RectangleShape *Shape)
{
shapeBat = *Shape;
}
sf::RectangleShape *playerBat::getShape()
{
return &shapeBat;
}
I allocate 1000 bytes just to be sure I allocate enough memory, I will change it when I will fix the segfautlt first.
I tried to display the variable 'test' of my class and it works fine.
Have an idea why I segfault ?
Thanks