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

Author Topic: Moving sprites to target position.  (Read 9184 times)

0 Members and 2 Guests are viewing this topic.

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Moving sprites to target position.
« on: March 05, 2015, 07:37:11 pm »
Hi there, I hope you can help me with this, because I don't know what's wrong with the code.
There are some strange moves going on and you have to click more than once on it to move to target.
I would like to move sprites around: Focus a sprite by left-click and then hit left mouse button again somewhere on the map to move it to that position. After this is done, the focus should be removed from the sprite. Thx in advance.

#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>

int main()
{
    sf::RenderWindow mMainWindow(sf::VideoMode(600,600), "Map", sf::Style::Close);
    mMainWindow.setFramerateLimit(60);
    mMainWindow.setKeyRepeatEnabled(false);
    sf::Image image;
    image.create(50, 50, sf::Color::Red);
    sf::Texture texture;
    texture.loadFromImage(image);

    std::vector<sf::Sprite> EnemyVector;
        std::vector<sf::Vector2f> EnemyPositions;
        std::vector<sf::Vector2f> EnemyDestinations;

        sf::Sprite* focus = nullptr;
        bool move = false;
       
    while (mMainWindow.isOpen())
    {
        sf::Event event;
        bool creating = false;
        bool leftclicked = false;
        sf::Vector2i mousePos;

        while (mMainWindow.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
                mMainWindow.close();
                break;
            case sf::Event::KeyPressed:
                creating = (event.key.code == sf::Keyboard::A);
                break;
            case sf::Event::MouseButtonPressed:
                if (event.mouseButton.button == sf::Mouse::Left)
                                {
                    leftclicked = true;
                                        mousePos = sf::Vector2i(event.mouseButton.x, event.mouseButton.y);
                                        break;
                                }
            }
        }
        if (creating)
        {
            sf::Sprite sprite;
            mousePos = (mousePos == sf::Vector2i(0, 0) ? sf::Mouse::getPosition(mMainWindow) : mousePos);
            sprite.setTexture(texture);
            sprite.setColor(sf::Color::Red);
            sprite.setOrigin(static_cast<float>(sprite.getTextureRect().width) / 2, static_cast<float>(sprite.getTextureRect().height) / 2);
            sprite.setPosition(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y));
                        focus=nullptr;
            EnemyVector.push_back(sprite);
                        EnemyPositions.push_back(sf::Vector2f(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y)));
                        EnemyDestinations.push_back(sf::Vector2f(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y)));
        }
                if (leftclicked)
                {
                        for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
                        {
                                if (enemy->getGlobalBounds().contains(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y)))
                                {
                                        focus = &(*enemy);
                                       
                                }
                                else
                                {
                                        EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)].x = static_cast<float>(mousePos.x);
                                        EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)].y = static_cast<float>(mousePos.y);
                                        move=!move;    
                                }
                        }
                }
                if(move)
                {
                        for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
                        {
                                if(focus!=nullptr)
                                {
                                        focus->move((EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)].x - focus->getPosition().x)*0.1,(EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)].y - focus->getPosition().y)*0.1);
                               
                                }
                        }
                }
        mMainWindow.clear();
        for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
        {
            mMainWindow.draw(*enemy);
        }
        mMainWindow.display();
    }
    return 0;
}
 

Arcade

  • Full Member
  • ***
  • Posts: 230
    • View Profile
Re: Moving sprites to target position.
« Reply #1 on: March 05, 2015, 08:20:10 pm »
You might need to be more specific about the weird behavior you are seeing. How many enemies are in the EnemyVector, exactly how many clicks are you performing and where, what happens vs what are you expecting to happen in that situation, etc. I glanced through your code and did see a few potential problems.


std::vector<sf::Vector2f> EnemyPositions;
 
What is this for? It doesn't look like it is being used by anything.

           for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
            {
                if (enemy->getGlobalBounds().contains(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y)))
                {
                    focus = &(*enemy);
                   
                }
                else
                {
                    EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)].x = static_cast<float>(mousePos.x);
                    EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)].y = static_cast<float>(mousePos.y);
                    move=!move;
                }
            }
 
This likely won't do what you want if you have more than one enemy. When you click on one it will set the focus of that one, but set the destination and flip the move flag for all of the others. The move flag will just toggle back and forth depending on how many enemies you have.

for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
            {
                if(focus!=nullptr)
                {
                    focus->move((EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)].x - focus->getPosition().x)*0.1,(EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)].y - focus->getPosition().y)*0.1);
               
                }
            }
 
This will move the focused object once for every enemy in your EnemyVector. Is that what you want?

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Moving sprites to target position.
« Reply #2 on: March 05, 2015, 08:38:03 pm »
EnemyPositions is not being used yet. In future it will store the actual coordinates of the corresponding sprites.

The desired behaviour:     You have some sprites on the map, than left-click one of them to focus it. Then left-click again somewhere on the map-->sprite should move there and after movement is finished (better would be to remove the focus while it is still moving to its target position, so I could click another one and let it move as well to another target position), the focus has to be removed from it (every sprite should only be able to move once, after it has been selected).
« Last Edit: March 05, 2015, 08:40:14 pm by Bogdan »

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Moving sprites to target position.
« Reply #3 on: March 06, 2015, 03:47:29 pm »
I've rewritten it and now it works better, but some problems still remain.
1. Sprites can be moved around unlimitedly, instead of only one move+automatic deselect.
2. It is not possible to move a sprite into another one, without selecting the new one.

Any ideas what can be done to solve this?


#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>

int main()
{
    sf::RenderWindow mMainWindow(sf::VideoMode(600,600), "Map", sf::Style::Close);
    mMainWindow.setFramerateLimit(60);
    mMainWindow.setKeyRepeatEnabled(false);
    sf::Image image;
    image.create(50, 50, sf::Color::Red);
    sf::Texture texture;
    texture.loadFromImage(image);

    std::vector<sf::Sprite> EnemyVector;
        std::vector<sf::Vector2f> EnemyDestinations;

        sf::Sprite* focus = nullptr;
        bool move = false;
       
        sf::Clock clock;
        sf::Time time;

    while (mMainWindow.isOpen())
    {
        sf::Event event;
        bool creating = false;
        bool leftclicked = false;
                bool rightclicked = false;
        sf::Vector2i mousePos;

                time = clock.getElapsedTime();
                clock.restart();

        while (mMainWindow.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
                mMainWindow.close();
                break;
            case sf::Event::KeyPressed:
                creating = (event.key.code == sf::Keyboard::A);
                break;
            case sf::Event::MouseButtonPressed:
                if (event.mouseButton.button == sf::Mouse::Left)
                                {
                    leftclicked = true;
                                        mousePos = sf::Vector2i(event.mouseButton.x, event.mouseButton.y);
                                        break;
                                }
                                 if (event.mouseButton.button == sf::Mouse::Right)
                                {
                    rightclicked = true;
                                        mousePos = sf::Vector2i(event.mouseButton.x, event.mouseButton.y);
                                        break;
                                }
            }
        }
        if (creating)
        {
            sf::Sprite sprite;
            mousePos = (mousePos == sf::Vector2i(0, 0) ? sf::Mouse::getPosition(mMainWindow) : mousePos);
            sprite.setTexture(texture);
            sprite.setColor(sf::Color::Red);
            sprite.setOrigin(static_cast<float>(sprite.getTextureRect().width) / 2, static_cast<float>(sprite.getTextureRect().height) / 2);
            sprite.setPosition(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y));
                        focus=nullptr;
            EnemyVector.push_back(sprite);
                        EnemyDestinations.push_back(sf::Vector2f(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y)));
        }
                if (leftclicked)
                {
                        for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
                        {
                                if (enemy->getGlobalBounds().contains(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y)))
                                {
                                        focus = &(*enemy);
                                        EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)]=sf::Vector2f(static_cast<float>(mousePos.x),static_cast<float>(mousePos.y));
                                        move=false;
                                        break;
                                }
                                else
                                {
                                        move=true;
                                        EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)]=sf::Vector2f(static_cast<float>(mousePos.x),static_cast<float>(mousePos.y));
                                }
                        }
                }
                if(rightclicked)
                {
                        focus=nullptr;         
                }
                std::cout << time.asSeconds() << std::endl;
                if(move)
                {
                        for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
                        {
                                if(focus!=nullptr)
                                {
                                       
                                        focus->move(((EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)].x - focus->getPosition().x)*time.asSeconds()*0.1),
                                                         (EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)].y - focus->getPosition().y)*time.asSeconds()*0.1);
                                        clock.restart();
                                }
                        }
                }
        mMainWindow.clear();
        for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
        {
            mMainWindow.draw(*enemy);
        }
        mMainWindow.display();
    }
    return 0;
}
« Last Edit: March 06, 2015, 06:49:42 pm by Bogdan »

Arcade

  • Full Member
  • ***
  • Posts: 230
    • View Profile
Re: Moving sprites to target position.
« Reply #4 on: March 06, 2015, 08:00:53 pm »
Quote
I've rewritten it and now it works better, but some problems still remain.
1. Sprites can be moved around unlimitedly, instead of only one move+automatic deselect.
2. It is not possible to move a sprite into another one, without selecting the new one.

Are you needing help finding why your code is producing these problems, or do you understand why but aren't sure how to reorganize and re-architect things to be better?

1. Sprites can be moved around multiple times because you aren't doing anything to prevent that. Think about what is happening when you click an empty area. You are setting the "move" variable to true and setting every enemy destination to where you clicked. Then after that you check to see if move is true (yes it is) and then check if the "focus" variable is non-null (yes it is), so you move the "focused" enemy. Perhaps one solution is to set "focus" back to null after you perform the move. Also, not directly related to the problem, but I'm still not sure why you are moving the focused object in a loop...

2. This one is pretty clear. When you click an enemy you are changing the "focus" variable. Perhaps one solution is to not change the focus variable if it is already set to something else.

By the way these questions aren't really related to the Graphics module of SFML, or SFML in general. These questions focus more on general C++ concepts and movement logic. You might get be able to get more people to help out on a different forum.

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Moving sprites to target position.
« Reply #5 on: March 06, 2015, 09:22:46 pm »
I thought it was sfml related, because I'm moving sfml objects on the screen+its about sfml data types/commands.

My problems are not knowing how to do it better.

As for the first problem, I've tried to set the focus to zero after movement, but it worked so fast, that the sprite didn't even have the time and moved only one pixel. Is there any command for "do this (focus=nullptr) after that (movement of focussed sprite) is finished"


Second problem: if I set a condition "focus=nullptr" inside "leftclicked", than the sprites don't move at all. But they should move.


                if (leftclicked)
                {
                        for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
                        {
                                if (enemy->getGlobalBounds().contains(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y)))
                                        if(focus=nullptr)
                                        {
                                                focus = &(*enemy);
                                                EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)]=sf::Vector2f(static_cast<float>(mousePos.x),static_cast<float>(mousePos.y));
                                                move=false;
                                                break;
                                        }
                                        else
                                        {
                                                move=true;
                                                EnemyDestinations[std::distance(EnemyVector.rbegin(),enemy)]=sf::Vector2f(static_cast<float>(mousePos.x),static_cast<float>(mousePos.y));
                                        }
                        }
                }


I`m moving the focussed object in a loop, because I can't use std::distance command without it. Is there any better solution?

Arcade

  • Full Member
  • ***
  • Posts: 230
    • View Profile
Re: Moving sprites to target position.
« Reply #6 on: March 07, 2015, 12:25:15 am »
Well you are using SFML to draw to the screen, which you don't seem to have a problem with. The problem is in the movement logic. This is something you would need to solve no matter what library you were using to draw. Anyways, I'll try to help a little further.

Quote
As for the first problem, I've tried to set the focus to zero after movement, but it worked so fast, that the sprite didn't even have the time and moved only one pixel. Is there any command for "do this (focus=nullptr) after that (movement of focussed sprite) is finished"
You are right, with the way you are doing movement, if you set focus to null after calling move then your sprite won't move very far. Now, as you have things right now, only one object can be moving at a time. Meaning if you tried to move a second object, the first one would stop because there can only be one "focus" object. If that is fine, then what you can probably do is right after moving check to see if the object is near its destination, and if so, set focus to null at that time.

If you want an object to be able to continue moving after focusing a different object you'll probably need more major changes. In that case you'll probably need to use a container (such as vector) to store moving objects and loop through that container to move all of them.

Quote
Second problem: if I set a condition "focus=nullptr" inside "leftclicked", than the sprites don't move at all. But they should move.
This is because you are assigning focus instead of doing a comparison. You should use "==" not "=". I'm not sure if this is just a typo or if you don't understand the difference between "==' and "='. If it is the latter you should spend more time studying the language first. It can be very hard to use a library like SFML if you aren't very strong in C++ concepts.
if(focus==nullptr)
 

Quote
I`m moving the focussed object in a loop, because I can't use std::distance command without it. Is there any better solution?
Why wouldn't you be able to use std::distance without a loop? How you have it right now doesn't seem to make sense to me. It technically works, but is very confusing to understand.

Imagine you have 5 enemies. With your loop, the focused object will move towards the first enemy's destination, then the 2nd enemy's destination, etc. The only reason this works is because during the click you are setting all enemy's destination to the same spot. You still have a problem, though, being that the more enemies you have the faster your object will move because it is moving once per enemy.

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Moving sprites to target position.
« Reply #7 on: March 08, 2015, 02:47:35 pm »
Now I can move focussed sprites into another ones and after movement finishes, it deselects automatically.
As my code doesn't allow simultanous movement of more objects, it is not a perfect solution.

If I want being able to finish object moves after focussing another object, what information should such a new vector store? (Coords?, Bool?) Can't imagine it how it could work.

#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>

int main()
{
    sf::RenderWindow mMainWindow(sf::VideoMode(600,600), "Map", sf::Style::Close);
    mMainWindow.setFramerateLimit(60);
    mMainWindow.setKeyRepeatEnabled(false);
    sf::Image image;
    image.create(50, 50, sf::Color::Red);
    sf::Texture texture;
    texture.loadFromImage(image);

    std::vector<sf::Sprite> EnemyVector;
        std::vector<sf::Vector2f> EnemyDestinations;
        sf::Sprite* focus = nullptr;
        bool move = false;

        int focusxvar = 0;
        int focusyvar = 0;

        sf::Clock clock;
        sf::Time time;

    while (mMainWindow.isOpen())
    {
        sf::Event event;
        bool creating = false;
        bool leftclicked = false;
        sf::Vector2i mousePos;

                time = clock.getElapsedTime();
                clock.restart();

        while (mMainWindow.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
                mMainWindow.close();
                break;
            case sf::Event::KeyPressed:
                creating = (event.key.code == sf::Keyboard::A);
                break;
            case sf::Event::MouseButtonPressed:
                if (event.mouseButton.button == sf::Mouse::Left)
                                {
                    leftclicked = true;
                                        mousePos = sf::Vector2i(event.mouseButton.x, event.mouseButton.y);
                                        break;
                                }
            }
        }
        if (creating)
        {
            sf::Sprite sprite;
            mousePos = (mousePos == sf::Vector2i(0, 0) ? sf::Mouse::getPosition(mMainWindow) : mousePos);
            sprite.setTexture(texture);
            sprite.setColor(sf::Color::Red);
            sprite.setOrigin(static_cast<float>(sprite.getTextureRect().width) / 2, static_cast<float>(sprite.getTextureRect().height) / 2);
            sprite.setPosition(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y));
                        focus=nullptr;
            EnemyVector.push_back(sprite);
                        EnemyDestinations.push_back(sf::Vector2f(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y)));
        }
                if (leftclicked)
                {
                        for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
                        {
                                if (enemy->getGlobalBounds().contains(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y)))
                                {
                                        if(focus==nullptr)
                                        {
                                        focus = &(*enemy);
                                        EnemyDestinations[0]=sf::Vector2f(static_cast<float>(mousePos.x),static_cast<float>(mousePos.y));
                                        move=false;
                                        break;
                                        }
                                }
                                else
                                {
                                        move=true;
                                        EnemyDestinations[0]=sf::Vector2f(static_cast<float>(mousePos.x),static_cast<float>(mousePos.y));
                                }
                        }
                }
                if(move)
                {
                        {
                                if(focus!=nullptr)
                                {      
                                        focusxvar = focus->getPosition().x;
                                        focusyvar = focus->getPosition().y;

                                        focus->move(((EnemyDestinations[0].x - focusxvar)*time.asSeconds()*10),
                                                         (EnemyDestinations[0].y - focusyvar)*time.asSeconds()*10);
                                        clock.restart();

                                        if((EnemyDestinations[0].x == focusxvar && EnemyDestinations[0].y == focusyvar))
                                        {
                                                focus=nullptr;
                                        }
                                }
                        }
                }
        mMainWindow.clear();
        for (auto& enemy = EnemyVector.begin(); enemy != EnemyVector.end(); ++enemy)
        {
            mMainWindow.draw(*enemy);
        }
        mMainWindow.display();
    }
    return 0;
}
« Last Edit: March 09, 2015, 10:06:21 am by Bogdan »

StormWingDelta

  • Sr. Member
  • ****
  • Posts: 365
    • View Profile
Re: Moving sprites to target position.
« Reply #8 on: March 09, 2015, 02:31:38 pm »
If you are going for simultaneous movement you are going to need a group selection of some kind.  Are you talking multiple sprites on the same tile or spread over many tiles?  In one case moving a list of sprites from one tile you have to have all selected first.  The other case is the same idea just spread over many tiles.
I have many ideas but need the help of others to find way to make use of them.