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

Author Topic: Aligning movement with rotation vector  (Read 4108 times)

0 Members and 1 Guest are viewing this topic.

Arthareos

  • Newbie
  • *
  • Posts: 3
    • View Profile
Aligning movement with rotation vector
« 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

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Aligning movement with rotation vector
« Reply #1 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.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Arthareos

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Aligning movement with rotation vector
« Reply #2 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
    - 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
    - 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.
« Last Edit: January 28, 2018, 01:22:52 pm by Arthareos »

Paul

  • Jr. Member
  • **
  • Posts: 78
    • View Profile
Re: Aligning movement with rotation vector
« Reply #3 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  
 



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.
« Last Edit: January 28, 2018, 07:33:11 pm by Paul »

Arthareos

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Aligning movement with rotation vector
« Reply #4 on: January 28, 2018, 07:45:02 pm »
Thank you very much. :)