Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Generowanie mapy w locie po określonym kluczu (SEED)

Ostatnio zmodyfikowano 2016-01-06 21:38
Autor Wiadomość
arczi14
Temat założony przez niniejszego użytkownika
Generowanie mapy w locie po określonym kluczu (SEED)
» 2015-12-10 22:15:16
Witam,
Rzuciłem się na głęboką wodę piszę coś na kształt minecraft w 2 wymiarach i zamiast jak każdy początkujący wybrać mapę statyczną wczytywaną z pliku
zaprojektowałem silnik raczej pod dynamiczne generowanie terenu. Drzewa czwórkowe łatwo w czymś takim zastosować mam wrażenie.
Ale powstają problemy i to dość poważnie. Paradoksalnie gra z pozoru tak prosta jak Mc to jednak zmyślny kawałek kodu.
Przechodząc do rzeczy jestem skłony zadać pytanie jak? Jak w tego typu grach rozwiązywana jest kwestia generowania map ?
I drugie pytanie wszelkie zmiany na mapie muszą być jakoś zapisywane. w jaki sposób je można zapisać i jak te zmiany uwzględnić w generowanym świecie?
Ktoś poradzi coś?
P-141739
RazzorFlame
» 2015-12-15 08:26:19
Podziel sobie mapę na chunki czyli w Twoim przypadku prostokąty. Rozmiar jest dowolny ale nie wypada dawać zbyt małych np. 2x4 gdyż odczytywanie i zapisywanie będzie ciężkie. Z kolei gdy dasz zbyt duże np. 1000x1000 to przy zmianie 1 klocka czy tam kratki (nadpisujesz cały chunk) będzie to trwało trochę długo. Polecam wybrać wymiary od minimum rozmiaru ekranu (podanych w ilości kostek wszerz i wzdłuż) do ok. 100x100. Następnie wszystkie chunki pakujesz do vectora pamiętając, że przy dużej ilości elementów push_back jest powolne i opracowujesz jakąś technikę dostępu do poszczególnego klocka w chunku np:
C/C++
class Chunk;
class MapTile;
class Map
{
    std::vector < Chunk *> Chunks;
public:
    Chunk * GetChunkAt( int x, int y ); //zwraca wskaznik chunku dla okreslonej pozycji
};
class Chunk
{
    std::vector < MapTile *> Tiles;
public:
    MapTile * GetTileAt( int x, int y );
};
class MapTile { }; // wlasna implementacja
 
P-142003
pekfos
» 2015-12-15 17:36:41
P-142011
arczi14
Temat założony przez niniejszego użytkownika
» 2016-01-04 15:03:35
RazzorFlame mógłbyś dokładnie opisać czym są chunki ?  I w jaki sposób ma to działać? Jest może jakaś literatura na ten temat?
P-142838
Gibas11
» 2016-01-04 15:57:34
@autor Chunki razem upakowane kawałki terenu, razem je wczytujesz, zapisujesz itd.
@RazzorFlame Może zamiast vectora powinien użyć tablicy asocjacyjnej? Trochę roboty, ale działałaby raczej szybciej niż vector, można by szybko po niej przeiterować i bardzo szybko dodawać nowe elementy, tylko usuwanie jest raczej wolne, ale usuwanie chunków w tego typu grze raczej rzadko się zdarza (przy obecnych ilościach ramu i prawdopodobnym zapotrzebowaniu tej gry można i w ogóle).
P-142839
arczi14
Temat założony przez niniejszego użytkownika
» 2016-01-04 16:18:50
Dobra Panie i Panowie powiem wam jak to jak na razie u mnie wylgąda. Gdyż projekt się rozwija.

Mam dwa kontenery w jednym wszystkie obiekty razem w drugim quadTree to kolizji, które swoją drogą nie działają najlepiej na granicach jednego drzewka z drugim, ale mniejsza o to.  Wiadomo marnotrawienie pamięci ale nic lepszego nie wymyśliłem.

Algorytmem PerlinNoice generuję jakąś wysokość i do wysokości minimalnej dodaję wygenerowaną z klucza wysokość daje to ładny efekt.
Następnie robię pętlę i,j i dodaję kolejno do obu kontenerów każdy obiekt.

Wygląda to mniej więcej tak
C/C++
PerlinNoise * noise = new PerlinNoise( SEED, CHUNK );

p = new Quadtree( 0.0f, 0.0f,(( worldSizeMin.x + worldSizeMax.x ) * 32 ),(( worldSizeMin.y + worldSizeMax.y ) * 32 ), 0, 3 );

float width = 32;
float height = 32;
long long int summator = 0;

for( int i = 0; i < worldSizeMax.x + worldSizeMin.x; i++ ) //columns (x values
{
    int columnHeight = 2 + noise->getNoise( i - worldSizeMin.x, worldSizeMax.y - worldSizeMin.y - 2 );
   
    mapIndex.push_back( sf::Vector3f( i,( worldSizeMin.y + columnHeight ), summator ) );
    summator = summator + worldSizeMin.y + columnHeight;
   
    for( int j = 0; j < worldSizeMin.y + columnHeight; j++ ) //rows (y values)
   
    {
        sf::Vector2f currentPosition( i * width,(( worldSizeMax.y + worldSizeMin.y ) - j ) * height );
       
        DirtGrass * dirtGrass = new DirtGrass( currentPosition, sf::Vector2f( width, height ) );
        p->AddObject( dirtGrass );
        worldContainer.push_back( dirtGrass );
    }
}

Jak widać mam jeszczę kontener o nazwię mapIndex dzięki któremu mogę sobie ograniczyć generowany obszar do rysowania:

jak widać summator dodawany do mapIndex to ilość klocków które znajdują się przed elementem. jak dla x=0 tworzymy 7 klocków to dla x=1 sumator=7 ... a jeśli w x1 zrobimy już 10 kolejnych klocków to dla x2 sumator = 17 i tak dalej. tak więc wiemy że jak mamy rysować od np x1 do x10 to robimy zwykłą petlę w której od i=0 dodajemy summator gdyż wiadomo, że w kontenerze od i = 7 są już klocki z x1 (przynajmniej zakładamy że od 7 aż do końca wysokości zapisanej w mapIndex będą klocki z pozycją odpowiadającą x1).

Rysowanie wygląda jak narazie tak:

C/C++
for( int i = cam.mX /* Okreslana wielkość ekranu względem kamery, gracz na pozycji np 1024 to wiadomo że trzeba rysować dla x=32 bo jeden klocek ma 32 px czyli 32*32 to 1024 */; i < cam.screenSizeX + cam.mX /* do początku dodajemy rozdzielczość ekranu dzielona przez 32 czyli jeden klocek*/; i++ )
{
    for( long long int j = abs( cam.mY ) - int( cam.screenSizeY ); j < abs( cam.mY ) + int( cam.screenSizeY ) / 2; j++ ) // Robimy to samo co wyżej ale określamy wartość rysowania w pionie.
    {
        WindowApp->draw( w1->cont[ w1->mapIndex[ i ].z + j ]->drawableObject );
    }
}

Mam nadzieję że kod jest dość jasny i że da się go ogarnąć. Tylko takie rozwiązanie ma jednak wadę. Jak będziemy chcieli usunąć albo dodać jakiś klocek to będziemy musieli znaleść go w mapIndex i potem dla każdego x zmiejszyć wartość summatora o jeden gdyż liczba klocków zmniejszyła się.
O usuwaniu z quadTree i z vektora ze wszystkimi klockami nie wspomnę.
Dodawanie byłoby jeszcze gorsze gdyż trzebaby go dodać w odpowiednim miejscu w kontenerze aby się nie posypało.

Druga sprawa jak chce mieć nieskończony świat to przecież nie mogę wszystkiego trzymać w kontenerze myślałem żeby generować tylko trochę ponad rozdzielczość ekranu i na bieżąco usuwać (jak gracz idzie w prawo) obiekty po lewej i generować nowe po prawej i analogicznie odwrotnie jakby gracz szedł w drugą stronę. i zrobić dodatkowy kontener dla zmian jaki gracz wprowadził czyli np idę w lewo generuję np 10 klocków ale w kontenerze ze zmianami jest zapisane że na pozycji x,y klocek został usunięty więc go pomijam przy generowaniu... Fajna opcja do zapisu gry by to była.

Czy to co napisałem ma jakikolwiek sens?
P-142840
arczi14
Temat założony przez niniejszego użytkownika
» 2016-01-06 21:38:13
Na prawdę nikt z tym nie jest w stanie pomóc ?
Jakiś pomysł idea cokolwiek co pomogłoby mi wpaść na pomysł jak to wykonać.
Będę na prawdę wdzięczny.
P-143028
« 1 »
  Strona 1 z 1