Moving a sprite and handling events - c++

I'm learning the SFML library at the moment but I'm a little lost on moving the sprite. Here's my main.cpp file:
#include <SFML/Graphics.hpp>
int main()
{
// Create the main window
sf::RenderWindow App(sf::VideoMode(800, 600), "SFML window");
// Load a sprite to display
sf::Texture Image;
if (!Image.LoadFromFile("cb.bmp"))
return EXIT_FAILURE;
sf::Sprite Sprite(Image);
// Define the spead of the sprite
float spriteSpeed = 10.f;
// Start the game loop
while (App.IsOpened())
{
// Process events
sf::Event Event;
while (App.PollEvent(Event))
{
// Close window : exit
if (Event.Type == sf::Event::Closed)
App.Close();
if (sf::Keyboard::IsKeyPressed(sf::Keyboard::Up))
Sprite.Move(spriteSpeed * App.GetFrameTime(), 0);
}
// Clear screen
App.Clear();
// Draw the sprite
App.Draw(Sprite);
// Update the window
App.Display();
}
return EXIT_SUCCESS;
}
But I get really slow, inconsistent movements, why isn't the sprite moving steadily around the screen? Also, seeing as how I plan to use the mouse to control the character how will I use the loop to make the character move towards where the user clicks?

You shouldn't be checking if the key is held down in the event loop.
SFML only posts one event when the key is first pressed down, and then another event when the key is released. In this case, your code is only checking if the key is held when an event occurs (such as moving your mouse, clicking, or anything else).
Moving the IsKeyPressed check out of the event loop, preferably below it, should fix the issue.
Making the sprite move towards your mouse is a more complicated issue, better suited for the Game Development StackExchange.

Related

Detecting if a touch pressed, not if its down?

i will make a beat em up game with sfml c++ on mobilephone. So i need to use the Touch function. The problem I have is, what is the best way to detect when the Touch has been pressed, and only execute the code which should be executed when the key has been pressed once? I need it for an animation when the Player make a kick. Now its always repeating the spritesheet animation loop, i wanna fix that, here is the a piece if my code where i need it:
...
if(animHit == true){
if(plrClock.getElapsedTime().asSeconds() > 0.1)
{
animRec.x ++;
if(animRec.x * 103 >= plrtex.getSize().x)
animRec.x = 0;
plrClock.restart();
}
}
FloatRect touchButtonRect = btnSprite.getGlobalBounds();
// the Touch is pressed the button
if(touchButtonRect.contains(worldPos)){
animHit = true;
}
else
{
if(animRec.x * 412<= plrtex.getSize().x){
animHit = false;
}
}
You haven't shown the minimal amount of code needed to replicate the problem, but i think i know where the problem lies. You most likely are trying to get the touch in the while loop without any events. Events are the things that tell your program to run things at, well, a trigger of sorts. This trigger can be a mouse click, resize of window, keyboard buttons or touch events.
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
using namespace std;
using namespace sf;
int main()
{
// create the window
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
window.setFramerateLimit(60);
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
if(event.type == sf::Event::Closed) window.close();
if (event.type == sf::Event::TouchBegan)
{
//do something
}
if (event.type == sf::Event::TouchEnded)
{
//do something
}
if (event.type == sf::Event::TouchMoved)
{
//do something
}
}
// clear the window with black color
window.clear(sf::Color::Black);
// draw everything here...
// end the current frame
window.display();
}
return 0;
}
With events you can use the triggers really well such as a screen touch. Using touchBegan it will record the single screen touch, even if you hold down the touch it will still be considered single touch.
Hope this helped.

SFML splash logo window transparent

SFML only allows creating a window of a rectangular(boxy) shape and all other actions are done within it. I am making a Monopoly game and I basically want Monopoly Logo to flash on a screen when the user clicks the executable file and it han’t has to be inside any window(just logo with transparent background).After the logo, the rectangular window then appears. Is there any way to do this?
SFML doesn't have any integrated feature to make window background transparent.
In order to achieve this, you should use some OS specific functions. But this won't work either. If you change window attributes to have a transparent window, SFML will render correctly, but you won't see anything because everything, background and foreground, will be transparent.
What's the solution then? The easiest way to do this is by not having any background, making your logo fit perfectly into your window. Then you only need to remove the title bar and borders, with sf::Style::None.
This is how I reach this:
int main()
{
// First, I load the logo and create an sprite
sf::Texture logo;
if (!logo.loadFromFile("monopoly.png")){
exit(1);
}
sf::Sprite sp;
sp.setTexture(logo);
sp.scale(0.2, 0.2); // My logo is quite big in fact (1st google result btw)
int logoWidth = sp.getGlobalBounds().width;
int logoHeight = sp.getGlobalBounds().height;
// With the logo loaded, I know its size, so i create the window accordingly
sf::RenderWindow window(sf::VideoMode(logoWidth, logoHeight), "SFML", sf::Style::None); // <- Important!! Style=None removes title
// To close splash window by timeout, I just suppose you want something like this, don't you?
sf::Clock timer;
sf::Time time = timer.restart();
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
// event loop is always needed
}
// Window closed by time
time += timer.restart();
if (time >= sf::seconds(2.f)){
window.close();
}
window.clear();
window.draw(sp);
window.display();
}
// Then, reuse the window and do things again
window.create(sf::VideoMode(600, 400), "SFML");
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
}
window.clear();
window.draw(sp);
window.display();
}
return 0;
}
Note that you can re-use your window again just by re-creating with create method.
Results:
and then the other window :

Developing SFML framework

I created an exemple in which i have 2 windows opened at the same time and window1 cant handle events while window2 is open. I changed the current window's color to ilustrate that its working(while window1 is open if i move the mouse, window2 gets greener and greener). But even though window1 cant handle events while window 2 is open, i cant still change window1 position. I want to be unable to do that.
#include <SFML/OpenGL.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
using namespace std;
sf::Event event;
int main()
{
sf::RenderWindow window1(sf::VideoMode(600, 600), "Window1");
sf::RenderWindow window2(sf::VideoMode(300, 300), "Window2");
int r=0,g=0;
while (window1.isOpen())
{
if(window2.isOpen()==false)
while (window1.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window1.close();
r=(r+1)%255;
}
else
{
while (window2.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window2.close();
g=(g+1)%255;
}
}
window1.clear(sf::Color(r,0,0));
window1.display();
window2.clear(sf::Color(0,g,0));
window2.display();
}
return 0;
}
How do i do that?
There isn't direct functionality in SFML for this (although I expect it's possible using platform specific code), but there are a couple of work arounds:
Change the window style to sf::Style::None. This is quick and easy, but has the effect of removing the title bar and window border, which you may not want.
Brute force the window position, either by manually setting the position each render, or checking for a position change and reversing it.

SFML Window::getPosition() and setPosition do not agree in coordinates

Going through the SFML tutorial I tried to write a small code example that slides the window to the right over time, it acted in a way that I didn't expect (the window slid all the way to the bottom). Here's a minimal example that has the window moving despite sticking the exact same coordinates that getPosition spits out into setPosition
#include <SFML/Window.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/System/Time.hpp>
int main(){
sf::Window window(sf::VideoMode(800,600), "Aydin's Window");
window.setPosition(sf::Vector2i(10, 10));
sf::Clock clock;
while(window.isOpen()){
sf::Event event;
while(window.pollEvent(event)){
if(event.type == sf::Event::Closed)
window.close();
}
sf::Time elapsed = clock.getElapsedTime();
if(elapsed > sf::milliseconds(100)){
sf::Vector2i pos = window.getPosition();
window.setPosition(pos);
clock.restart();
}
}
return 0;
}
One would expect this code to keep the window where it is, but instead it slides to the right and downwards on my machine. I had a friend run the same code. On his machine it slides to the left and upwards. What is going on?
edit: when I create the window without decorations (sf::Style::None) the windows stays where it is. I'm guessing one of getPosition or setPosition is getting offset by the title bar and the other is not.

SFML - fluid screen update?

i'm starting with sfml 2.1 but i cant find how to make the program to run fluidly
i mean, the program its working but unless i do something, like pressing a button or moving the mouse, the main loop wont run,
here is an example for my main loop code
window.setFramerateLimit(30); // set max fps to 30
while (window.isOpen())
{
// this code ignores the framerate limit and doesnt runs when an event is found
while (window.pollEvent(event))
{
// this code works fine but it wont run unless the user presses a key or moves the mouse
}
}
any ideas?
The main loop does run, you aren't doing anything in it.
From the tutorials for 2.1:
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
// clear the window with black color
window.clear(sf::Color::Black);
// draw everything here...
// window.draw(...);
// end the current frame
window.display();
}