Mehrere Sprites auf einmal bewegen.



  • Hallo Leute,
    es geht darum mehrere Sprites zu bewegen (SFML mit C++ 2010). Egal was ich probiere: Entweder es bewegen sich alle auf einmal (wenn ich alles durch eine Schleife laufen lasse) oder eben wie hier im Code jeweils nur ein Sprite (das was zuletzt angeklickt wurde).
    Was muss man tun, damit man mehrere Sprites bewegen kann, also hier in dem Beispiel durch Klick auf die einzelnen Kästchen, diese einfach in Bewegung setzen. Schon mal vielen Dank im Voraus für jegliche Tipps.

    #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;
    	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.setOrigin(sprite.getTextureRect().width / 2,sprite.getTextureRect().height / 2);
                sprite.setPosition((mousePos.x),(mousePos.y));
    			focus=nullptr;
                EnemyVector.push_back(sprite);
            }
    		if (leftclicked)
    		{
    			for (auto& enemy = EnemyVector.begin(); enemy != EnemyVector.end(); ++enemy)
    			{
    				if (enemy->getGlobalBounds().contains((mousePos.x),(mousePos.y)))
    				{
    					focus = &(*enemy);
    					move=true;
    				}
    			}
    		}
    		if(move)
    		{
    			if(focus!=nullptr)
    				focus->move(1,0);
    		}
            mMainWindow.clear();
            for (auto& enemy = EnemyVector.begin(); enemy != EnemyVector.end(); ++enemy)
            {
                mMainWindow.draw(*enemy);
            }
            mMainWindow.display();
        }
        return 0;
    }
    


  • eldottore schrieb:

    es geht darum mehrere Sprites zu bewegen (SFML mit C++ 2010). Egal was ich probiere: Entweder es bewegen sich alle auf einmal (wenn ich alles durch eine Schleife laufen lasse) oder eben wie hier im Code jeweils nur ein Sprite (das was zuletzt angeklickt wurde).
    Was muss man tun, damit man mehrere Sprites bewegen kann, also hier in dem Beispiel durch Klick auf die einzelnen Kästchen, diese einfach in Bewegung setzen.

    Du musst Dir dann wohl eine Möglichkeit schaffen bewegte von unbewegten Sprites zu unterscheiden.
    Du könntest z.b. für jeden Feind ein std::pair<bool, sprite> in EnemyVector speichern und dort vermerken, ob das sprite sich bewegen soll, oder nicht.



  • So, habe das jetzt als pair umgeschrieben, komme jetzt aber nicht weiter bei dem move. Es müsste doch jetzt irgendwie ne Bedingung her, wie "Bewege nur die Sprites, welche auf true stehen". Wie schreibt man so einen Befehl?

    #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<std::pair<sf::Sprite, bool>> EnemyVector;
    	sf::Sprite* focus = nullptr;
    	bool move = false;
    
        while (mMainWindow.isOpen())
        {
            sf::Event event;
            bool creating = false;
            bool leftclicked = false;
            sf::Vector2i mousePos;
    		int pos = 0;
    
            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.setOrigin(sprite.getTextureRect().width / 2,sprite.getTextureRect().height / 2);
                sprite.setPosition((mousePos.x),(mousePos.y));
    			focus=nullptr;
    			EnemyVector.push_back(std::make_pair(sprite,false) );
            }
    		if (leftclicked)
    		{
    			for (auto& enemy=EnemyVector.begin(); enemy!=EnemyVector.end(); ++enemy)
    			{
    				if (enemy->first.getGlobalBounds().contains((mousePos.x),(mousePos.y)))
    				{
    					focus = &(enemy->first);
    					pos = enemy - EnemyVector.begin();
    					move=true;
    					EnemyVector[pos].second=true;
    				}
    			}
    		}
    		if(move)
    		{
    			if(focus!=nullptr)
    				focus->move(1,0);
    		}
            mMainWindow.clear();
            for (auto& enemy = EnemyVector.begin(); enemy != EnemyVector.end(); ++enemy)
            {
                mMainWindow.draw(enemy->first);
            }
            mMainWindow.display();
        }
        return 0;
    }
    


  • Was machst du denn da? Du nutzt den Pair-bool doch gar nicht!?

    for (auto& enemy = EnemyVector.begin(); enemy != EnemyVector.end(); ++enemy)
    {
       if(enemy->second)
         enemy->first.move(1,0);
       mMainWindow.draw(enemy->first);
    }
    

    Später vielleicht übliche, separate 'update' und 'draw' Funktionen schreiben.



  • Dieser Thread wurde von Moderator/in SeppJ aus dem Forum C++ (alle ISO-Standards) in das Forum Spiele-/Grafikprogrammierung verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Funktioniert alles soweit, rätsle jetzt aber schon seit längerem über ein Sache im gleichen Zusammenhang wie die Themenstellung.

    Es geht darum Sprites einzeln anzuklicken und sie individuell mit einem weiteren Klick jeweils auf eine eigene Zielposition zu schicken, die dann auch nicht mehr verändert werden kann, außer man klickt das Sprite erneut an.

    Also Sprite A anklicken und per nochmaligem Klick auf ein Ziel bewegen und noch während die Bewegung von Sprite A läuft, Sprite B anklicken und wiederum auf eine andere Position bewegen usw.

    Jetzt ist es so, dass alle Sprites auf die gleiche Position zulaufen, wenn man irgendwo hin klickt. Hab irgendwie kein Vorstellungsvermögen, wie man das umsetzen könnte. Man müsste jedes Sprite irgendwie dazu bringen, individuelle Zielkoordinaten anzunehmen und jeweils nur eine Bewegung zuzulassen, bevor es automatisch deselektiert wird..........Bin für jede Hilfe dankbar.

    #include <SFML/Graphics.hpp>
    #include <iostream>
    #include <vector>
    #include <tuple>
    
    int main()
    {
        sf::RenderWindow mMainWindow(sf::VideoMode(600,600), "Map", sf::Style::Close);
        mMainWindow.setFramerateLimit(60);
        mMainWindow.setKeyRepeatEnabled(false);
        sf::Texture texture;
        texture.loadFromFile("sprite.png");
    
    	std::vector<std::tuple<sf::Sprite,bool,sf::Vector2f>> EnemyVector;
    
    	sf::Sprite* focus = nullptr;
    	bool move = false;
    
        while (mMainWindow.isOpen())
        {
            sf::Event event;
            bool creating = false;
            bool leftclicked = false;
    		bool rightclicked = 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 (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.setOrigin(sprite.getTextureRect().width / 2.0f,sprite.getTextureRect().height / 2.0f);
                sprite.setPosition((mousePos.x),(mousePos.y));
    			focus=nullptr;
    			EnemyVector.push_back(std::make_tuple(sprite,false,sf::Vector2f((mousePos.x),(mousePos.y))));
            }
    		if (leftclicked)
    		{
    			for (auto& enemy=EnemyVector.rbegin(); enemy!=EnemyVector.rend(); ++enemy)
    			{
    				if (std::get<0>(*enemy).getGlobalBounds().contains((mousePos.x),(mousePos.y)))	
    				{
    					focus = &(std::get<0>(*enemy));
    					std::get<2>(*enemy)=sf::Vector2f((mousePos.x),(mousePos.y));
    					std::get<1>(*enemy)=true;
    					move=false;
    					break;
    				}
    				else
    				{
    					move=true;
    					std::get<2>(*enemy)=sf::Vector2f((mousePos.x),(mousePos.y));
    				}
    			}
    		}
    		if(rightclicked)
    		{
    			if(focus!=nullptr)
    			for (auto& enemy=EnemyVector.rbegin(); enemy!=EnemyVector.rend(); ++enemy)
    				if (std::get<0>(*enemy).getGlobalBounds().contains((mousePos.x),(mousePos.y)))
    				{
    					std::get<1>(*enemy)=false;
    					break;
    				}
    		}
    		if(move)
    			if(focus!=nullptr)
    			for (auto& enemy = EnemyVector.rbegin(); enemy != EnemyVector.rend(); ++enemy)
    			{
    				if(std::get<1>(*enemy))
    				{
    					std::get<0>(*enemy).move(((std::get<2>(*enemy).x - std::get<0>(*enemy).getPosition().x)*0.01),
    					(std::get<2>(*enemy).y - std::get<0>(*enemy).getPosition().y)*0.01);
    				}
    			}
            mMainWindow.clear();
            for (auto& enemy = EnemyVector.begin(); enemy != EnemyVector.end(); ++enemy)
            {
    			mMainWindow.draw(std::get<0>(*enemy));
            }
            mMainWindow.display();
        }
        return 0;
    }
    


  • Mit 100+ Zeilen wird es langsam unübersichtlich in der main() Funktion. Wie sieht es denn aus mit Deinem Wissen über Funktionen und Objekte?

    Nachdem was ich jetzt lese (und Dein std::tuple sehend), denke ich Du könntest eventuell eine eigene Klasse für Deine beweglichen Sprites einführen.

    // beispielhaft ohne Anspruch auf Vollstaendigkeit :)
    struct enemy{
      sf::Sprite m_sprite;
      sf::Vector2f m_target_pos;
      sf::Vector2f m_velocity;
      const sf::Vector2f& get_position() const {
        return m_sprite.get_position();
      }
      bool is_moving() const {
        return m_velocity!=sf::Vector2f{};
      }
    };
    

    An und für sich hast Du den Großteil schon erschlagen, wenn Du ein paar sinvolle Methoden für Deine enemy -Klasse implementierst.



  • Also Funktionen sind mir bekannt, Klassen hab ich bis jetzt noch nicht gebraucht 🙂
    Habe zusätzlich noch Funktionen im Tupel erstellt, wo die Bewegungsformel für jede Einheit separat gespeichert wird, komme aber nicht weiter, weil ich nicht weiß, was man da überhaupt rein von der Logik her machen kann, damit es wie gewünscht funktioniert.



  • eldottore schrieb:

    Also Funktionen sind mir bekannt, Klassen hab ich bis jetzt noch nicht gebraucht 🙂

    Ja dann nimm doch ein paar Funktionen und teil Dein Programm erstmal auf.
    Ob Du jetzt ein std::tuple oder eine Klasse nimmst ist doch erstmal egal.
    Hauptsache, Du kriegst erstmal Ordnung in Deinen Code und Deine Gedanken.

    Deine main() könnte z.B. so aussehen:

    int main() {
      sf::RenderWindow wnd(sf::VideoMode(600,600), "Map", sf::Style::Close);
      wnd.setFramerateLimit(60);
      // einfacher gameloop
      while (wnd.isOpen()) {
        // alle eingaben verarbeiten
        process_input(wnd);
        // alles bewegen usw.
        update(wnd);
        // alles zeichnen
        render(wnd);
      }
    }
    


  • du könntest mehrere Sprites dank einer for-Schleife bewegen:

    for(int i = 0; i < 10; i++)
    {
     [...]
    }
    

    Zuvor aber musst du, wenn du diese Methode anwendest, ein Array erstellen!

    #include <array>
    
    [...]
    
    std::array<Sprite, 10> name;
    

    Der Rest dürfte dir bewusst sein 😉



  • Habe das damals so gelöst, indem jedes Sprite ein eigenes Feld im Tupel für die Zielkoordinaten erhielt und so konnte sich alles unabhängig voneinander bewegen.


Anmelden zum Antworten