Menu / szukaj

Jak działa generator map

Na prośbę jednego z graczy, i może też dlatego że jest to jeden z tych aspektów EFa którym zawsze lubiłem się zajmować, mały wpis poświęcony działaniu generatora map losowych (RMG).

Generator ma za zadanie utworzyć mapę, która nosić ma znamiona losowości, jednakże musi być sprawiedliwa dla wszystkich grających najbardziej jak to tylko możliwe. Mapy losowe występują w kilku odsłonach tematycznych, jest to nie mniej różnica tylko w wyglądzie tła i rodzaju przeszkód. W pierwszej kolejności generowane są różnorakie parametry mapy skorelowane z ilością graczy na jaką ma zostać ona przygotowana, np.: początkowy wygląd państwa, ilość złóż złota, ilość przeszkód terenowych, rozrzut złóż, itp.

Kolejnym krokiem jest rozmieszczenie graczy na mapie z uwzględnieniem pewnego rozrzutu, im więcej graczy tym jest on mniejszy aby mogli się oni w ogóle pomieścić w obszarze gry. W promieniu danego gracza umieszczane też są złoża aby mieć pewność że każdy z grających ma jakieś blisko siebie. Nie mniej jeśli pechowo trafi mogą one i tak być względnie daleko. Kolejno rozmieszczane są pozostałe „kropki” w losowych miejscach mapy. Na koniec ustawiane są ozdoby terenu z zachowaniem 2 sektorowego obramowania wokoło mapy – swego czasu zdarzało się że gracza wyrzucało w róg a dookoła tworzył się mur z przeszkód, co oczywiście uniemożliwiało rozstrzygnięcie partii. I gotowe.

Dla zainteresowanych, kompletny kod źródłowy odpowiedzialny za RMG (Delphi):

procedure RandomEFMapServerSide(const players: Byte; const theme: Byte; var fields: TEFMapServerSide);

function FindBuild(const x, y: Integer; const r: Single; const fields: TEFMapServerSide): Boolean;
var
i, u: Integer;
begin

Result := False;

for i := x - Ceil(r) to x + Ceil(r) do
for u := y - Ceil(r) to y + Ceil(r) do
  if ValidCoords(i, u) then
    if (Power(i - x, 2) + Power(u - y, 2) <= Power(r, 2)) and
       ((fields[i, u].owner <> 0) or (fields[i, u].build <> 0)) then
      begin
      Result := True;
      Break;
      end;

end;

const
start_fields: array[0..7, 0..2, 0..2] of Byte = ( // 0 - puste, 1 - gracz, 2 - ratusz, 3 - zloze
(
(0,1,0),
(1,2,1),
(0,1,0)
),
(
(0,1,0),
(0,2,0),
(0,1,0)
),
(
(0,0,0),
(1,2,1),
(0,0,0)
),
(
(0,0,0),
(0,2,0),
(0,0,0)
),
(
(1,1,1),
(1,2,1),
(1,1,1)
),
(
(0,0,0),
(0,2,1),
(0,1,1)
),
(
(1,1,0),
(1,2,1),
(0,1,1)
),
(
(1,1,1),
(1,2,1),
(0,0,0)
)
);

var
i, u: Integer;
x, y, r, p, m: Byte;
mp_startfield, mp_minecount, mp_minecountperplayer, mp_terraincount, mp_playerscount, mp_radius, mp_mineradius: Integer;
begin

// Generowanie parametrow
mp_startfield := Random(Length(start_fields));
mp_minecount := Random(3)+4;
mp_minecountperplayer := Ceil((Random(8+1)+12) / players);
mp_terraincount := Random(7) + Round((MaxPlayers-players+Random(4))*1.25);
mp_playerscount := players;
mp_radius := Min(MaxPlayers-players+4, 10);
mp_mineradius := Max(Round(6*(1-((players-2)/MaxPlayers))), 2);

// Czyszczenie mapy
for x := 0 to AreaWidth-1 do
for y := 0 to AreaHeight-1 do
  begin
  fields[x, y].owner := 0;
  fields[x, y].build := 0;
  fields[x, y].army := 0;
  fields[x, y].mine := 0;
  end;

// Ustawianie graczy
p := 0;
r := mp_radius;

while (mp_playerscount > 0) do
  begin
  // Losowanie srodka panstwa (3x3)
  x := Random(AreaWidth-2)+1;
  y := Random(AreaHeight-2)+1;

  if (fields[x, y].build = 0) and (not FindBuild(x, y, r, fields)) then
    begin

    for i := 0 to 2 do
    for u := 0 to 2 do
      begin
      if start_fields[mp_startfield, i, u] >= 1 then fields[u+x-1, i+y-1].owner := players-mp_playerscount+1;

      if start_fields[mp_startfield, i, u] = 2 then
        begin
        fields[u+x-1, i+y-1].build := 1;
        fields[u+x-1, i+y-1].army := Armors[BuildIDToAct(fields[u+x-1, i+y-1].build)];
        end
      else if start_fields[mp_startfield, i, u] = 3 then
        fields[u+x-1, i+y-1].mine := 1;
      end;

    Dec(mp_playerscount);
    p := 0;
    r := mp_radius;
    end;

  if p = 32 then
    begin
    p := 0;
    if r = 2 then Break else Dec(r);
    end
  else
    Inc(p);
  end;

// Ustawianie zloz wokol graczy
for x := 0 to AreaWidth-1 do
for y := 0 to AreaHeight-1 do
  if fields[x, y].build = 1 then
    begin
    m := mp_minecountperplayer;

    while m > 0 do
      begin
      i := Random(mp_mineradius*2+1)-mp_mineradius+x;
      u := Random(mp_mineradius*2+1)-mp_mineradius+y;

      if ValidCoords(i, u) then
        if (fields[i, u].build = 0) and (fields[i, u].mine = 0) then
          if ((not ValidCoords(i+1, u)) or (fields[i+1, u].mine = 0)) and
             ((not ValidCoords(i-1, u)) or (fields[i-1, u].mine = 0)) and
             ((not ValidCoords(i, u+1)) or (fields[i, u+1].mine = 0)) and
             ((not ValidCoords(i, u-1)) or (fields[i, u-1].mine = 0)) then
            begin
            fields[i, u].mine := 1;
            Dec(m);
            end;

      end;

    end;

// Ustawianie pozostalych zloz
while mp_minecount > 0 do
  begin
  x := Random(AreaWidth);
  y := Random(AreaHeight);

  if (fields[x, y].owner = 0) and (fields[x, y].build = 0) and (fields[x, y].mine = 0) then
    if ((not ValidCoords(x+1, y)) or (fields[x+1, y].mine = 0)) and
       ((not ValidCoords(x-1, y)) or (fields[x-1, y].mine = 0)) and
       ((not ValidCoords(x, y+1)) or (fields[x, y+1].mine = 0)) and
       ((not ValidCoords(x, y-1)) or (fields[x, y-1].mine = 0)) then
    begin
    fields[x, y].mine := 1;
    Dec(mp_minecount);
    end;
  end;

// Ustawianie ozdob terenu
while mp_terraincount > 0 do
  begin
  x := Random(AreaWidth-4)+2;
  y := Random(AreaHeight-4)+2;

  if (fields[x, y].owner = 0) and (fields[x, y].build = 0) and (fields[x, y].mine = 0) then
    begin
    fields[x, y].build := RMGThemes[theme, Random(RMGThemes[theme, 0])+1];
    Dec(mp_terraincount);
    end;
  end;

end;

Dodaj komentarz

imię*

e-mail* (nie publikowany)

strona www

Time limit is exhausted. Please reload CAPTCHA.