i am new to SFML and was wandering why my player will only move at a certain distance witch is a very small distance.
Here is my code:
game.cpp:
#include <SFML/Graphics.hpp>
int main() {
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML Game!");
while(window.isOpen()) {
sf::Event event;
while(window.pollEvent(event)) {
if(event.type == sf::Event::Closed)
window.close();
}
sf::Font font;
if(!font.loadFromFile("../resources/Lets Coffee.ttf"))
return EXIT_FAILURE;
sf::Text text("Use the WASD keys to move the player around", font, 20);
text.setPosition(5, 5);
// make a player sprite
sf::Texture *playerTexture;
playerTexture = new sf::Texture();
if(!playerTexture->loadFromFile("../resources/Bluey.png"))
return EXIT_FAILURE;
sf::RectangleShape player(sf::Vector2f(128, 128));
player.setPosition(400, 300);
player.setTexture(playerTexture);
player.setOutlineColor(sf::Color::Black);
player.setOutlineThickness(10);
// Here is my distance problem:
if(sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
player.move(0, -5);
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
player.move(0, 5);
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
player.move(-5, 0);
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
player.move(5, 0);
}
window.clear();
window.draw(text);
window.draw(player);
window.display();
}
return 0;
}
Could any of you help?, and am i doing something wrong?, if i am the please tell me!
Credit : Gerard0097
The issue is that your are creating the player object within your main loop, so each cycle you create a new object and that's why is seems like it's moving a short distance but it's just different objects moving once and then being destroyed
Credit : Me
Just create player and texture before main loop (game loop) :
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML Game!");
sf::Font font;
if(!font.loadFromFile("../resources/Lets Coffee.ttf"))
return EXIT_FAILURE;
sf::Text text("Use the WASD keys to move the player around", font, 20);
text.setPosition(5, 5);
sf::Texture *playerTexture;
playerTexture = new sf::Texture();
if(!playerTexture->loadFromFile("../resources/Bluey.png"))
return EXIT_FAILURE;
sf::RectangleShape player(sf::Vector2f(128, 128));
player.setPosition(400, 300);
player.setTexture(playerTexture);
player.setOutlineColor(sf::Color::Black);
player.setOutlineThickness(10);
and then your game loop :
while (game.isOpen) {
// Your Game Logic, Event Handling and drawings
}
Related
I have a problem using sfml where it seems sf::Transforms get applied relative to the origin of whole coordinate system and not the origin of the sprite/thing being transformed.
For example in the two following example I expect the same behavior and it's not what happens.
(differences in bold, most of rest just serves to actually display a sfml window with a circle that gets scaled down when space is pressed)
First Example : here the circle is scaled down towards the top left corner of the window
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 800), "Example");
sf::CircleShape shape(100.f);
shape.setFillColor(sf::Color::Green);
shape.setPosition(400, 400);
sf::Transform t;
t.scale( 9/10.f , 9/10.f);
sf::Transform t_n;
while (window.isOpen())
{
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::Space) {
t_n = t_n * t;
}
}
}
window.clear();
window.draw(shape, t_n);
window.display();
}
return 0;
}
Second Example : Here the circle is scaled down towards the top left corner of its bounding box : this is the kind of behavior I want to achieve but using Transforms
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 800), "Example");
sf::CircleShape shape(100.f);
shape.setFillColor(sf::Color::Green);
shape.setPosition(400, 400);
// no Transforms need declaring
while (window.isOpen())
{
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::Space) {
shape.scale(9/10.f, 9/10.f);
}
}
}
window.clear();
window.draw(shape);
window.display();
}
return 0;
}
note: this is a possible duplicate of Transformations igrnores sf::Sprite's origin , but the only answer to this thread is my own, and the solution I suggest is really not ideal.
In this code I have one view (white, zoom 2) and the original window, also one sprite for a car and one sprite for a wall...
#include <SFML/Graphics.hpp>
#include "collision.hpp"
#define windowWidth 1000
#define windowHeight 600
int main()
{
sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), "SFML Views");
sf::View view(sf::FloatRect(0,0, windowWidth, windowHeight));
view.zoom(2);
// car
sf::Texture imgCar;
Collision::CreateTextureAndBitmask(imgCar, "carro.png" );
sf::Sprite car;
car.setTexture(imgCar);
car.setPosition(0, (windowHeight - imgCar.getSize().y) / 2);
// wall
sf::Texture imgWall;
Collision::CreateTextureAndBitmask( imgWall, "barreira.png" );
sf::Sprite wall;
wall.setTexture(imgWall);
wall.setPosition(windowWidth - imgWall.getSize().x, 0);
sf::RectangleShape background (sf::Vector2f(windowWidth, windowHeight));
background.setFillColor(sf::Color::White);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
if (!Collision::PixelPerfectTest(car, wall))
car.move(0.1, 0);
window.clear();
window.setView(view);
window.draw(background);
window.setView(window.getDefaultView());
window.draw(car);
window.draw(wall);
window.display();
}
return 0;
}
... if both car and wall are related with the main window, I get a perfect car collision with the wall. (see image).
Now if I put the car inside the view ...
window.clear();
window.setView(view);
window.draw(background);
window.draw(car);
window.setView(window.getDefaultView());
window.draw(wall);
window.display();
... the collision is detected as if the wall were within the boundaries of the view (which is zoomed in) (see image).
How can I make the collision detection independent of the view?
I am writing a small program using SFML which draws a 5 x 5 rectangle at any point specified by clicking the mouse.
I am using mapPixelToCoords() to map the mouse coordinates to the pixels as recommended in the documentation, however I am still encountering a weird offset between the coordinates and the actual shape which is drawn.
The offset varies on different parts of the window (it is not a constant x,y value).
I would like the rectangle to be drawn precisely under the mouse pointer, how do I go about removing this offset?
This is the code I'm using to draw the rectangle on click:
Screenshot of offset in the window
int main(){
sf::RenderWindow window(sf::VideoMode(800, 720), "SFML window");
sf::Event event;
//Rectangle to be drawn on the screen
sf::RectangleShape someRect;
someRect.setFillColor(sf::Color(0, 0, 0));
someRect.setSize({ 5, 5 });
someRect.setPosition(100, 120);
while (window.isOpen())
{
if (!windowStarted) {
event.type = sf::Event::Closed;
}
while (window.pollEvent(event))
{
// Close window: exit
if (event.type == sf::Event::Closed) {
window.close();
}
if (event.type == sf::Event::MouseButtonPressed) {
someRect.setPosition(window.mapPixelToCoords(sf::Mouse::getPosition(window)));
}
}
window.clear(sf::Color(255, 255, 255));
window.draw(someRect);
window.display();
}
return 0;
}
Just started learning SFML (so please bear with me).
I have made a RenderWindow object, and I have a image I want to fit perfectly to that window.
By searching through the documentation, I found the sf::Sprite::SetScale function. Is this the right function to do it? But how do I set the scale of the sprite to the scale of the RenderWindow, when the RenderWindow object size is set in pixels? Do I have to get the scale of the RenderWindow, and then assign the background sprite to that scale or?
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode(600, 300), "Simple Game");
sf::Texture BackgroundTexture;
sf::Sprite background;
//background.setScale(0.2, 0.2); <--- how?
if(!BackgroundTexture.loadFromFile("media/background.png"))
{
return -1;
}
else
{
background.setTexture(BackgroundTexture);
}
while(window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
window.close();
}
}
window.clear();
window.draw(background);
window.display();
}
}
The scale factor you need is simply the ratio between the window size and the texture size. sf::Texture has a getSize function, as has sf::RenderWindow. Simply get the sizes of both, calculate the ratio and use it to set the scale of the sprite, like this:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode(600, 300), "Simple Game");
sf::Texture BackgroundTexture;
sf::Sprite background;
sf::Vector2u TextureSize; //Added to store texture size.
sf::Vector2u WindowSize; //Added to store window size.
if(!BackgroundTexture.loadFromFile("background.png"))
{
return -1;
}
else
{
TextureSize = BackgroundTexture.getSize(); //Get size of texture.
WindowSize = window.getSize(); //Get size of window.
float ScaleX = (float) WindowSize.x / TextureSize.x;
float ScaleY = (float) WindowSize.y / TextureSize.y; //Calculate scale.
background.setTexture(BackgroundTexture);
background.setScale(ScaleX, ScaleY); //Set scale.
}
while(window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
window.close();
}
}
window.clear();
window.draw(background);
window.display();
}
}
I'm actually facing a issue I can't solve by myself, using SFML I have a single shape, and I'm moving it at each frame, and then I draw it. The problem is, SFML using two buffers, the trail won't be the same on each buffer (frame) and it will give a weird blinking effect.
I need your knowledge, should I find another way of doing it, like an array of shapes that I'll extend. Or is there a way to skip the second buffer? Making this buffer a piece of paper, and my shape the brush.
sf::CircleShape circle;
//Init the circle (radius etc)
sf::Vector2f pos(0, 500);
while(!done)
{
pos.x += 1;
circle.setPosition(pos);
window.draw(circle);
window.display();
}
May you spend a nice day.
you can achieve that by using sf::RenderTexture which acts as the back buffer (single buffer) to make your drawing and then draw it on screen via sf::RenderWindow`
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML art");
window.setVerticalSyncEnabled(true);
sf::RenderTexture target;
if (!target.create(window.getSize().x, window.getSize().y))
return -1;
target.clear(sf::Color::White);
target.display();
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sf::CircleShape circle(5.f, 32u);
circle.setPosition(sf::Vector2f(sf::Mouse::getPosition(window)));
circle.setFillColor(sf::Color::Red);
target.draw(circle, sf::BlendNone);
target.display();
}
window.clear();
window.draw(sf::Sprite(target.getTexture()));
window.display();
}
}
The purpose of double buffering is to avoid showing parts of not fully rendered scene during rendering of a frame. So your problem has nothing to do with double-buffering itself. Basically, you need to generate all the primitives necessary to render a particular frame every time. In your specific case you could achieve this like this:
sf::CircleShape circle;
//Init the circle (radius etc)
sf::Vector2f pos(0, 500);
int frameCount = 0;
while(!done)
{
++frameCount;
for (int i = 0; i < frameCount; ++i) {
circle.setPosition(pos + sf::Vector2f(i, 0));
window.draw(circle);
}
window.display();
}