I'm using sfml 2.0 to make a game. The background is going to be a starfield. Rather than use an image, I thought it might be neat to randomly generate a starfield each time the game starts up, so the background looks slightly different each time. Problem is, the way I'm currently doing it slows my game down A LOT. Does anyone know what is causing the speed hit? I've looked through the documentation to see what, but I haven't found anything...
Here's my code:
#include <SFML/Graphics.hpp>
#include "sfml helper/initialization_helpers.h"
#include "sfml helper/cursor_functions.h"
#include "sfml helper/global_event_handler.h"
#include "sfml helper/globals.h"
#include <cstdio>
int main(int argc, char* argv[])
{
try {
// some non-related preparations...
PrepareApplication(argv[0]);
float width = 640, height = 480;
sf::RenderWindow window(sf::VideoMode(width, height), "SFML Test", sf::Style::Close);
window.setFramerateLimit(60);
// Textures is a global object that has an internal std::map<string, sf::Texture>
Textures.add("ball.png", "ball");
sf::Sprite sprite;
sprite.setTexture(Textures.get("ball"));
// This is the snippet that generates the starfield
srand(time(NULL));
sf::Image starsImg;
starsImg.create(width, height, sf::Color::Black);
int numStars = rand() % 20 + 490;
for (int i = 0; i < numStars; i++) {
int x = rand() % (int)width;
int y = rand() % (int)height;
sf::Color color(255, 255, 255, rand() % 75 + 25);
starsImg.setPixel(x, y, color);
}
sf::Texture starsTexture;
starsTexture.loadFromImage(starsImg);
sf::Sprite stars;
stars.setTexture(starsTexture);
// main loop
while (window.isOpen()) {
if (Flags.isActive && Flags.inFocus) {
confineCursorToWindow(window);
} else {
freeCursor();
}
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::Escape) {
Flags.isActive = (!Flags.isActive);
}
}
if (event.type == sf::Event::MouseMoved) {
sprite.setPosition(event.mouseMove.x, event.mouseMove.y);
}
// handles default events like sf::Event::WindowClosed
handleDefaultEventsForWindow(event, window);
}
window.clear();
window.draw(stars); // here's where I draw the stars
window.draw(sprite);
window.display();
}
} catch (const char* error) {
printf("%s\n", error);
exit(1);
}
return 0;
}
EDIT
I tried loading an image of a starfield and tried drawing that, the game still runs slow!
Also, by slow, I mean the sprite called "sprite" lags when following the mouse. Is that actually a speed issue?
Related
I have to make Quarto game as a GUI program so firstly I wanted to make buttons in menu, but I don't know why it don't fill color when my mouse is at the button.
Code:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include<bits/stdc++.h>
using namespace std;
using namespace sf;
class button{
public:
bool isClicked=false;
int Yposition;
int Xposition;
bool isMouseOn=false;
};
int main(){
//Defining variables
Vector2i mouseWindowPosition;
//rendering window "window"
RenderWindow window(VideoMode(800,600), "Quarto game - menu", Style::Default);
window.display();
//setting vsync
window.setVerticalSyncEnabled(true);
//loading textures
Texture backgroundTexture;
backgroundTexture.loadFromFile("Resources/background.png");
//making sprites
Sprite backgroundSprite;
backgroundSprite.setTexture(backgroundTexture);
backgroundSprite.setPosition(0,0);
//making buttons and their colors
RectangleShape playButton(Vector2f(200.f,50.f));
playButton.setFillColor(Color(128,128,128));
playButton.setOutlineThickness(5.f);
playButton.setOutlineColor(Color(100,100,100));
button play;
//setting position of buttons
play.Xposition=70;
play.Yposition=200;
//game loop
while(window.isOpen()){
Event event;
playButton.setFillColor(Color(128,128,128));
play.isMouseOn=false;
while(window.pollEvent(event)){
if(event.type==Event::Closed){
window.close();
}
}
//Getting mouse position
mouseWindowPosition=Mouse::getPosition(window);
if(mouseWindowPosition.x<=play.Xposition && mouseWindowPosition.y<=play.Yposition && mouseWindowPosition.x>=play.Xposition+200 && mouseWindowPosition.y>=play.Yposition+50){
play.isMouseOn=true;
}
//Drawing to screen
window.clear();
window.draw(backgroundSprite);
if(play.isClicked==false){
playButton.setPosition(Vector2f(play.Xposition, play.Yposition));
window.draw(playButton);
}
if(play.isMouseOn==true){
playButton.setFillColor(Color(128,128,128));
}
window.display();
}
}
Is there any better way to make buttons in sfml?
The immediate reason why the button doesn't fill is your if the statement has the signs reversed for checking the box. Using this if statement instead should work:
//Getting mouse position
mouseWindowPosition=Mouse::getPosition(window);
if (mouseWindowPosition.x>=play.Xposition && mouseWindowPosition.y>=play.Yposition &&
mouseWindowPosition.x<=play.Xposition+200 && mouseWindowPosition.y<=play.Yposition+50){
//your code here
}
If you are not already aware, the x and y values are arranged like a table where positive y goes down instead of a cartesian coordinate system where positive y is up.
The other problem is the color you are updating your fill with is the same color of the fill, so changing that color will get you your desired fill.
Also, logic wise you should swap the statement
if (play.isMouseOn == true)
{
}
with the statement
if (play.isClicked == false)
{
playButton.setPosition(Vector2f(play.Xposition, play.Yposition));
window.draw(playButton);
window.display();
}
Here is a working code that changes the fill from grey to red when you hover above it:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
using namespace std;
using namespace sf;
class button
{
public:
bool isClicked = false;
int Yposition;
int Xposition;
bool isMouseOn = false;
};
int main()
{
//Defining variables
Vector2i mouseWindowPosition;
//rendering window "window"
RenderWindow window(VideoMode(800, 600), "Quarto game - menu", Style::Default);
window.display();
//setting vsync
window.setVerticalSyncEnabled(true);
//loading textures
Texture backgroundTexture;
backgroundTexture.loadFromFile("Resources/background.png");
//making sprites
Sprite backgroundSprite;
backgroundSprite.setTexture(backgroundTexture);
backgroundSprite.setPosition(0, 0);
//making buttons and their colors
RectangleShape playButton(Vector2f(200.f, 50.f));
playButton.setFillColor(Color(100, 100, 100));
playButton.setOutlineThickness(5.f);
playButton.setOutlineColor(Color(100, 100, 100));
button play;
//setting position of buttons
play.Xposition = 70;
play.Yposition = 200;
//game loop
while (window.isOpen())
{
Event event;
playButton.setFillColor(Color(128, 128, 128));
play.isMouseOn = false;
while (window.pollEvent(event))
{
if (event.type == Event::Closed)
{
window.close();
}
}
//Getting mouse position
mouseWindowPosition = Mouse::getPosition(window);
if (mouseWindowPosition.x >= play.Xposition && mouseWindowPosition.y >= play.Yposition && mouseWindowPosition.x <= play.Xposition + 200 && mouseWindowPosition.y <= play.Yposition + 50)
{
play.isMouseOn = true;
}
//Drawing to screen
window.clear();
window.draw(backgroundSprite);
if (play.isMouseOn == true)
{
playButton.setFillColor(Color(128, 0, 0));
}
if (play.isClicked == false)
{
playButton.setPosition(Vector2f(play.Xposition, play.Yposition));
window.draw(playButton);
window.display();
}
}
}
I'm making a Pacman game using SFML. I have a background image for the maze that I'm using and I was wondering how I would be able to use multiple bounding boxes for the background so that when the yellow Pacman character collides with the walls, it stops him. Also, I was wondering if I could use multiple bounding boxes for the background maze image, if so, how?
My code:
#include <SFML/Graphics.hpp>
#include <iostream>
int main(int argc, char** argv)
{
sf::RenderWindow renderWindow(sf::VideoMode(280, 480), "Pacman" /*, sf::Style::Titlebar | sf::Style::Close*/);
sf::Event event;
sf::Texture texture, texture2;
texture.setSmooth (true);
texture2.setSmooth (true);
texture.loadFromFile("images/pacmanbkgd.png");
sf::Sprite background_sprite(texture);
background_sprite.setScale(sf::Vector2f(1.25, 1.25));
texture2.loadFromFile("images/transparentPacman3Sprites.png");
sf::IntRect rectSourceSprite(0, 0, 18, 16);
sf::Sprite pacmanMC_sprite(texture2, rectSourceSprite); // sf::intrect(int rectleft, int recttop, int rectwidth, int rectheight)
// pacmanMC_sprite.setScale(sf::Vector2f(1, 1));
pacmanMC_sprite.move(sf::Vector2f(200, 345)); // set sprite at inital location point (140, 145)
sf::Clock clock;
//sets the origin of the sprite
sf::Rect<float> size = pacmanMC_sprite.getGlobalBounds();
pacmanMC_sprite.setOrigin(sf::Vector2f(size.width / 2, size.height / 2));
while (renderWindow.isOpen())
{
while (renderWindow.pollEvent(event))
{
if (event.type == sf::Event::EventType::Closed)
renderWindow.close();
}
if (clock.getElapsedTime().asSeconds() > 0.75f) // 0.07, used for making the mouth faster
{
if (rectSourceSprite.left == 34)
rectSourceSprite.left = 0;
else
rectSourceSprite.left += 17; // pushes the sprite towards the left using x axis
pacmanMC_sprite.setTextureRect(rectSourceSprite);
clock.restart();
}
// pacmanMC_sprite movement
// sprite keeps on moving to a different position when a the correct key is pressed for its rotation
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Up))
{
pacmanMC_sprite.move(0.0f, -0.015f);
pacmanMC_sprite.setRotation(-90.f);
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Down))
{
pacmanMC_sprite.move(0.0f, 0.015f);
pacmanMC_sprite.setRotation(90.f);
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Left))
{
pacmanMC_sprite.move(-0.015f, 0.0f);
pacmanMC_sprite.setRotation(-180.f);
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Right))
{
pacmanMC_sprite.move(0.015f, 0.0f);
pacmanMC_sprite.setRotation(0);
}
renderWindow.clear();
renderWindow.draw(background_sprite);
renderWindow.draw(pacmanMC_sprite);
renderWindow.display();
}
return 0;
}
I am currently trying to recreate Chess in SFML. Generating the board normally works as intended but when I am resizing the window I get weird white borders.
Before Resize:
After Resize:
It looks like the view is not aligned with the window properly so I think my problem is not in the board generation but how I am handling resizes. I thought manually updating the window view would help but it only ensured that the squares don't get streched. The border issue remains however so now I am quite clueless as to how I could fix this problem.
Board.h:
#pragma once
#include <SFML/Graphics.hpp>
class Board
{
public:
void createBoard(sf::Vector2u windowSize);
void drawBoard(sf::RenderWindow& window) const;
private:
sf::RenderTexture board;
sf::Color lightColor = sf::Color(159, 144, 176);
sf::Color darkColor = sf::Color(125, 74, 141);
sf::Color backColor = sf::Color(32, 31, 32);
};
Board.cpp:
#include <SFML/Graphics.hpp>
#include "Board.h"
void Board::createBoard(sf::Vector2u windowSize)
{
const float xOffset = static_cast<float>(windowSize.x - windowSize.y) / 2.f;
const float squareSize = static_cast<float>(windowSize.y) / 8.f;
board.create(windowSize.x, windowSize.y);
board.clear(backColor);
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
sf::RectangleShape currSquare({ squareSize, squareSize });
currSquare.setFillColor((i + j) % 2 ? lightColor : darkColor);
currSquare.setPosition(xOffset + static_cast<float>(i) * squareSize, (static_cast<float>(j) * squareSize));
board.draw(currSquare);
}
}
}
void Board::drawBoard(sf::RenderWindow& window) const
{
window.draw(sf::Sprite(board.getTexture()));
}
main.cpp:
#include <SFML/Graphics.hpp>
#include "Board.h"
int main()
{
sf::RenderWindow window(sf::VideoMode(500, 300), "Chess");
sf::Event event;
sf::View view = window.getDefaultView();
Board board;
board.createBoard(window.getSize());
while (window.isOpen()) {
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
else if (event.type == sf::Event::Resized) {
view.setSize({ static_cast<float>(event.size.width), static_cast<float>(event.size.height) });
window.setView(view);
board.createBoard({ event.size.width, event.size.height });
}
}
window.clear(sf::Color::White);
board.drawBoard(window);
window.display();
}
return 0;
}
Does anyone know how I could fix this problem?
The problem is that you don't only need to resize the view, but also recenter it. As right now you are not doing it, the center remains where the smaller board was and the bigger view takes a chunk from the outside in the top left corner.
So just change your code like this:
...
else if (event.type == sf::Event::Resized) {
float w = static_cast<float>(event.size.width);
float h = static_cast<float>(event.size.height);
view.setSize({w , h});
view.setCenter({w/2.f , h/2.f}); // <----- !
window.setView(view);
board.createBoard({ event.size.width, event.size.height });
}
...
I could really use some help. I am trying to make a falling sand simulation and have some basic code down, but I can't figure how to do collision detection. Here is my code so far:
//SFML Include
#include <SFML/Graphics.hpp>
//Include Vectors
#include <vector>
//Main Loop
int main()
{
//Window Init
sf::RenderWindow window(sf::VideoMode(720, 480, 32), "Yip Yip Physics", sf::Style::Default);
//Global Envoirmental Variables
static float gravity = 0.25;
static float frict = 3;
//Particle Structures
struct Particle
{
//Shape
sf::RectangleShape rect;
//Cell Position
sf::Vector2f cell_pos;
//Vel and frict
float slide_vel = 3;
float grv_vel = 0;
//Init Particle (size, color and origin)
void init()
{
rect.setSize(sf::Vector2f(3, 3));
rect.setFillColor(sf::Color::Green);
rect.setOrigin(rect.getSize());
}
};
//Particle Setup
std::vector<Particle> particles;
//Window Loop
while (window.isOpen())
{
//Update
if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left))
{
//Make and Position Particle
Particle part;
part.rect.setPosition(sf::Vector2f(sf::Mouse::getPosition(window)));
//Initalize the Particle and add to vector
part.init();
particles.push_back(part);
}
//Pixel Update
for (auto& p : particles)
{
//Draw in window
window.draw(p.rect);
}
//Display
window.display();
//Event Variable
sf::Event event;
//Window Event System
while (window.pollEvent(event))
{
//Close Window
if (event.type == sf::Event::Closed)
{
window.close();
}
}
//Window Clear
window.clear(sf::Color::Black);
}
//Return 0
return 0;
}
The code works in making the particles, putting them in a vector and drawing them to the screen, but I don't know where to go for collision. I don't know where to look and would really appreciate help on it or direction on where to find it. I have heard a bit about cellular automata but have no idea how to do it or if it's the best option.
I'm trying to create a loop to draw 10 blocks on the screen, but nothing is showing. I got no error, so I think that the vector is not storing the sprites. I'm new to SFML, so I don't really know what I'm doing wrong.
sf::Texture bTexture;
sf::Texture bloqueTexture;
sf::Sprite bloqueSprite;
//create vector of blocks
std::vector<sf::Sprite> bricks(10, sf::Sprite(bloqueTexture));
fondo.setTexture(img_mgr.getImage("fondo.jpg"));
personaje.setTexture(img_mgr.getImage("jumper.png"));
personaje.setPosition(100,POSICION_TERRENO_Y);
bloqueSprite.setTexture(img_mgr.getImage("bloque.png"));
bloqueTexture.loadFromFile("Recursos/imagenes/bloque.png");
//Fill the vector with the texture
for (int i = 0; i < bricks.size(); i++)
{
bricks[i].setTexture(bloqueTexture);
bricks[i].setPosition(100 + (i * 45) , 320);
window.draw(bricks[i]);
}
2nd edit with final answer : if you want to display png files with SFML, save them 8bit.
Edit: I had some bad copy/paste in the second code, I fixed it
As SFML is made for multi media applications (mostly games), you need to refresh and draw to screen many times by second (that's frames). That being said, the basic approach is to have a main loop doing 3 things : handling inputs, updating your game logic and then drawing.
See the classic example from SFML's website :
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
sf::CircleShape shape(100.f);
shape.setFillColor(sf::Color::Green);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
window.draw(shape);
window.display();
}
return 0;
}
Your texture loading and filling the vector have to be done before the main loop, and then between window.clear() and window.display you need to draw everything you want to display (your blocks).
You may end up with something like this :
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
sf::Texture bTexture;
sf::Texture bloqueTexture;
sf::Sprite bloqueSprite;
//create vector of blocks
std::vector<sf::Sprite> bricks(10, sf::Sprite(bloqueTexture));
fondo.setTexture(img_mgr.getImage("fondo.jpg"));
personaje.setTexture(img_mgr.getImage("jumper.png"));
personaje.setPosition(100,POSICION_TERRENO_Y);
bloqueSprite.setTexture(img_mgr.getImage("bloque.png"));
bloqueTexture.loadFromFile("Recursos/imagenes/bloque.png");
for (int i = 0; i < bricks.size(); i++)
{
bricks[i].setTexture(bloqueTexture);
bricks[i].setPosition(100 + (i * 45) , 320);
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
for (int i = 0; i < bricks.size(); i++)
{
window.draw(bricks[i];
}
// Consider doing this :
// for(const auto& brick : bricks)
// window.draw(brick);
window.display();
}
return 0;
}
I think problem is with loading textures, try to check is loadFromFile function returning true.