Konsolengame-Roguelike auf C++

Konsolengame-Roguelike auf C++

Einführung

„Linux ist nicht für Spiele!“ – eine veraltete Aussage: Heute gibt es viele großartige Spiele, die speziell für dieses wunderbare System entwickelt wurden. Manchmal möchte man jedoch etwas Besonderes, das genau zu dir passt… Und ich habe beschlossen, dieses Besondere zu schaffen.

Grundlage

Ich werde nicht den gesamten Code zeigen und erklären (das ist nicht sehr interessant) – nur die wichtigsten Punkte.

1. Charakter

Hier sind alle Parameter des Charakters aufgeführt (Gesundheit, Rüstung, Erfahrung etc.), interessant sind die Darstellung und die Bewegungsrichtung (die es derzeit nicht gibt).

int x = 5, y = 5;
    hp = 100,
    maxhp = 100,
    dm    = 20,
    armor = 0,
    xp    = 0,
    level = 0,
    diff  = 10, // Schwierigkeitsgrad
    pos   = 0; // Richtung

bool reg = 0,
       Mdm = 0, // Boni
       ght = 0;

string color; // Die Farbe wird als Zustand des Helden verwendet

void hero() // Hier erfolgt die Bewegung des Helden zu den Koordinaten (x ; y)
{
  cout << "e[u " << "e[0;0H"; // Wiederherstellung der Cursorposition, Überschreibung mit Leerzeichen
  for (int i = 0; i <= x; i++)
    cout << RIGHT;              // Makro "e[1C"
  for (int i = 0; i <= y; i++)
    cout << DOWN;             // Makro "e[1B"
  cout << "e[s" << color << "╬"; // Speicherung der Cursorposition
}

2. Steuerung

Wie man den Charakter bewegt, ist klar (x—++, y—++). Aber die Verarbeitung der Tastatureingaben ist interessanter:

char key;
char getkey()
{
  system("stty raw");
  key = getchar();
  system("stty cooked");
  return key;
}

Jetzt müssen nur noch die „Steuerungssymbole“ festgelegt werden. Man könnte das mit einem switch machen, aber ich hasse das.

switch(...) case .. : ... ; break Besser so

#define KEY if (key ==
#define I ){
#define J ;}else

void keys()
{
  getkey();
    KEY 'a' I x-- ; pos = 1 J
    KEY......
}

Schönheit! Wir zirkeln Funktionen und laufen über den Bildschirm! Aber es ist irgendwie ruckelig… Der Cursor zuckt und die Buchstaben… Das werden wir beheben!

//До цикла
  cout << "e[?25l"; //отключаем отображение курсора
  system("stty -echo"); //отключаем эхо-ввод
  system("xset r rate 120 10"); // изменяем задержку на более плавную
//После цикла
//-------Return_normal_system_settings--------
  cout << "e[00m";
  system("reset");
  system("xset r rate 200 20");

Uff! Ein Prozent ist fertig!

3. Die Umgebung

Hier erstellen wir Arrays für x, y von Stückchen der Welt und die Stücke selbst (char o[N]), das Gleiche für Monster und Boni.

Wir erstellen eine Funktion world(int objx[N] .... objy[N] ... obj[N], ... objcolor[N]) analog zu hero(), aber mit Parametern und einer zusätzlichen Schleife für die Ausgabe des Arrays… zur Abwechslung zeichnen wir nur im Sichtfeld (vis) (if (ox[k] < vis && oy[k]....))

Jetzt füllen wir den Bildschirm mit Teilen der Welt durch eine einfache for-Schleife und erstellen prozedural Räume und Durchgänge, und fügen gleichzeitig Feinde und Objekte hinzu, für die volle Zufälligkeit vergessen wir nicht srand(time(NULL));

//------------------GENERATION---------------
void rooms()
{
  for (int i = 0; i <= 50; i++)
  {
    px[i] = rand() % 115 + 2;
    py[i] = rand() % 34 + 2;
    pl[i] = rand() % 5 + 5;
    ph[i] = rand() % 5 +  5;

    if (px[i] + pl[i] > 117) px[i] = 50 - pl[i] / 2; else
    if (px[i] < 2)           px[i] = 50 - pl[i] / 2; else
    if (py[i] < 1)           py[i] = 15 - ph[i] / 2; else
    if (py[i] + ph[i] > 37)  py[i] = 15 - ph[i] / 2;

    for (int j = 0; j <= i; j++)
    {
      while (px[i] > px[j] && px[i] < px[j] + pl[j])
        (px[i]+pl[i]/2 >= 55) ? px[i]++ : px[i]-- ;

      while (py[i] > py[j] && py[i] < py[j] + ph[j])
        (py[i]+ph[i]/2 >= 18) ? py[i]++ : py[i]-- ;

      while (px[i]+pl[i] > px[j] && px[i]+pl[i] < px[j] + pl[j])
        (px[i]+pl[i]/2 >= 55) ? px[i]++ : px[i]-- ;

      while (py[i]+ph[i] > py[j] && py[i]+ph[i] < py[j] + ph[j])
        (py[i]+ph[i]/2 >= 18) ? py[i]++ : py[i]-- ;
    }

    for (int j = 0; j <= i; j++)
    {
      while (px[j] + pl[j] >= 116) px[j]-- ;
      while (px[j] < 2)            px[j]++ ;
      while (py[j] < 1)            py[j]++ ;
      while (py[j] + ph[j] >= 37)  py[j]-- ;
    }
    tx[i] = px[i]+10; ty[i] = py[i]-3;

    if (i <= diff)
    {
      ex[i]  = px[i];
      ey[i]  = py[i];
      while (ex[i] < 10){ ex[i]++ ; epos[i] = 3 ;}
      while (ey[i] < 10){ ey[i]++ ; epos[i] = 1 ;}
      e[i]   = evar[pl[i]];
      ecolor[i] = "e[00me[31m";

      edm[i] = edmvar[pl[i]];
      ehp[i] = ehpvar[pl[i]];
      exp[i] = expvar[pl[i]];
    }
    rect(px[i], py[i], pl[i], ph[i]);
  }
}

void corrs()
{
  int pc, px, py;
  for (int i = 0; i <= 4; i++)
  {
    if (i < 2){
      px = 3;
      py = rand() % 33 + 3;
      pc = 110;
      line(px, py, pc, true);
      line(px, py+1, pc, true);
    } else {
      px = rand() % 100 + 3;
      py = 3;
      pc = 33;
      line(px, py, pc, false);
      line(px+1, py, pc, false);
    }
  }
}

4. Interaktion

Jetzt müssen wir irgendwie verhindern, dass wir durch Wände und Monster hindurchgehen und Boni von Objekten erhalten.

Unsere geliebten for und #define

#define TOUCH if (x == ox[i] && y == oy[i] && pos ==
#define HIT   x == ex[i] && y == ey[i] && pos ==
 for (int i = 0; i <= n; i++)
  {
    if (i <= diff)
    {
     if (Mdm) ehp[i]-=2 ; // если бонус "массовый урон" включен
     epos[i] = 0;

     if (ex[i] < x+5 && ex[i] > x-5 &&
         ey[i] < y+5 && ey[i] > y-5  )
     {
       edel(i); // функция переписывающая предыдущее положение противника
       if (ex[i] < x I ex[i]++ ; epos[i] = 1 J
       if (ex[i] > x I ex[i]-- ; epos[i] = 2 J
       if (ey[i] < y I ey[i]++ ; epos[i] = 3 J
       if (ey[i] > y I ey[i]-- ; epos[i] = 4 ;}
     }
   for (int j = 0; j <= n; j++) // столкновение моба со стенками
       while (ex[i] == ox[j] && ey[i] == oy[j] || ex[i] == ex[j] && ey[i] == ey[j] && j != i)
       {
         if (epos[i] == 1) ex[i]-- ; else
         if (epos[i] == 2) ex[i]++ ; else
         if (epos[i] == 3) ey[i]-- ; else
         if (epos[i] == 4) ey[i]++ ;
       }

     if (x == ex[i] && y == ey[i]) //  "битва"
      {
       if (ehp[i] > 1)
       {
         ehp[i] -= dm;
         (edm[i] < armor) ?
         hp -= 0 :
         hp -= edm[i]-armor;
       } else {
         ex[i] = ey[i] = -1;
         xp += exp[i];
         ehp[i] = 12;
       }
     }
     if (!ght) // если не призрак проверять столкновение игрока с врагами
     {
       if (HIT 1) y++ ;else
       if (HIT 2) x-- ;else
       if (HIT 3) y-- ;else
       if (HIT 4) x++ ;
     }
    }
    if (!ght) // то же, но со стенами
    {
      TOUCH 1 I y++ J
      TOUCH 2 I x-- J
      TOUCH 3 I y-- J
      TOUCH 4 ) x++ ;
    }
  }

5. Menü

Das Menü wird einfach auf dem Bildschirm angezeigt, die Punkte werden nummeriert, und mit getkey() verarbeiten wir die Wahl des Spielers. Wir schreiben die Statusleiste des Charakters, implementieren das Auflevel-Menü, schreiben die Hintergrundgeschichte und erhalten das, was ich «Subsoil» genannt habe.

Fazit

So etwas. Sie können es spielen, indem Sie es herunterladen, entpacken und wie folgt starten:

$ sudo chmod +x Subsoil-1.0/Subsoil

$ Subsoil-1.0/Subsoil

, oder schließlich, inspiriert, ein Abenteuer nach Ihrem Geschmack schreiben. Ich warne Sie im Voraus: Mein Spiel ist nicht leicht!

Links

Prozedurale Generation, Inspiration.

Quelle: habr.com

60GB SSD 8Gb DDR4