(2d)Chunks Algorithmus



  • Hey Leute,
    arbeite gerade an einem Spiel, das so ähnlich wie GTA 2 ist. Den Untergrund über den der Spieler läuft habe ich ihn mehrere große Bilder eingeteilt, die beim laden in kleinere Tiles zerlegt werden, die dann gerendert werden. Nun brauche ich einen Algorithmus, der entscheidet, welcher Chunk als nächstes geladen wird. Habe probiert das selber zu machen, jedoch buggt der Code rum(den ersten Chunk lädt er, aber sobald man an einer Position ist, an der er den ersten Chunk und den darunter laden muss lädt er bei jedem Durchgang etwas) und ist sehr langsam.
    Könntet ihr mir helfen den Code zu überarbeiten/ einen neuen zu schreiben, oder mir andere Lösungsmöglichkeiten vorstellen ?

    //speichert die Bereiche, die von den Chunks abgedeckt werden
    IntRect rect1, rect2, rect3, rect4, empty;
    
    struct Chunk {
    //die Tiles des Chunks
    Tile tiles[100] [100];
    //gibt an ob der Chunk benutzt wird
    bool used;
    char chunkid;
    };
    
    Chunk chunk1, chunk2, chunk3, chunk4;
    ///hier beginnt die Funktion
    //ich benutze SFML
    //Chunks sind 6400*6400 Pixel groß
    //mein Bildschirm hat 1920*1080 Pixel
    Vector2f temppos (Player::getPosition()); //Position des Spielers auf der Karte
    //Die Punkte, an denen überprüft werden soll, ob ein Chunk geladen werden muss
    Vector2<int> pos1 (temppos.x - 1000, temppos.y - 1000); 
    Vector2<int> pos2 (temppos.x + 1000, temppos.y - 1000);
    Vector2<int> pos3 (temppos.x + 1000, temppos.y + 1000);
    Vector2<int> pos4 (temppos.x - 1000, temppos.y + 1000);
    //gibt an, ob an der Position ein Chunk ist
    bool bpos1 = false;
    bool bpos2 = false;
    bool bpos3 = false;
    bool bpos4 = false;
    //gibt an ob etwas geladen werden muss
    bool createThread = false;
    
    chunk1.used = false;
    chunk2.used = false;
    chunk3.used = false;
    chunk4.used = false;
    
    while(true) {
        createThread = false;
    //*64, weil die Rects Tiles und nicht Pixel als Maßeinheit benutzen
        if(pos1.x >= rect1.left * 64 && pos1.x <= rect1.left * 64 + rect1.width * 64 && pos1.y >= rect1.top * 64 && pos1.y <= rect1.top * 64 + rect1.height * 64) {
    		chunk1.used = true;
    		bpos1 = true;
    	} else if(pos1.x >= rect2.left * 64 && pos1.x <= rect2.left * 64 + rect2.width * 64 && pos1.y >= rect2.top * 64 && pos1.y <= rect2.top * 64 + rect2.height * 64) {
    		chunk2.used = true;
    		bpos1 = true;
    	} else if(pos1.x >= rect3.left * 64 && pos1.x <= rect3.left * 64 + rect3.width * 64 && pos1.y >= rect3.top * 64 && pos1.y <= rect3.top * 64 + rect3.height * 64) {
    		chunk3.used = true;
    		bpos1 = true;
    	} else if(pos1.x >= rect4.left * 64 && pos1.x <= rect4.left * 64 + rect4.width * 64 && pos1.y >= rect4.top * 64 && pos1.y <= rect4.top * 64 + rect4.height * 64) {
    		chunk4.used = true;
    		bpos1 = true;
    	}
    ///das gleiche für die anderen Positionen(pos2, pos3 und pos4)
    ///loadInChunk ist eine Referenz auf den Chunk, in den die Daten geladen werden sollen
            if(!chunk1.used) {
    			loadInChunk = chunk1;
    		} else if(!chunk2.used) {
    			loadInChunk = chunk2;
    		} else if(!chunk3.used) {
    			loadInChunk = chunk3;
    		} else if(!chunk4.used) {
    			loadInChunk = chunk4;
    		} else {
    			loadInChunk = empty;//empty ist ein unbenutzter Chunk
    		}
    if(!bpos1) {
    			if(pos1.x >= 0 && pos1.y >= 0) {
    				loadpos.x = pos1.x;
    				loadpos.y = pos1.y;
    				bpos1 = true;
    				createThread = true;
    			} else {
    				bpos1 = true;
    			}
    /// über else if das gleiche für die anderen Positionen
    loadpos.x = loadpos.x - loadpos.x%6400;
    loadpos.y = loadpos.y - loadpos.y%6400;
    loadpos.x /= 6400;
    loadpos.y /= 6400;
    
    if(createThread) {
    			std::thread t (&World::loadChunk, this);
    			t.join();
    			createThread = false;
    		}
    if(bpos1 && bpos2 && bpos3 && bpos4)break;
    }
    

  • Mod

    dein code ist unnoetig kompliziert.
    funktionierte er ohne threading, oder wieso ist da threading drinnen?

    [code="cpp"]
    if(createThread) {
    std::thread t (&World::loadChunk, this);
    }
    [/code]
    uebergibst du jedem thread dein pointer auf denselben speicherbereich?



  • World::loadChunk() ist eine Funktion, die loadInChunk und loadPos benutzt, um den nächsten Chunk in einem Extrathread zu laden. Ich weiß, dass mein Code unnötig kompliziert ist, konnte das Problem aber nicht anders lösen. Deshalb habe ich ihn ja hier hochgeladen.



  • Ich verstehe das Problem noch nicht so recht. Du benutzt doch scheinbar eigentlich ein normales Tilesystem, oder? (Du schreibst etwas von "die chunks werden in kleinere Tiles unterteilt")
    Wieso musst du dann überhaupt entscheiden, welche chunk du laden musst? Lade doch einfach jeden und zeichne nur die sichtbaren Tiles.
    Auf der SFML-Seite ist sogar n explizites Tilemap-Beispiel gegeben.


  • Mod

    playking21 schrieb:

    Ich weiß, dass mein Code unnötig kompliziert ist, konnte das Problem aber nicht anders lösen. Deshalb habe ich ihn ja hier hochgeladen.

    du weisst nicht dass du es auch erstmal ohne threading loesen kannst? 😛
    funktionierte der code denn jemals als es noch kein threading darin gab?


Anmelden zum Antworten