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

Author Topic: Sprite Movement on Single MouseClick  (Read 11037 times)

0 Members and 1 Guest are viewing this topic.

LucasShadow

  • Jr. Member
  • **
  • Posts: 52
    • View Profile
Sprite Movement on Single MouseClick
« on: January 02, 2012, 12:55:32 am »
Hello.  I was wondering if anyone had any suggestions as how to go about making a sprite move from Point A to Point B on a 2d plane.  I am able to do this, but the sprite simply warps from one point to another...I have looked into making a speed variable (dont want to use framerates because of the "faster on faster computer" thing) somehow.  I have also looked into vectors some, but have not been able to figure out how to set the sprite's position with the vector.

EDIT: Using SFML 1.6

Maybe some code will help too
Code: [Select]
if (App.GetInput().IsMouseButtonDown(sf::Mouse::Left)) {

            OldX = PlayerObj.GetPosition().x;
            OldY = PlayerObj.GetPosition().y;
            NewX = App.GetInput().GetMouseX();
            NewY = App.GetInput().GetMouseY();
            XVector = (OldX - NewX);
            YVector = (OldY - OldY);
        }
        //Vector...
        float OldPosition = ???;
        float NewPosition = ???;
        sf::Vector2f GetDir(sf::Vector2f OldPosition);
        sf::Vector2f RVector = NewPosition - OldPosition;
        float temp =(float) sqrt((RVector.x * RVector.x + RVector.y * RVector.y));
        RVector = RVector / temp;
        RVector = RVector * SPEED;
        //Set position...
        PlayerObj.SetPosition(RVector.x, RVector.y);

LucasShadow

  • Jr. Member
  • **
  • Posts: 52
    • View Profile
Sprite Movement on Single MouseClick
« Reply #1 on: January 04, 2012, 04:56:00 pm »
Bump?

If it helps, I just need to find a way to define OldPosition (where the sprite was) and a way to define NewPosition (where the sprite is going).

Tex Killer

  • Full Member
  • ***
  • Posts: 242
    • View Profile
Sprite Movement on Single MouseClick
« Reply #2 on: January 04, 2012, 07:55:57 pm »
You must use clocks to control the time passed since the click.

Specify some duration for the animation, say one second, and, based on the time passed since the click, you correct the position accordingly.

jmcmorris

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Sprite Movement on Single MouseClick
« Reply #3 on: January 05, 2012, 12:26:37 am »
This is how I do a translations. First you need to do initialization. Specify the destination and duration as well as store the starting position and keep track of the elapsed time since the translation started. Then you can calculate the progress of the translation and calculate the current position. Here is some psuedo code.

Code: [Select]
//initialization of translation
sf::Vector2f destination(100, 100);
Uint32 duration = 5000; //5 seconds
Uint32 elapsed = 0;
sf::Vector2f start = sprite.GetPosition();
sf::Vector2f delta = destination - start

Code: [Select]
//update translation
elapsed += renderWindow.GetFrameTime(); //sf::RenderWindow
float progress = elapsed / float(duration);
sf::Vector2f current = start + delta * min(progress, 1);
sprite.SetPosition(current);


Note that this is an absolute destination. For it to be relative you need to add start to destination in the initialization part.

LucasShadow

  • Jr. Member
  • **
  • Posts: 52
    • View Profile
Sprite Movement on Single MouseClick
« Reply #4 on: January 05, 2012, 01:09:06 am »
Alright, I think I am able to follow what you guys are getting at. I tried to alter my code some, and the result was much better, but with one little hiccup.  No matter what the distance my sprite goes, it always covers it within 2 seconds.  How can I alter my current code so that the sprite covers any distance at a constant speed?

Code:
Code: [Select]
if (App.GetInput().IsMouseButtonDown(sf::Mouse::Left)) {
            NewX = App.GetInput().GetMouseX();
            NewY = App.GetInput().GetMouseY();
            Clock1.Reset();
        }
        //Clock
        float ElapsedTime = Clock1.GetElapsedTime();
        //Initialization of translation
        sf::Vector2f NewPosition(NewX, NewY);
        float duration = 50;
        sf::Vector2f OldPosition = PlayerObj.GetPosition();
        sf::Vector2f Movement = NewPosition - OldPosition;
        //Update translation
        ElapsedTime += App.GetFrameTime();
        float progress = ElapsedTime / (duration);
        sf::Vector2f Current = OldPosition + Movement * progress;
        PlayerObj.SetPosition(Current);
        App.Draw(PlayerObj);

jmcmorris

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Sprite Movement on Single MouseClick
« Reply #5 on: January 05, 2012, 04:33:45 am »
For a constant rate you will want use the frametime and a constant. Multiply the constant by the framerate divided by the constant's unit. Such as if you want your player moving at 40 pixels per second then you need it to be 40 * (framerate / 1000) assuming the framerate is in milliseconds, which it is here. Another thing to consider is that if it moves at a diagonal then it will be moving faster. You will need to do some trigonometry to get the correct movement vector.

LucasShadow

  • Jr. Member
  • **
  • Posts: 52
    • View Profile
Sprite Movement on Single MouseClick
« Reply #6 on: January 05, 2012, 01:49:44 pm »
Where would I implement the constant speed in the code?

And by trigonometry, I assume you mean something like this:
Code: [Select]
 float XDistance = sqrt((NewX - OldX) * (NewX - OldX));//always outputs positive number
        float YDistance = sqrt((NewY - OldY) * (NewY - OldY));
        sf::Vector2f NewPosition(NewX, NewY);
        sf::Vector2f OldPosition = PlayerObj.GetPosition();
        float duration = 50;
        sf::Vector2f Movement = sqrt(XDistance * XDistance + YDistance * YDistance);


However, I get the following error:
Code: [Select]
|146|error: conversion from 'double' to non-scalar type 'sf::Vector2f' requested|

Tex Killer

  • Full Member
  • ***
  • Posts: 242
    • View Profile
Sprite Movement on Single MouseClick
« Reply #7 on: January 05, 2012, 07:23:25 pm »
Your code is very messed up... The error is hapening on the last line, but look at the first two: You are taking the square root of some square number... Result: the same number.

The error is due to you trying to put a number on a vector variable on the last line. A vector is not a number.

By the way, to get what you want, you must forget the distance at all, and stablish some constant speed. Do it as jmcmorris sugested.

LucasShadow

  • Jr. Member
  • **
  • Posts: 52
    • View Profile
Sprite Movement on Single MouseClick
« Reply #8 on: January 05, 2012, 10:17:28 pm »
Quote

...you must forget the distance at all...


Okay...thats a little confusing in my head but okay.

Quote
...and stablish some constant speed. Do it as jmcmorris sugested.


Alright, but how do I implement his coding suggestions? Or better phrased, where do I implement it?

Code: [Select]

40 * FrameRate / 1000

Tex Killer

  • Full Member
  • ***
  • Posts: 242
    • View Profile
Sprite Movement on Single MouseClick
« Reply #9 on: January 06, 2012, 12:38:11 am »
Create some current position vector, and get the angle between the start position and the end position, in radians.

Then you can do this each frame:
Code: [Select]
float speed = 40 * FrameTime / 1000;
current_position.x += cos(angle) * speed;
current_position.y += sin(angle) * speed;

When the current position is bigger than the destination, make it be the destination and the transition is over.

LucasShadow

  • Jr. Member
  • **
  • Posts: 52
    • View Profile
Sprite Movement on Single MouseClick
« Reply #10 on: January 06, 2012, 04:12:27 pm »
How would you calculate the angle between the two vectors without using the distance? Is there some special function I cant find in the documentation.

Tex Killer

  • Full Member
  • ***
  • Posts: 242
    • View Profile
Sprite Movement on Single MouseClick
« Reply #11 on: January 06, 2012, 06:07:18 pm »
Yeah, you must use the distances, but only to get the angle and only one time.
You can use the standard atan function.

LucasShadow

  • Jr. Member
  • **
  • Posts: 52
    • View Profile
Sprite Movement on Single MouseClick
« Reply #12 on: January 06, 2012, 10:38:52 pm »
Alright, I know this is probably frustrating to you continuing to correct me so this is my last reply...I believe I have implemented all of the coding suggestions, but the result is the same.  No matter the distance, the sprite covers it in the same amount of time.

Code: [Select]
       if (App.GetInput().IsMouseButtonDown(sf::Mouse::Left)) {
            NewX = App.GetInput().GetMouseX();
            NewY = App.GetInput().GetMouseY();
            Clock1.Reset();
        }
        //Clock
        float ElapsedTime = Clock1.GetElapsedTime();
        float FrameTime = App.GetFrameTime();
        //Initialization of translation
        sf::Vector2f NewPosition(NewX, NewY);
        float duration = 50;
        sf::Vector2f OldPosition = PlayerObj.GetPosition();
        sf::Vector2f Movement = NewPosition - OldPosition;
        //Update translation
        ElapsedTime += App.GetFrameTime();
        float progress = ElapsedTime / (duration);
        sf::Vector2f Current_Position = OldPosition + Movement * progress;
        float speed = 40 * FrameTime / 1000;
        float angle = atan((sqrt((NewX - OldX) * (NewX - OldX))) / (sqrt((NewY - OldY) * (NewY - OldY))));
        Current_Position.x += cos(angle) * speed;
        Current_Position.y += sin(angle) * speed;
        if(PlayerObj.GetPosition().x == NewX && PlayerObj.GetPosition().y == NewY);
        PlayerObj.SetPosition(Current_Position.x, Current_Position.y);


If I take out the following code from the above code...
Code: [Select]
if(PlayerObj.GetPosition().x == NewX && PlayerObj.GetPosition().y == NewY);
It doesn't seem to have an effect.  In conjunction with this article: http://gamedev.stackexchange.com/questions/20175/sfml-moving-a-sprite-on-mouseclick, I think I have done something wrong since I don't seem to need to control it...

Naufr4g0

  • Full Member
  • ***
  • Posts: 112
    • View Profile
Sprite Movement on Single MouseClick
« Reply #13 on: January 07, 2012, 12:00:11 am »
I think you have to normalize  the "destination - origin" vector, that is the movement direction vector, on mouse click, with a code like this:

Code: [Select]

sf::Vector2f direction = Destination - Origin;
// calculate distance between origin and destination points
float distance = sqrt( (Destination.X - Origin.X) * (Destination.X - Origin.X) + (Destination.Y - Origin.Y) *  (Destination.Y - Origin.Y) );
// vector normalization (you obtain a unit vector = vector of lenght 1)
direction /= distance;


At each loop you could move your player sprite with:

Code: [Select]

Player.Move ( direction * speed );


So you have a movement not-dependent from distance. :)
You have also to manually check when sprite reach the destination point (within a certain error margin)

LucasShadow

  • Jr. Member
  • **
  • Posts: 52
    • View Profile
Sprite Movement on Single MouseClick
« Reply #14 on: January 14, 2012, 04:24:54 am »
I dont expect a reply right now since everything I need to now is probably right in front of me....

I have tried working on this for a few days alone now, and have the below code:
Code: [Select]
if (App.GetInput().IsMouseButtonDown(sf::Mouse::Left)) {
            NewX = App.GetInput().GetMouseX();
            NewY = App.GetInput().GetMouseY();
            Clock1.Reset();
        }
        sf::Vector2f Origin = PlayerObj.GetPosition();
        sf::Vector2f Destination(NewX, NewY);
        sf::Vector2f Direction = Destination - Origin;
        // calculate distance between origin and destination points
        float Distance = sqrt( (Destination.x - Origin.x) * (Destination.x - Origin.x) + (Destination.y - Origin.y) *  (Destination.y - Origin.y) );
        // vector normalization (you obtain a unit vector = vector of lenght 1)
        Direction /= Distance;
        float FrameTime = App.GetFrameTime();
        float Speed = 40 * FrameTime / 1000;
        PlayerObj.Move(Direction * Speed);


Problem is that when I run it, the sprite doesnt move at all. Thanks in advance to anyone willing to help me :)