SFML community forums

Help => Graphics => Topic started by: Arthareos on January 28, 2018, 12:43:05 am

Title: Aligning movement with rotation vector
Post by: Arthareos on January 28, 2018, 12:43:05 am
So, i'm trying to make a game in which some a character launches an projectile (still haven't thought about it's appearance too much), to catch an object.

I created an arrow that the player uses to align the shot using the w ans s keys and when he presses space (in theory) the projectile goes to the predetermined direction.

The issue is that i couldn't manage to make the projectile to go in the respective direction, it just goes in one direction.

I'm a noob, be kind :) .

main.cpp
#include "main.h"

sf::Vector2i map[150][150];
sf::Vector2i loadCounter = sf::Vector2i(0, 0);
sf::Texture tileTexture, playerTexture;
sf::Sprite tiles, playerArc;

bool fireOK = false, collisionOK = true;
float playerRotation = 153, bulletRotation = 0, bulletSpeed = 1;
int leftID = 1, rightID = 3, topID = 2, bottomID = 4;
sf::Vector2f bulletVelocity, bulletDirection;
sf::VertexArray targetLine(sf::Lines, 2);
sf::Transformable transform;

class Player
{
public:
        sf::RectangleShape rect;
        float bottom, left, right, top;
        int identifier;

        Player(sf::Vector2f position, sf::Vector2f size, sf::Color color)
        {
                rect.setPosition(position);
                rect.setSize(size);
                rect.setFillColor(color);
        }

        void Update()
        {
                bottom = rect.getPosition().y + rect.getSize().y;
                left = rect.getPosition().x;
                right = rect.getPosition().x + rect.getSize().x;
                top = rect.getPosition().y;
        }

        bool Collision(Player p)
        {
                if (p.identifier == topID && p.bottom < top)
                {
                        return true;
                }
                if (p.identifier == leftID && p.right < left)
                {
                        return true;
                }
                if (p.identifier == rightID && p.left < right)
                {
                        return true;
                }
                if (p.identifier == bottomID && p.top < bottom)
                {
                        return true;
                }
                return false;
        }
};

Player left_wall(Player(sf::Vector2f(0, 64), sf::Vector2f(32, 672), sf::Color(255, 87, 34))), right_wall(Player(sf::Vector2f(992, 64), sf::Vector2f(32, 672), sf::Color(255, 87, 34))),
top_wall(Player(sf::Vector2f(32, 32), sf::Vector2f(960, 32), sf::Color(255, 87, 34))), bottom_wall(Player(sf::Vector2f(32, 736), sf::Vector2f(960, 32), sf::Color(255, 87, 34)));

Player bullet(Player(sf::Vector2f(492, 364), sf::Vector2f(8, 8), sf::Color::Yellow));

int main() {

        sf::Event event;
        sf::ContextSettings settings;

        std::ifstream textFile("./src/map/map1.txt");
        playerTexture.loadFromFile("./src/arrow.png");
       
        playerArc.setTexture(playerTexture);
        playerArc.setPosition(sf::Vector2f(496, 368));
        playerArc.setRotation(playerRotation);
        playerArc.setScale(1, 1);

        left_wall.identifier = 1;
        top_wall.identifier = 2;
        right_wall.identifier = 3;
        bottom_wall.identifier = 4;

        if (textFile.is_open())
        {
                std::string tileLocation;
                textFile >> tileLocation;
                tileTexture.loadFromFile(tileLocation);
                tiles.setTexture(tileTexture);
                while (!textFile.eof())
                {
                        std::string str;
                        textFile >> str;
                        char x = str[0], y = str[2];
                        if (!isdigit(x) || !isdigit(y))
                        {
                                map[loadCounter.x][loadCounter.y] = sf::Vector2i(-1, -1);
                        }
                        else
                        {
                                map[loadCounter.x][loadCounter.y] = sf::Vector2i(x - '0', y - '0');
                        }
                        if (textFile.peek() == '\n')
                        {
                                loadCounter.x = 0;
                                loadCounter.y++;
                        }
                        else
                        {
                                loadCounter.x++;
                        }
                }
        }

        //24 tiles height, 32 width
        sf::RenderWindow window(sf::VideoMode(1024, 768), "Ricochet", sf::Style::Titlebar | sf::Style::Close);

        window.setFramerateLimit(60);

        Player bullet(Player(sf::Vector2f(492, 364), sf::Vector2f(8, 8), sf::Color::Yellow));

        while (window.isOpen())
        {
                while (window.pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                        {
                                window.close();
                        }
                        if (event.type == sf::Event::KeyPressed)
                        {
                                if (event.key.code == sf::Keyboard::W)
                                {
                                        playerRotation = playerArc.getRotation();
                                        playerArc.setRotation(playerRotation + 1);
                                }
                                if (event.key.code == sf::Keyboard::S)
                                {
                                        playerRotation = playerArc.getRotation();
                                        playerArc.setRotation(playerRotation - 1);
                                }
                                if (event.key.code == sf::Keyboard::Space)
                                {
                                        bulletRotation = playerRotation - 135;
                                        bullet.rect.setRotation(bulletRotation);
                                        fireOK = true;
                                }
                        }
                }

                if (fireOK == true)
                {
                        bulletDirection = thor::rotatedVector(sf::Vector2f(100, 0), bulletRotation);
                        bulletVelocity = bulletSpeed * thor::unitVector(bulletDirection);
                        bullet.rect.move(-1, 0);
                        if (collisionOK == false)
                        {
                                fireOK = false;
                        }
                }

                if (bullet.Collision(left_wall))
                {
                        std::cout << "Collision1" << std::endl;
                        collisionOK = false;
                }
                else if (bullet.Collision(right_wall))
                {
                        std::cout << "Collision2" << std::endl;
                        collisionOK = false;
                }
                else if (bullet.Collision(top_wall))
                {
                        std::cout << "Collision3" << std::endl;
                        collisionOK = false;
                }
                else if (bullet.Collision(bottom_wall))
                {
                        std::cout << "Collision4" << std::endl;
                        collisionOK = false;
                }

                window.clear();

                //This loop loads every tile in the map
                for (int i = 0; i < loadCounter.x; i++)
                {
                        for (int j = 0; j < loadCounter.y; j++)
                        {
                                if (map[i][j].x != -1 && map[i][j].y != -1)
                                {
                                        tiles.setPosition(i * 32, j * 32);
                                        tiles.setTextureRect(sf::IntRect(map[i][j].x * 32, map[i][j].y * 32, 32, 32));
                                        window.draw(tiles);
                                }
                        }
                }
               
                left_wall.Update();
                right_wall.Update();
                top_wall.Update();
                bottom_wall.Update();

                ///window.draw(bullet);
                window.draw(playerArc);
                window.draw(bullet.rect);
                window.draw(left_wall.rect);
                window.draw(top_wall.rect);
                window.draw(bottom_wall.rect);
                window.draw(right_wall.rect);
                window.display();

        }

        ///End of execution
}
 

main.h
#ifndef MAIN_H
#define MAIN_H

#include <SFML/Graphics.hpp>
#include <Thor/Vectors.hpp>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <string>

#endif
 

PS: i tried the method from this post, but i couldn't get it working :/ https://en.sfml-dev.org/forums/index.php?topic=16801.0
Title: Re: Aligning movement with rotation vector
Post by: eXpl0it3r on January 28, 2018, 11:31:55 am
It's a very common problem. We get such a question pretty much every other week, plus there are tons of answers to that problem out there.
I suggest you try the search engine a bit. ;)

It's just some vector math, usually involving some atan2, to convert from angle to direction vector.
Title: Re: Aligning movement with rotation vector
Post by: Arthareos on January 28, 2018, 01:20:27 pm
It's a very common problem. We get such a question pretty much every other week, plus there are tons of answers to that problem out there.
I suggest you try the search engine a bit. ;)

It's just some vector math, usually involving some atan2, to convert from angle to direction vector.
So, ty for the response and i don't want to sound like an a hole, but I've been searching for a method to do this for 2 days straight and i found "tons", more like 5-7 forum posts on the topic, i watched some youtube videos on the matter (i know it's bad practice and most of the time it doesn't work), and i found only two resources that are kinda useful:

1. https://en.sfml-dev.org/forums/index.php?topic=16801.0 (https://en.sfml-dev.org/forums/index.php?topic=16801.0)
    - says about the "Thor" library and the "PolarVector2" and "RotatedVector" classes;
    - but i couldn't get it working;

2. https://en.sfml-dev.org/forums/index.php?topic=11667.0 (https://en.sfml-dev.org/forums/index.php?topic=11667.0)
    - the kid had the same issue, but i could't find any useful data on how it calculates the movement based on the rotation/direction;

I dunno, maybe i just didn't see the rest of 99% of the posts on the matter, maybe it's because this is my first try at a game entirely in c++, or because my math skills are average at most, but i can't get it working.

Please do correct me if i got wrong any of the information above, any further help would be greatly appreciated.
Title: Re: Aligning movement with rotation vector
Post by: Paul on January 28, 2018, 07:31:19 pm
Use atan2 how eXpl0it3r suggested. I had same problem week ago (It's not C/C++ code, but the meaning is clear):

// Initial angle
initAngle := ArcTan2( mouse.y - gun.y, mouse.x - gun.x );

// Velocity
vel.x := initvel.x * cos( initAngle ); // Initvel is initial velocity
vel.y := initvel.y * sin( initAngle );

// Applying gravity
acc.y := acc.y + gravity * weight * dt;
vel.y := vel.y + acc.y;

// Get position based on speed
pos.x := pos.x + vel.x * dt;
pos.y := pos.y + vel.y * dt;

angle := ArcTan2( vel.x, vel.y ); // angle of projectile
angle := 90 - RadToDeg( Angle ); // bullet sprites are under 90 degrees  
 

https://www.youtube.com/watch?v=xup0lQd2F10&list=PLj70zoTd37yDLq7pWz4lW3m_dhdThL9cC

Of course position and velocity formulas are big question, you can implement it in many ways, also it can depend on the order what is calculated first. There is lot of articles in game dev forums about it.
Title: Re: Aligning movement with rotation vector
Post by: Arthareos on January 28, 2018, 07:45:02 pm
Thank you very much. :)