Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: sprite rotation for following mouse  (Read 12463 times)

0 Members and 1 Guest are viewing this topic.

zalkore

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
sprite rotation for following mouse
« on: January 03, 2013, 03:12:14 pm »
okay this is driving me crazy. I want to rotate a sprite so that it follows the mouse cursor. I know there's quite a few posts on the subject ( I've looked through all that I could find) and my code seems correct so I don't know what to do.

The issue is when I implement the code all inside of main() it runs the way it should. When I put the code inside of a class though, it does this http://youtu.be/03r05NjPoTA

the rotation doesn't follow the cursor all the way around the screen, nor does it track the angle at a consistent rate.

here's the original code that works:
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <math.h>
#include <iostream>


int main()
{
    sf::Texture playerTexture;
    playerTexture.loadFromFile("StickFig.png");

    sf::Sprite playerSprite;
    playerSprite.setTexture(playerTexture);

    playerSprite.setOrigin(50,50);
    playerSprite.setPosition(400,300);
    playerSprite.setRotation(0);

    sf::Vector2i mouse;
    float angle;
    sf::Vector2f playerPosition;
    double a, b;

    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML works!");
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }
        playerPosition = playerSprite.getPosition();
        a = mouse.x - playerPosition.x;
        b = mouse.y - playerPosition.y;

        mouse = sf::Mouse::getPosition(window);
        angle = -atan2( a , b) * 180 / 3.14;
        playerSprite.setRotation(angle);
        window.clear(sf::Color::White);
        window.draw(playerSprite);
        window.display();
    }

    return 0;
}

 

and here's the code using the class that is messing up:

main()
#include <SFML/Graphics.hpp>
#include "player.h"

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML works!");
    while (window.isOpen())
    {
        player playerOne;
        playerOne.initialize();
        playerOne.loadContent();

        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear(sf::Color::White);
        playerOne.draw(window);
        window.display();
    }

    return 0;
}

 

player.cpp

#include "player.h"
#include <iostream>

player::player()
{
    //ctor
}

player::~player()
{
    //dtor
}

void player::initialize()
{
    playerSprite.setOrigin(50,50);
    playerSprite.setPosition(400,300);

}
void player::loadContent()
{
    playerTexture.loadFromFile("player.png");
    playerSprite.setTexture(playerTexture);


}
void player::draw(sf::RenderWindow &window)
{
    this->trackMouse(true, playerSprite, window);
    window.draw(playerSprite);
}
void player::update(sf::RenderWindow &window)
{

}

void player::trackMouse(bool value, sf::Sprite &sprite, sf::RenderWindow &window)
{
    if(value == true)
    {
        window.convertCoords(mouse);

        //gets sprite origin coordinates and mouse coordinates
        this->spritePosition = sprite.getPosition();
        this->mouse = sf::Mouse::getPosition();

        mouseAngle = -atan2( mouse.x - spritePosition.x , mouse.y - spritePosition.y) * 180 / 3.14159; //angle in degrees of rotation for sprite

        playerSprite.setRotation(mouseAngle);
    }
}
 

any help would just be fantasmical
« Last Edit: January 03, 2013, 03:16:24 pm by zalkore »
"I'm crazy, and I'm right"

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11018
    • View Profile
    • development blog
    • Email
Re: sprite rotation for following mouse
« Reply #1 on: January 03, 2013, 03:57:25 pm »
It's a small but important mistake:
this->mouse = sf::Mouse::getPosition();
// turns into
this->mouse = sf::Mouse::getPosition(window);

So instead of getting the absolute coordinates you get the relative ones.

As for your code ;)
  • The usage of this-> isn't needed. For member variables it's common practice to use a prefix, e.g. m_ and thus you'd already see that the variable comes from the class and there won't be any name clashes with arguments.
  • You should probably use a better naming scheme, because currently it would be very hard to differentiate classes from variables. Personally I always capitalize the first letter of the class name, e.g. Player instead of player.
  • Checking a boolean against true is a silly thing, it's not only redundant, but it can also be a source of hard to spot errors (i.e. if(boolean = false))
  • Passing a member variable from a member function to another (i.e. your sprite) doesn't make any sense. Both member functions have access to the sprite already.
  • The constructor's job is to initialize a class, so use it and don't use your own init or initialize function. It will only lead to errors, if you forget to call it by accident...
  • Only use a dtor if you actually need one.
« Last Edit: January 03, 2013, 04:01:25 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

masskiller

  • Sr. Member
  • ****
  • Posts: 284
  • Pointers to Functions rock!
    • MSN Messenger - kyogre_jb@hotmail.com
    • View Profile
    • Email
Re: sprite rotation for following mouse
« Reply #2 on: January 03, 2013, 04:12:19 pm »
Take into account that rotation of sprites doesn't use their center as an origin, but the default origin (0, 0) or any origin you have set before. I assume you want the sprite to go to the mouse current location while rotating. In that case the fastest way without setting a new origin every time is to move the sprite to it's "center" point, rotate it and then move it to the position you want it to be in.

Also note that sprites calculate their position not by their center, but by the top-left point of the quad they represent. As you need to have the texture alive you can perfectly make a locate center function that uses the texture size or the current texture rect in order to locate your sprite in a center-wise location around the origin so it can rotate around itself.

///Something like this:
Sprite.setPosition(texture.getSize().x/2.f, texture.getSize().y/2.f);
Sprite.rotate(whatever);
Sprite.setPosition(previousPosition);

///In case you are not using a sprite sheet.
///else you need to use the current texture rect that complicates things slightly.
 

Also take into account that SFML uses inverted coordinates, so a 90 degrees angle is actually a -90 angle in usual coordinates. I personally prefer to use the default origin and just move things to it, make rotations (the transformation that is usually the most confusing at first) and then move back to the previous position before drawing, rather than shifting the origin as I go, since it may cause some unexpected behavior.

Edit: You should also not try to call functions like initialize() within the loop unless you really need to. It may break what your program does and it tends to become wasted processing. There's no need to load everything every frame just to have it destroyed the next iteration when you are still using it. Put it outside of the loop, just like your window is.
« Last Edit: January 03, 2013, 04:18:37 pm by masskiller »
Programmer, Artist, Composer and Storyline/Script Writer of "Origin of Magic". If all goes well this could turn into a commercial project!

Finally back into the programming world!

zalkore

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: sprite rotation for following mouse
« Reply #3 on: January 03, 2013, 05:10:23 pm »
@eXpl0it3r
gah I didn't realize I was doing things so messy. I adjusted the naming to clarify what were member variables and classes, etc.
the boolean was the lack of sleep seeping in heh. glad you caught it.
I was following codingmadeeasy on youtube and he uses an initialize function. I thought that the constructor was for that purpose but didn't look into it to make sure   :-\

as for the passing of the sprite member, I intend to have an array of different "equipable" sprites for the character that will be rotated. therefor, I need to pass which sprite is tracking the mouse.

@masskiller
ah excellent information on keeping the correct origin for the sprites. I hadn't really thought of that heh.


Most importantly, it's working now. Thank you very much!
"I'm crazy, and I'm right"

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: sprite rotation for following mouse
« Reply #4 on: January 03, 2013, 05:27:49 pm »
Be careful with Youtube tutorials (and internet tutorials in general). Even if their intentions are good, most uploaders who teach anything related to C++ make fundamental mistakes and have a questionable code design.

I have just taken a look at a random video of CodingMadeEasy (#29 - Tilemaps). The first things I see are #define for constants, static arrays for tilemaps and global variables. This doesn't mean that everything he says is bad, perhaps he shows good concepts. But it means that you should not adopt the code style of internet tutorials 1:1.

To learn good C++ practice, you need a book. Also here, there is a lot of literature written by people who have no clue of the programming language.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

zalkore

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: sprite rotation for following mouse
« Reply #5 on: January 04, 2013, 12:57:27 am »
I'm definitely starting to recognize that. I guess take everything with a grain of salt eh? ha

I went ahead and picked up SAMS Teach Yourself C++ in One Hour a Day, 6th Edition. Thanks for the help and quick responses everyone!
"I'm crazy, and I'm right"