Generowanie mapy

0

Cześć.

Piszę grę (aktualnie w C#...) i próbuję jakoś zrobić generowanie mapy.
Mam taką tablicę:

int[,] map = new int[80, 45];

Czyli mapa ma 80 x i 45 y.

Generowanie ma być następujące:

  • Wybiera najpierw losową wartość od 1 do 45 (start mapy)
  • Start mapy zaczyna od ustawienia w tym miejscu int'a 2
  • Poniżej każdego punktu ustawia 5, a powyżej 0
    I tak 80 razy.
protected void GenerateWorld()
        {
            Random randObj = new Random();
            int start = randObj.Next(10, 30);
            for (int x = 0; x < 80; x++)
            {
                map[x, start] = 2;
                for (int y = 0; y < start; y++) map[x, y] = 5;
                for (int y = start + 1; y < 45; y++) map[x, y] = 0;
            }
        }

Taki kod będzie odpowiedni czy może da się to zrobić jeszcze inaczej?

0

Można np tak: int start = randObj.Next(10, 30);
int[] Tb={5,2,0};
for(int x=0;x<80;++x) for(int y=0;y<45;++y) map[x,y]=Tb[1-(int)(x<start)+(int)(x>start)];

Ale rozważ odwrócenie tej mapy w pamięci w sensie
int[,] map = new int[45,80];
zainicjalizowanie pierwszego wiersza a potem kopiowanie tego w pozostałe.
0

Można np tak:

Nie za bardzo, bo to nie zadziała w C# (w tym języku autor pisze) - nie ma konwersji bool -> int.
Można oczywiście obejść przepisując 1-(int)(x<start)+(int)(x>start) na coś nie wykorzystującego tej konwersji.

0

Dobra teraz rozwijamy :>
Przy każdej kolejnej linii odbywa się kolejny random:
a) albo funkcja wykonuje się po staremu
b) albo funkcja zwiększa y o 1 i ustawia dla niego 3
c) albo funkcja zmniejsza y o 1 i ustawia dla niego 4

Dla punktów a i b sprawdza jeszcze czy y nie jest mniejsze lub równe 2 oraz większe od 43

@Edit
Wyszło mi coś takiego:

protected void GenerateWorld()
        {
            Random randObj = new Random();
            int start = randObj.Next(10, 30), rand = randObj.Next(1,3);
            for (int x = 0; x < 80; x++)
            {
                map[x, start] = 2;
                for (int y = 0; y < start; y++) map[x, y] = 5;
                for (int y = start + 1; y < 45; y++) map[x, y] = 0;
                if (rand == 1)
                {
                    if (start > 2 || start < 43)
                    {
                        start++;
                        map[x, start + 1] = 3;
                        for (int y = 0; y < start; y++) map[x, y] = 5;
                        for (int y = start + 1; y < 45; y++) map[x, y] = 0;
                    }
                }
                else if (rand == 2)
                {
                    if (start > 2 || start < 43)
                    {
                        start--;
                        map[x, start - 1] = 4;
                        for (int y = 0; y < start; y++) map[x, y] = 5;
                        for (int y = start + 1; y < 45; y++) map[x, y] = 0;
                    }
                }
            }
        }

Jakieś sugestie?

0

Wszytko zależy od założeń jakie masz co do tej mapy. Jeśli jest to mapa reprezentująca lody i morza, to można posłużyć się np modelem Isinga (sterując parametrami, można ustalić ilość lądów i spójność wysp).
Jeśli generujesz jakiś labirynt, to trzeba było by skorzystać z teorii grafów by zrobić to mądrze (by każde miejsce było osiągalne).
Czyli napisz konkretnie co to za mapa jakie ma obiekty i jakie masz oczekiwania co do tej mapy.

0

Ma być to mapa do gry 2d widok od "boku". 0 to pusta przestrzeń 5 to ziemia, 2 to trawa, 3 to trawa w lewy dolny róg, 4 to trawa w prawy dolny róg i chcę aby z tego powstała "spójna" ziemia

0

Zmieniłem język na C++.
Teraz mam taki kod:

void generateMap()
{
    int start = 25, r;
    for (int x = 0; x < 80; x++)
    {
        r = rand() % 3;
        if (r == 0)
        {
            if (start > 2 || start < 43)
            {
                start++;
                map[x][start] = 1;
                for (int y = 0; y < start; y++) map[x][y] = 2;
                for (int y = start + 1; y < 45; y++) map[x][y] = 0;
            }
            else
            {
                map[x][start] = 1;
                for (int y = 0; y < start; y++) map[x][y] = 2;
                for (int y = start + 1; y < 45; y++) map[x][y] = 0;
            }
        }
        else if (r == 1)
        {
            if (start > 2 || start < 43)
            {
                start--;
                map[x][start] = 1;
                for (int y = 0; y < start; y++) map[x][y] = 2;
                for (int y = start + 1; y < 45; y++) map[x][y] = 0;
            }
            else
            {
                map[x][start] = 1;
                for (int y = 0; y < start; y++) map[x][y] = 2;
                for (int y = start + 1; y < 45; y++) map[x][y] = 0;
            }
        }
        else
        {
            map[x][start] = 1;
            for (int y = 0; y < start; y++) map[x][y] = 2;
            for (int y = start + 1; y < 45; y++) map[x][y] = 0;
        }
    }
}

Pomoże ktoś zoptymalizować ? :> Bo mi się wydaje, że jest troszkę źle :(

P.S.
Zmieniło się trochę to, że:
0 - pusta przestrzeń
1 - trawa
2 - ziemia
i na razie nic więcej.

0

Prosty sposób, który mi przyszedł do głowy by utworzyć coś a'la lądy. Losujemy pusty kafelek. Liczymy ile sąsiednich kafelków jest lądem. Następnie losujemy liczbę która pozwoli określić, czy postawić na kafelku ląd. Niech prawdopodobieństwo rośnie wraz z ilością sąsiednich lądów czyli np.

bool postawic_lad = 9 * randObj.NextDouble() < ilosc_sasiadow; // 9 bo mamy max 8 sąsiadów

Prawdopodobieństwo nie musi się rozkładać dokładnie liniowo. Możesz wręcz ręcznie podać (stabelaryzować) prawdopodobieństwo dla każdej ilości sąsiadów z osobna. Różne efekty otrzymasz przy różnych regułach.

0

Dzięki sopelek ;d
Kod po zmianie:

void generateMap()
{
    int start = 25, r;
    for (int x = 0; x < 80; x++)
    {
        r = rand() % 3;
        if (r == 0)
        {
            if (start > 2 || start < 43) start++;
        }
        else if (r == 1)
        {
            if (start > 2 || start < 43) start--;
        }
        map[x][start] = 1;
        for (int y = 0; y < start; y++) map[x][y] = 2;
        for (int y = start + 1; y < 45; y++) map[x][y] = 0;
    }
}
0

naprawdę?
void generateMap()
{
int start = 25, r;
for (int x = 0; x < 80; x++)
{
r = rand() % 3;
if (start > 2 || start < 43 && r<2)
start+=(r<<1)-1; //r*2 wyjdzie 2 albo 0, po odjęciu 1 zostanie 1 albo -1
map[x][start] = 1; //lol po co to jest? jak nie potrzebne to wywal
for (int y = 0; y < start; y++) map[x][y] = 2;
for (int y = start + 1; y < 45; y++) map[x][y] = 0;
}
}
i staraj się używać preinkrementacji (++a) niż postinkrementacji (a++) jeśli nie jest to konieczne, bo postinkrementacja to udefined behavior

0

map[x][start] = 1
Jest potrzebne. To jest trawa pod nia ziemia i nad nia pusto.

Mozesz wyjasnic to undefined ?

1

i staraj się używać preinkrementacji (++a) niż postinkrementacji (a++) jeśli nie jest to konieczne, bo postinkrementacja to udefined behavior

Co to za bzdura?

Z undefined behavior możemy się spotkać zarówno przy preinkrementacji jak i postinkrementacji, gdy dwa razy zmodyfikujemy zmienną i nie oddzielimy tych operacji sequence pointem.
Przykładowo: ++(++a) to undefined behavior (pomimo wykorzystania preinkrementacji).
A już abstrahując od tego - gdy na typie prostym wykonujemy postinkrementację i nie chcemy zachować rezultatu sprzed tej operacji to jedną z najprostszych optymalizacji kompilatora jest właśnie sprawienie, by ++a i a++ były tak samo wydajne. Tak właśnie, gdy dzieje się to w standardowym przypadku pętli for.

1

i staraj się używać preinkrementacji (++a) niż postinkrementacji (a++) jeśli nie jest to konieczne, bo postinkrementacja to udefined behavior

Lepiej uzywac preinkrementacji ale akurat z innego powodu. Kod gdzie stosuje sie preinkrementacje latwiej przerobic na kod dzialajacy na iteratorach. Tzn. preinkrementacja w przypadku bardziej zlozonych iteratorow jest szybsza od postinkrementacji. I bardzo watpliwe, zeby kompilator zamienil postinkrementacje iteratora listowego na preinkrementacje w przypadkach gdzie ma to sens.

1 użytkowników online, w tym zalogowanych: 0, gości: 1