SFML community forums

Help => Graphics => Topic started by: GunnDawg on December 14, 2014, 10:47:30 pm

Title: Problem with sprite movement.
Post by: GunnDawg on December 14, 2014, 10:47:30 pm
I am new to SFML and am having a problem with my sprites and mouse events. I'm trying to make it so that when I right click somewhere, the sprite moves to that location slowly (not just warps). I have managed to get it partly working with only one problem. If I right click somewhere the sprite will move towards that position only a few pixels meaning I have to click over and over again until it gets there. Think of League of Legends or any RTS game for an example. You click on the map where you want the unit to go, and he goes. In my current code I must keep clicking as my sprite is only moving a few pixels per click, instead of a steady movement. Here is a snippet of what I've got so far, let me know if you need more.

                        case sf::Event::MouseButtonPressed:

                                if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Right))
                                {
                                        sf::Vector2f totalMovement(sf::Mouse::getPosition(window).x - darthVader.getPosition().x, sf::Mouse::getPosition(window).y - darthVader.getPosition().y);

                                        darthVader.move(totalMovement * (1.f / 30.f));
                                }
 
Title: Re: Problem with sprite movement.
Post by: Cpl.Bator on December 14, 2014, 11:46:15 pm
your event was fired one time when you click.
you mix event and move, it's bad way. you must use some flag for your problem :


if (event.type == sf::Event::MouseButtonPressed)
{
    if (event.mouseButton.button == sf::Mouse::Right)
    {
        button_right = true;
    }
}

if (event.type == sf::Event::MouseButtonReleased)
{
    if (event.mouseButton.button == sf::Mouse::Right)
    {
        button_right = false;
    }
}



...
...
after event
...
...

if(button_right==true)
{
        // do move here
}
 

process your event , and after, and only after move your stuff.
Title: Re: Problem with sprite movement.
Post by: Ixrec on December 14, 2014, 11:51:08 pm
Or more simply, he can use real-time input properly by calling sf::Mouse::isButtonPressed() unconditionally every frame, rather than only at the moment when the mouse button is first pressed.

If your goal was to check if the mouse pressed event was for the left or right mouse button, you're supposed to check event.mouseButton.button.  Reread the tutorial about all the event types.

Also, sf::Vector2f has overloaded arithmetic operators, so subtracting the mouse and sprite positions should be one operation, not two.
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 14, 2014, 11:52:43 pm
Hmmm. Not sure I fully understand what you guys are saying. I'll read what you guys said over again and try to make sense of it.
Title: Re: Problem with sprite movement.
Post by: Ixrec on December 15, 2014, 12:08:58 am
Basically, reread the two tutorials about this:

http://www.sfml-dev.org/tutorials/2.1/window-events.php <-- event-based input
http://www.sfml-dev.org/tutorials/2.1/window-inputs.php <-- real-time input

These are two very different ways of handling input that mean completely different things, so using both APIs to process a single input never really makes any sense, but that's what your snippet of code is doing.
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 15, 2014, 12:31:46 am
Alright I am making progress here. I've changed the code up.

while (window.isOpen())
        {
                sf::Event event;

                if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
                {
                        sf::Vector2f totalMovement(sf::Mouse::getPosition(window).x - darthVader.getPosition().x, sf::Mouse::getPosition(window).y - darthVader.getPosition().y);

                        darthVader.move(totalMovement * (1.f / 10.f));
                }

 

The problem now is that it all happens sooo fast. I'm pretty sure it's sliding/animating to the mouse position but at light speed. How would I slow that down?
Title: Re: Problem with sprite movement.
Post by: Cpl.Bator on December 15, 2014, 12:37:37 am
Probably my english is not correct... i'm french.

you mix Event ( probably in your event loop ) and movement.
you need to know , when an event was fired ( your mouse click ) , is fired just ONE time.
that's explain your problem : you click over and over again to reach the correct position.

and you mix real time input : sf::Mouse::isButtonPressed() and event input : pollEvent()
is not correct , listen Ixrec, and reread the tutorial and my first reply.


edit :

too fast ? use deltatime, use search on the forum.

@++
Title: Re: Problem with sprite movement.
Post by: Ixrec on December 15, 2014, 12:41:06 am
@Cpl.Bator: Too late, he already fixed that problem.

@GunnDawg: The 1/10 speed constant is entirely under your control.  Nothing's stopping you from changing it.

Remember, this is code that gets executed every single frame.  Add some cout statements to tell you how long each frame (ie, iteration of the game loop) actually takes, and how much you're moving the sprite each time.  It should be fairly obvious why it's "too fast".

I would worry about frame-independent movement (ie, deltatime) after you have this basic understanding of what your game loop is actually doing.  It is something you should do, but the mistakes you're making right now are even more important.
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 15, 2014, 12:49:39 am
I guess I just don't know how to implement this.
Title: Re: Problem with sprite movement.
Post by: Ixrec on December 15, 2014, 01:14:05 am
Your current speed:
darthVader.move(totalMovement * (1.f / 10.f));

One tenth of your current speed:
darthVader.move(totalMovement * (1.f / 100.f));
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 15, 2014, 01:24:18 am
Yeah I've been messing with that and found that when changing it to (1.f / 100.f)); the sprite will move slower(good), but if I release the mouse button the sprite stops. I have to hold the mouse button down for the sprite to reach its destination(the mouse cursor). Seems like it would be as simple as changing sf::Mouse::isButtonPressed to sf::Mouse::isReleased, but that's not an option.
Title: Re: Problem with sprite movement.
Post by: Ixrec on December 15, 2014, 01:40:52 am
If you wanted the sprite to move regardless of whether the mouse button is pressed or not, why would you only call move() when it is pressed? :/

In that case, you want a variable to remember the last place the user clicked, and every frame move the character toward that position.
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 15, 2014, 01:45:57 am
If you wanted the sprite to move regardless of whether the mouse button is pressed or not, why would you only call move() when it is pressed? :/

In that case, you want a variable to remember the last place the user clicked, and every frame move the character toward that position.

I figured I was doing that already. Do you know of any video or text tutorials that teach doing EXACTLY what I am trying to do so I can follow it and just copy the code. I seem to learn better when seeing the code I'm trying to implement working, so I can then study it. Otherwise I'm just kind of lost and trying random things.
Title: Re: Problem with sprite movement.
Post by: Ixrec on December 15, 2014, 02:14:28 am
The official SFML tutorials are always the safest bet (almost all the others we've ever seen are just wrong).  They have plenty of sample code snippets in them.  You need to read them all anyway to stand any chance of knowing what you're doing.

For complete programs, the examples that come with SFML itself should be fine for the really basic stuff like this.
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 15, 2014, 02:22:40 am
so because  "sf::Mouse::isButtonPressed" isn't what I am after for this example then can you point me in another direction?
Title: Re: Problem with sprite movement.
Post by: Hapax on December 15, 2014, 03:16:16 am
I think I understand the interface you're trying to achieve. Click once and it'll travel to that location regardless of what you are doing with the mouse afterwards unless you click for it to go somewhere else.
If thats right, I imagine the process would be something as follows:
The first part (first two bullet points) is working with events and is in the event loop. As linked earlier, you'll need to understand this: http://www.sfml-dev.org/tutorials/2.1/window-events.php
The last part (last two bullet points) is similar to what you were doing already except you move towards the stored target location instead of the mouse position.

As a final note, to regulate the speed of the sprite, you could multiply the movement by the amount of time passed in that frame. This is known as delta time.
For working with time, look at this tutorial about using sf::Clock: http://www.sfml-dev.org/tutorials/2.1/system-time.php .
For more indepth timing control, have a read of this article: http://gafferongames.com/game-physics/fix-your-timestep/ (it's a bit more advance and I have had to read it several times to fully comprehend it but it's really worth it!)
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 15, 2014, 03:35:34 am
Thanks. I suppose I'll scrap this and start over with a new approach.
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 15, 2014, 08:32:33 am
So I've come up with this solution that seems to do the trick. I'll post my solution/code for you to see. Like I said "it works" though I'm not sure if this is the proper or most efficient way to do something like this. Can it be done easier? Will this bite me in the rear later on? Any input is appreciated.

        while (window.isOpen())
        {
                sf::Event event;

                if (sf::Mouse::isButtonPressed(sf::Mouse::Right) && totalMovementSet == false)
                {
                        totalMovementSet = true;
                        totalMovement.x = sf::Mouse::getPosition(window).x - darthVader.getPosition().x;                       
                        totalMovement.y = sf::Mouse::getPosition(window).y - darthVader.getPosition().y;

                        mousePoint.x = sf::Mouse::getPosition(window).x;
                        mousePoint.y = sf::Mouse::getPosition(window).y;
                }

                if (totalMovementSet == true)
                {
                        darthVader.move(totalMovement * (1.f / 8000.f));
                }

                if (darthVader.getPosition().x > mousePoint.x - 10 && darthVader.getPosition().x < mousePoint.x + 10 && darthVader.getPosition().y > mousePoint.y - 10 &&
                        darthVader.getPosition().y < mousePoint.y + 10)
                {
                        totalMovementSet = false;
                }
 

the sprite now moves to the location that I right click and stops until I click somewhere else.
Title: Re: Problem with sprite movement.
Post by: Ixrec on December 15, 2014, 08:40:30 am
Yes, that's exactly how it should be done.

Now that the structure is correct, the only significant issues I see are smaller things like:

- The
&& totalMovementSet == false
explicitly prevents the player from changing totalMovement until the current "movement" is completed; are you sure you want to do that?

- The vector operations in your code can be significantly simplified in a few places:
            totalMovementSet = true;
            totalMovement = sf::Mouse::getPosition(window) - darthVader.getPosition();
            mousePoint = sf::Mouse::getPosition(window);
and
sf::Vector2f distFromMouse = darthVader.getPosition() - mousePoint;
if (abs(distFromMouse.x) < 10 && abs(distFromMouse.y) < 10) { // I think this is what your if() means

- Technically, in this snippet you're declaring an sf::Event object and then never using it, but I assume you'll want to write at least a line of code to handle the Close event later, so it's not exactly a problem.
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 15, 2014, 08:47:00 am
Correct that is not what I want to happen. I'd like for them to be able to move where and when they want and not be locked out while moving from point A to point B


EDIT: I do use that event further down for like you said, to close. I only provided essential code for this.
Title: Re: Problem with sprite movement.
Post by: Hapax on December 15, 2014, 03:25:23 pm
You could use events instead to respond to mouse clicks if you wanted to only change the target when clicked but if you want the target to follow the mouse when dragging with the right button, your approach looks great (although you technically can use events for that too).

I'm glad you got it to do what you were looking for and didn't just give up. It sounded like you were going to do that when you wrote "I'll scrap this"  :P
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 15, 2014, 10:45:46 pm
You could use events instead to respond to mouse clicks if you wanted to only change the target when clicked but if you want the target to follow the mouse when dragging with the right button, your approach looks great (although you technically can use events for that too).

I'm glad you got it to do what you were looking for and didn't just give up. It sounded like you were going to do that when you wrote "I'll scrap this"  :P

I would rather it not follow the mouse on right click but instead go to where the mouse cursor is at when right clicking, which is does fine at the moment. I am now trying to get it to move to a different mouse location in the middle of its movement if case the player decides before he gets to the destination that he wants to go somewhere else. Take an RTS game for example. Lets say you accidentally start sending your army/units into the enemy base, you would be able to go "wow wait, no", and right click somewhere else. Trying to do that. At the moment once you right click somewhere, you're committed to moving there, not good!
Title: Re: Problem with sprite movement.
Post by: Ixrec on December 15, 2014, 10:57:30 pm
Simply removing the "&& totalMovementSet == false" should accomplish that.
Title: Re: Problem with sprite movement.
Post by: GunnDawg on December 16, 2014, 12:03:24 am
Simply removing the "&& totalMovementSet == false" should accomplish that.

Ah yes, that did the trick. Sorry for the beginner oversights. I still have issues comprehending what some stuff is doing and why. Appreciate the help guys. I've accomplished (with your guys help of course) what this thread was designed for :)