Cpp + SFML Spiel



  • Hi,

    um ich mal wieder etwas in C++ einzuarbeiten wollte ich einfach mal ein 2d Spiel schreiben mit Hilfe von SFML.
    Sicher kennt ihr die Pokemon Spiele für den gameboy, so ähnlich solls halt werden. Spieler immer in der Mitte nur der Hintergund bewegt sich und alles mit vorgegebenen Feldern, sodass Pixel Kollisonen nichts zur Sache tun. Nun wollt ich erstm mit dem graphischen Teil anfangen, da ich damit doch recht wenig Erfahrung habe.
    Sprich erstmal nur ein Raum, an den Seiten begrentzt ohne irgendwelche Objekte, nur der Spieler der dort lang läuft.

    Animationen zu erstellen war bis jetzt kein Problem, man müsste sie nur in die Bewegung einbinden.

    Jetzt zu meiner Frage wie geh ich das am Besten an ? Mit einem 2d vector der jedes Feld speichert(Textur, denn es soll nicht eine einfache Fläsche sein sondern jedes Feld soll eine eigene Textur haben können) oder den Hintergrund einfach um eine konstante Pixelzahl verschieben ...
    Ich bin mir da echt nicht ganz sicher, hoffe jemand der schon etwas mit SFML oder allgemein 2d Anwendungen gearbeitet hat kann mir helfen. 😉



  • Du machst dir eine große Textur (Tilemap) die alle Tiles für das Level hält. Das Aussehen des Levels wird dann definiert durch einen Index in diese map. Den Kram schiebst du in einen VBO (äh, das wäre für OpenGL/DirectX, also, du hälst die Daten irgendwie so vor, dass man sie zeichnen kann) und dann zeichnest du den Kram halt abhängig von der Position der Spielfigur.



  • Ok, Tilemap schau ich mir mal an und du meinst alles relaiv zum Spieler zeichnen ? Klingt schonmal logisch vielen Dank, falls ihr noch Tipps habt würd ich mich sehr freuen oder ich melde mich nochmal wenn ich noch Fragen habe.



  • Fang am besten einfach an. Vertex Arrays (VBOs gibts in SFML nicht) brauchst du für den Anfang nicht, das kannst du dir später zur Optimierung vormerken.

    Einfach heisst: Du hast ein logisches 2D-Array, das die Daten für jedes Tile abspeichert. Am Anfang ist pro Tile vielleicht nur eine enum -Variable für den Tile-Typen gespeichert, mit der Zeit kannst du da auch andere Daten einbauen.

    Nun schaust du pro Frame, welche Tiles gerade im aktuellen Sichtfeld ( sf::View ) sind, und zeichnest nur diese. Zeichnen kannst du mittels sf::Sprite , die zugehörige sf::Texture wählst du aufgrund des Tile-Typen aus. Eigentlich sollte es performancemässig kein Problem sein, pro Frame neue Sprites zu erstellen, aber alternativ kannst du diese auch in der Tilemap abspeichern.



  • Vielen Dank und wenn sich der Spiele bewegt und sich der Hintergrund verschieb soll ich die Kamera schwenken lassen oder wirklich die Tile Texturen verschieben?



  • Die Tiles bleiben am Ort, du kannst das View verschieben.



  • und dann wenn es mal was größer wird mit Chunks ? Also am Rande schon den nächsten vorladen oder alles wie bisher verschiebn und nur das nächste zeichnen ? Dann wär aber alles im Speicher



  • Du kannst es erstmal machen wie Pokemon, also mehr oder weniger kleine Level connected mit Portalen. Das ist sehr einfach. Eine kontinuierliche Welt ist schon etwas komplizierter, da musste dir was ausdenken. Chunks sind dabei schon mal keine schlechte Idee, dann musst du halt noch überlegen wann du was von der Platte lädst etc. Wobei, auf einem PC kannst du bei so einem Spiel wahrscheinlich mehr Strecke auf einmal in den Speicher laden als jemals jemand zurücklegen könnte.



  • Ok, ich denke soweit ist mir das jetzt eigentlich alles klar, aber bei der umsetzung bekomm ich dann doch etwas Schwierigkeiten. Ich habe grad einfachmal versucht eine 10*10 Tile große Fläsche mit der selben Textur zu erstellen.
    Ich denke aber, dass ich das irgendwie falsch angegangen bin, da es erstens doch relativ lange dauert bis etwas geschiet und zweitens, da anstatt der Textur nur ein weißes Feld entsteht.

    #include <SFML/Graphics.hpp>
    #include "Tile.h"
    
    int main() {
    	sf::RenderWindow window(sf::VideoMode(600, 600, 32), "Einfacher Raum", sf::Style::Close);
    	sf::Texture t;
    	t.loadFromFile("texture.png", sf::IntRect(0, 0, 16, 16));
    	std::vector<std::vector<Tile>> tilemap(10, std::vector<Tile>(10));
    	for(unsigned int x = 0; x < tilemap.size(); x++) {
    		for(unsigned int y = 0; y < tilemap[x].size(); y++) {
    			Tile tile;
    			tile.setTexture(t);
    			tilemap[x][y] = tile;
    		}
    	}
    	sf::Event event;
    	while(window.isOpen()) {
    		while(window.pollEvent(event)) {
    			if(event.type == sf::Event::Closed || event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) window.close();
    		}
    		for(unsigned int x = 0; x < tilemap.size(); x++) {
    			for(unsigned int y = 0; y < tilemap[x].size(); y++) {
    				sf::Sprite s;
    				s.setTexture(tilemap[x][y].getTexture());
    				s.setPosition(x * s.getGlobalBounds().width, y * s.getGlobalBounds().height);
    				window.draw(s);
    			}
    		}
    		window.display();
    		window.clear();
    	}
    	return 0;
    }
    
    #ifndef TILE_H
    #define TILE_H
    
    #include <SFML/Graphics/Texture.hpp>
    
    class Tile {
    public:
    	void setTexture(sf::Texture texture) { _texture = texture; };
    	sf::Texture getTexture() { return _texture; };
    private:
    	sf::Texture _texture;
    };
    #endif
    

    Sorry wenn hier gravierende Fehler sind komm grad von Java und will natürlich auch C++ beherschen 😉



  • Schau dir die Dokumentation zu sf::Sprite und sf::Texture an. Du willst sicher nicht pro Tile eine Textur.



  • Sorry, hab nochmal eure Antworten durchgelesen und schon überarbeitet, Tile sieht jetzt so aus, so war das doch gemeint oder ?

    #ifndef TILE_H
    #define TILE_H
    
    #include <SFML/Graphics/Texture.hpp>
    
    class Tile {
    public:
    	void setTyp(unsigned int typ) { _typ = typ; };
    	unsigned int getTyp() { return _typ; };
    	const enum Typs { WOOD, STONE };
    private:
    	unsigned int _typ;
    };
    #endif
    


  • Grundsätzlich ja, aber was soll const enum sein? Und warum nimmst du unsigned int , wenn du extra den Datentyp Typs (englisch wäre übrigens "Type") definierst?

    Das #include brauchst du auch nicht mehr. Und du solltest von der Angewohnheit wegkommen, präventiv für jede Eigenschaft gleich ein get/set-Methodenpaar zu definieren. Ein Konstruktor wäre vielleicht sinnvoll.



  • Sorry bin das mit den unsigned so gewöhnt und typs ist eine art Denglisch ^^
    hab halt die alte Klasse verändert und vergessen den #include rauszunehmen und das set get zu ändern. Mit const hab ich was ausprobiert, frag besser nicht war etwas sinnlos und _typ speichert die Art dieses Tiles während man Typs einfach zum vergleichen verwendet(if(tile.getTyp == Tile::WOOD) usw..
    Ok, das war nur ne schnell ausgetauschte Klasse, tut mir leid, hab einfach keinen 2. Blick drüber geworfen. Und View verschiebe ich mit move? Wie mach ich denn dann die Spielfigur davon unabhängig ?



  • Sorry habs schon, erst denken dann Fragen oder eher sein lassen XD



  • Und kein _ vor Variablen, etc. Das ist für die Implementierung reserviert!!!!!!!!!!!



  • u machst dir eine große Textur (Tilemap) die alle Tiles für das Level hält. Das Aussehen des Levels wird dann definiert durch einen Index in diese map. Den Kram schiebst du in einen VBO (äh, das wäre für OpenGL/DirectX, also, du hälst die Daten irgendwie so vor, dass man sie zeichnen kann) und dann zeichnest du den Kram halt abhängig von der Position der Spie



  • jhhhhhhhhh schrieb:

    Und kein _ vor Variablen, etc. Das ist für die Implementierung reserviert!!!!!!!!!!!

    Nö.

    int _Gross; // Nicht erlaubt !
    int _klein; // Erlaubt !
    int __bla;  // Nicht erlaubt !
    

  • Mod

    Ethon schrieb:

    jhhhhhhhhh schrieb:

    Und kein _ vor Variablen, etc. Das ist für die Implementierung reserviert!!!!!!!!!!!

    Nö.

    int _klein; // Erlaubt !
    

    ausser im globalen Namensraum.


Anmelden zum Antworten