Konsollroguelike på C++

Konsollroguelike på C++

Innledning

«Linux er ikke for spill!» — en foreldet frase: Nå finnes det mange fantastiske spill laget spesielt for dette fantastiske systemet. Men noen ganger ønsker man noe spesielt som passer akkurat deg… Så jeg bestemte meg for å lage det spesielle.

Grunnlag

Jeg vil ikke vise og forklare hele koden (det er ikke så interessant) — bare de viktigste punktene.

1. Karakter

Her er alle parametrene for karakteren listet opp (helse, rustning, erfaring osv.). Det som er interessant er tegning og bevegelsesretningen (som ikke finnes nå).

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

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

string color; // fargen vil bli brukt som en indikasjon på helsetilstanden til helten

void hero() // her skjer helten flytting til koordinatene (x; y)
{
  cout << "e[u " << "e[0;0H"; // gjenopprette markørposisjonen, slette med mellomrom
  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 << "╬"; // lagre markørposisjonen
}

2. Kontroll

Hvordan flytte karakteren er klart (x—++, y—++). Men behandling av tastaturet er mer interessant:

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

Det gjenstår bare å angi «kontrolltegnene». Man kan gjøre dette med switch, men jeg hater det.

switch(...) case .. : ... ; break bedre slik

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

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

Fantastisk! Vi setter funksjoner i en loop og løper rundt på skjermen! Men det føles litt brått… Og markøren blinker, og bokstavene… La oss fikse det!

//До цикла
  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! En prosent er ferdig!

3. Omgivelsene

Her lager vi arrayer for x, y biter av verden og selve bitene. (char o[N]), det samme for monstre og bonuser.

Vi lager en funksjon world(int objx[N] .... objy[N] ... obj[N], ... objcolor[N]) etter lignende mønster som hero(), men med parametere og en ekstra loop for å skrive ut arrayet… for moro skyld tegner vi bare i synsfeltet (vis) (if (ox[k] < vis && oy[k]....))

Nå fyller vi skjermen med biter av verden ved hjelp av en enkel for-løkke og prosessuelt lager vi rom og passasjer, i tillegg husker vi på fiender og gjenstander for å oppnå fullstendig tilfeldighet. 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. Interaksjon

Nå må vi finne en måte å ikke gå gjennom vegger og monstre, samt motta bonuser fra gjenstander.

Våre favoritter for og #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. Meny

Menyen vises enkelt på skjermen, vi nummererer punktene, og behandler spillerens valg med getkey(). Vi skriver ut statuslinjen til karakteren, implementerer oppgraderingsmenyen, skriver bakgrunnshistorie, og vi får det jeg har kalt «Subsoil».

Konklusjon

Slik er det. Du kan spille det, ved å laste ned, pakke ut og starte det slik:

$ sudo chmod +x Subsoil-1.0/Subsoil

$ Subsoil-1.0/Subsoil

, eller, hvis du blir inspirert, skrive et eventyr som passer dine ønsker. Jeg advarer på forhånd: spillet mitt er ikke lett!

Lenker

Prosedyrisk generering, Inspirasjonskilde.

Kilde: habr.com

Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere 🔥 Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere | ProHoster