Search code examples
c++trigonometrysfmlangle

How can I make angles not act weird?


I'm new to programming and SFML. I'm trying to make something like a canon. It's gonna fire balls that will be flying in an arc. Sounds like a very simple task to accomplish, yet I cannot seem to figure out how angles work in SFML. For example, with ang_const = 0.13 Rad (7.44 Deg), my balls flies in a beautiful arc. However, when I change the value of ang_const to 0.14 Rad (8.021 Deg), the ball flies in the opposite direction! If I change the angle to 0.19 Rad (10.88 Deg), it flies downwards for whatever reason.

So here's my code:

#include <SFML/Graphics.hpp>
#include <math.h>
int WIDTH = 1024, HEIGHT = 704;

class Ball {
private:
float radius = 16.00;
public:
sf::CircleShape shape;
Ball () {
    shape.setPosition(0 + radius*2, HEIGHT - radius*2);
    shape.setRadius(radius);
    shape.setFillColor(sf::Color::Cyan);
    shape.setOrigin(radius, radius);
}
void update() {
    if (x() - radius > WIDTH) {
        this->shape.setPosition(0 - radius, y());
    }
    if (x() + radius < 0) {
        this->shape.setPosition(WIDTH + radius, y());
    }
    if (y() - radius > HEIGHT) {
        this->shape.setPosition(x(), 0 - radius);
    }
    if (y() + radius < 0) {
        this->shape.setPosition(x(), HEIGHT + radius);
    }
}
float RadToDeg (float radian) {
    double pi = 3.14159;
    return radian * (180 / pi);
}
float x() { return shape.getPosition().x; }
float y() { return shape.getPosition().y; }
float getRadius() { return radius; }
};

int main()
{
// Create the main window
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "del");

// Some variables
float ang_const = 0.13;                   
float velX_const = 3.5, velY_const = 3.5; 
float grav_const = -0.02;                

float ang = ang_const;
float velX = velX_const, velY = velY_const;
float grav = grav_const;

// Text
int size_for_text = 64;
sf::Font f;
f.loadFromFile("Keyboard.ttf");
sf::Text text1;
text1.setFont(f);
text1.setCharacterSize(27);
text1.setFillColor(sf::Color::White);
text1.setPosition(size_for_text, size_for_text);

// Ball
Ball ball;

while (window.isOpen())
{
    // Process events
    sf::Event event;
    while (window.pollEvent(event))
    {
        // Close window: exit
        if (event.type == sf::Event::Closed) {
            window.close();
        }

        // Escape pressed: exit
        if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
            window.close();
        }

        // Restart
        if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space) {
            ang = ang_const;
            velX = velX_const, velY = velY_const;
            grav = grav_const;
            ball.shape.setPosition(0 + ball.getRadius()*2, HEIGHT - ball.getRadius()*2);
        }
    }

    // Ball movement
    ball.update();

    velY += grav;
    ball.shape.move(velX * cos(ball.RadToDeg(ang)),
                    velY * -sin(ball.RadToDeg(ang)));

    // Clear screen
    window.clear(sf::Color(0,0,80,100));

    // Draw ball
    window.draw(ball.shape);

    // Draw text
    text1.setString("ang " + std::to_string(ang));
    window.draw(text1);

    // Update the window
    window.display();
}

return EXIT_SUCCESS;
}

The main lines are these: Variables:

float ang_const = 0.13;                 
float velX_const = 3.5, velY_const = 3.5;
float grav_const = -0.02;               

Ball movement:

velY += grav;
ball.shape.move(velX * cos(ball.RadToDeg(ang)), velY * - 
sin(ball.RadToDeg(ang)));

Radians to Degrees function:

float RadToDeg (float radian) {
double pi = 3.14159;
return radian * (180 / pi);
}

Could someone explain what's wrong with my code and how angles work in SFML? I'd be appreciated for your help guys.


Solution

  • All the trigonometric functions defined in <cmath> expect their parameters to be values representing angles in radians (see e.g. std::cos).

    So, when you write something like

    cos(ball.RadToDeg(ang))
    

    where ang is equal to, say 0.13, RadToDeg will convert it to 7.44, but, even if your intention is to pass an angle in degrees, that value is interpreted by std::cos (and std::sin) as an angle of 7.44 radians (or 66.28°).

    That leads to your unexpected results:

    cosr(7.44) = 0.505 (instead of cosd(7.44°) = 0.993) and
    cosr(8.021) = -0.166 (instead of cosd(8.021°) = 0.992)