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

Author Topic: Trouble calculating new position based on mouse and player position for vertex  (Read 1747 times)

0 Members and 1 Guest are viewing this topic.

Snizzlenose

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
I'm trying to implement projectiles, which for now is just a line (VertexArray). 
I managed to create a line from the player to the mouse, and now I'm trying with a constant hypotenuse, projectileLength, but I'm having problems getting the correct position for the new x and y. 
it sets the vertex strange position close to the top left corner of the window and moves around a circle like area as I move the mouse. 
Github: https://github.com/Snizzlenose/2D-SFML-shooter-v2
The function and the functioncall: 

main.cpp:
world.player.Shooting( sf::Mouse::getPosition( window ).x, sf::Mouse::getPosition( window ).y );

Player.cpp:
void Player::Shooting( double mouse_x, double mouse_y )
{
        /* Calculate angle with restricted projectile length (hypotenuse) */
        double delta_x = GetPosition( ).x - mouse_x;
        double delta_y = GetPosition( ).y - mouse_y;
        double radians = atan( delta_y / delta_x );
        double new_x = cos( radians ) * _projectileLength;
        double new_y = sin( radians ) * _projectileLength;

        if( _shooting == true )
        {
                projectile[0].position = sf::Vector2f( GetPosition( ).x, GetPosition( ).y );
                projectile[1].position = sf::Vector2f( new_x, new_y );
                std::cout << "Shooting!\n";
        }
        else
        {
                projectile[0].position = sf::Vector2f( 9999, 9999 );
                projectile[1].position = sf::Vector2f( 9999, 9999 );
        }
}

dabbertorres

  • Hero Member
  • *****
  • Posts: 506
    • View Profile
    • website/blog
Personally, you're doing it the hard way.

Try vector math! Makes stuff like this much easier.

For example:
// constants
const sf::Vector2f CENTER = static_cast<sf::Vector2f>(window.getSize() / 2u);
constexpr float LENGTH = 35.f;
constexpr float VELOCITY = 122.f;

// the projectile
sf::VertexArray line(sf::Lines, 2);

// calculate projectile direction based off: mouse press location and center of window
sf::Vector2f mousePos = {static_cast<float>(event.mouseButton.x), static_cast<float>(event.mouseButton.y)};
sf::Vector2f projEndNorm = unitVec(mousePos - CENTER);
line[0].position = CENTER + projEndNorm;        // offset from the center slightly so: line[0].position - CENTER != {0, 0}
line[1].position = projEndNorm * LENGTH + CENTER;

// update
line[0].position += unitVec(line[0].position - CENTER) * VELOCITY * dt.asSeconds();
line[1].position += unitVec(line[1].position - CENTER) * VELOCITY * dt.asSeconds();

// the unitVec function:
sf::Vector2f unitVec(const sf::Vector2f& vec)
{
        if(vec.x != 0 && vec.y != 0)
                return vec / std::sqrt(vec.x * vec.x + vec.y * vec.y);    // vector / length = unit vector of the vector
        else
                return {0, 0};
}
 

Unit Vector Definition

Minimal and Naive Example if you need it
« Last Edit: May 25, 2015, 01:52:57 am by dabbertorres »

Snizzlenose

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Personally, you're doing it the hard way.

Try vector math! Makes stuff like this much easier.

For example:
// constants
const sf::Vector2f CENTER = static_cast<sf::Vector2f>(window.getSize() / 2u);
constexpr float LENGTH = 35.f;
constexpr float VELOCITY = 122.f;

// the projectile
sf::VertexArray line(sf::Lines, 2);

// calculate projectile direction based off: mouse press location and center of window
sf::Vector2f mousePos = {static_cast<float>(event.mouseButton.x), static_cast<float>(event.mouseButton.y)};
sf::Vector2f projEndNorm = vecNormal(mousePos - CENTER);
line[0].position = CENTER + projEndNorm;        // offset from the center slightly so: line[0].position - CENTER != {0, 0}
line[1].position = projEndNorm * LENGTH + CENTER;

// update
line[0].position += vecNormal(line[0].position - CENTER) * VELOCITY * dt.asSeconds();
line[1].position += vecNormal(line[1].position - CENTER) * VELOCITY * dt.asSeconds();

// the vecNormal function:
sf::Vector2f vecNormal(const sf::Vector2f& vec)
{
        if(vec.x != 0 && vec.y != 0)
                return vec / std::sqrt(vec.x * vec.x + vec.y * vec.y);    // vector / length = unit vector of the vector
        else
                return {0, 0};
}
 

Unit Vector Definition

Minimal and Naive Example if you need it

Awesome thanks! I'll try that tomorrow and use your naive guide as a reference to recreate it. 
However I have some questions beforehand, for the things I haven't encountered yet: 
const sf::Vector2f CENTER = static_cast<sf::Vector2f>(window.getSize() / 2u);
What is static_cast used for, it's a type of conversion from what I understand but what difference does it do to using ( sf::Vector2f ), or does that not work? 
is 2u supposed to be something specific or just half the window size? 
constexpr float LENGTH = 35.f; 
From what I understand constexpr is like const used for objects and functions, does it have purpose for a simple data type? 
sf::Vector2f mousePos = {static_cast<float>(event.mouseButton.x), static_cast<float>(event.mouseButton.y)};
This captures the position of the mouse as the mousebutton is pressed and doesn't update right?
As for using CENTER as a whole, what does it do? I assume that's why you don't need to calculate angles from the player. 
I probably should just read up a lot more til I understand, but vectors, are they just positions for dots right, with x, y , z, etc and the normal is the product of two or more vectors, or does vectors always have a magnitude / normal include together with the position?

Hapax

  • Hero Member
  • *****
  • Posts: 3357
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
const sf::Vector2f CENTER = static_cast<sf::Vector2f>(window.getSize() / 2u);
What is static_cast used for, it's a type of conversion from what I understand but what difference does it do to using ( sf::Vector2f ), or does that not work? 
I can't see anything wrong with just using the vector's constructor here:
e.g.
const sf::Vector2f CENTER = sf::Vector2f(window.getSize() / 2u);
or
const sf::Vector2f CENTER{ sf::Vector2f(window.getSize() / 2u) };

is 2u supposed to be something specific or just half the window size? 
It just divides the window size in half. Since the vector that stores the result of window's getSize() function in unsigned ints, the scalar to multiply/divide it by (the single value) must be of the same type (2u is unsigned 2). Try it with just 2 instead and your compiler will probably complain.
For example, if you converted the window size to sf::Vector2f first, you'd divide by a float instead:
const sf::Vector2f CENTER = sf::Vector2f(window.getSize()) / 2.f;

constexpr float LENGTH = 35.f; 
From what I understand constexpr is like const used for objects and functions, does it have purpose for a simple data type?
I don't suppose constexpr is required here. const should probably suffice.

This captures the position of the mouse as the mousebutton is pressed and doesn't update right?
Yes. event.mouseButton should only be used in the event loop when event.type == sf::Event::MousePressed or event.type == sf::Event::MouseReleased. If you required updating positions, you should update the value on mousemove, or use real-time mouse positions.

As for using CENTER as a whole, what does it do?
It stores the position of the centre of the window.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

dabbertorres

  • Hero Member
  • *****
  • Posts: 506
    • View Profile
    • website/blog
Quote
What is static_cast used for, it's a type of conversion from what I understand but what difference does it do to using ( sf::Vector2f ), or does that not work?
static_cast is the preferred way of casting, go read this stackoverflow answer on the differences.

Quote
I can't see anything wrong with just using the vector's constructor here:
I had forgotten about the conversion constructor, hence the explicit cast.

Quote
is 2u supposed to be something specific or just half the window size?
Yes, just half the window size. The 'u' on the end explicitly makes the value an unsigned integer.
I did this because sf::Window::getSize() returns a sf::Vector2u, an unsigned integer vector, not a float vector.

Quote
From what I understand constexpr is like const used for objects and functions, does it have purpose for a simple data type?
Eh, I just like using it when I can, since it's sure to enforce compile-time constants, rather than possible run-time constants.

Quote
This captures the position of the mouse as the mousebutton is pressed and doesn't update right?
Correct, that will only update when a mouse button was pressed or released. I made the assumption that most projectiles don't change direction much after being fired.

Quote
As for using CENTER as a whole, what does it do?
I just used the center of the window as the starting point for the projectiles. You could just replace this with the position of your player or whatnot as needed, it will work the same. Though, if your player ends up changing position, that could pose an issue. So you'd have to store the starting point of the projectile. Or:
line[0].position += -unitVec(line[0].position - line[1].position) * VELOCITY * dt.asSeconds();
line[1].position += unitVec(line[1].position - line[0].position) * VELOCITY * dt.asSeconds();
This way, the projectile will just reuse it's current direction to calculate its movement. Don't forget the negative in front of the first "unitVec", line[0].position - line[1].position will be the opposite direction of the movement, so you have to negate the result to get the opposite of the opposite. Hehe.

Quote
I probably should just read up a lot more til I understand, but vectors, are they just positions for dots right, with x, y , z, etc and the normal is the product of two or more vectors, or does vectors always have a magnitude / normal include together with the position?
Sort of, yes. I like to think of them as: "a displacement from the origin". And oh, wow. My bad. I name the function "vecNormal" when it should have been named "unitVec" or something. (I'll edit that in)
So, the unit vector of a vector, is itself divided by its magnitude.
« Last Edit: May 25, 2015, 01:56:02 am by dabbertorres »