Un roguelike de consolă în C++

Un roguelike de consolă în C++

Introducere

„Linux nu este pentru jocuri!” – o afirmație învechită: acum există multe jocuri minunate create special pentru acest sistem grozav. Cu toate acestea, uneori, îți dorești ceva special, care să ți se potrivească… Așa că am decis să creez acest lucru special.

Baza

Nu voi arăta și explica tot codul (nu este foarte interesant) – doar elementele principale.

1. Personajul

Aici sunt enumerate toate parametrii personajului (sănătate, armură, experiență etc.) cei mai interesanți fiind desenarea și direcția de mișcare (care acum lipsește).

int x = 5, y = 5;
    hp = 100,
    maxhp = 100,
    dm    = 20,
    armor = 0,
    xp    = 0,
    level = 0,
    diff  = 10, // dificultate
    pos   = 0; // direcție

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

string color; // culoarea va fi folosită ca indicator al stării eroului

void hero() // aici se mișcă eroul la coordonatele (x ; y)
{
  cout << "e[u " << "e[0;0H"; // restabilirea poziției cursorului, ștergerea cu un spațiu
  for (int i = 0; i <= x; i++)
    cout << RIGHT;              // macro „e[1C”
  for (int i = 0; i <= y; i++)
    cout << DOWN;             // macro „e[1B”
  cout << "e[s" << color << "╬"; // salvarea poziției cursorului
}

2. Control

Cum să miști personajul e clar (x—++, y—++). Dar procesarea tastaturii este mai interesantă:

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

Rămâne doar să definim „simbolurile de control”. Se poate face cu un switch, dar eu îl urăsc.

switch(...) case .. : ... ; break mai bine așa

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

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

Frumos! Ciclicizăm funcțiile și ne plimbăm pe ecran! Dar parcă e un pic prea brusc… Și cursorul clipește, iar literele… Hai să reparăm!

//До цикла
  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! Un procent este gata!

3. Lumea înconjurătoare

Aici facem array-uri pentru x, y părți ale lumii și părțile în sine (char o[N]), la fel pentru monștri și bonusuri.

Creăm o funcție world(int objx[N] .... objy[N] ... obj[N], ... objcolor[N]) similar cu hero(), dar cu parametri și un ciclu suplimentar pentru a afișa array-ul… pentru interes, desenăm doar în câmpul de vedere (vis) (if (ox[k] < vis && oy[k]....))

Acum umplem ecranul cu bucăți din lume printr-un for simplu și creăm camere și coridoare, în același timp adăugând dușmani și obiecte, pentru o completă randomizare nu uităm de 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. Interacțiune

Acum trebuie să facem cumva să nu trecem prin pereți și monștri, să obținem bonusuri de la obiecte.

Iubitele noastre for și #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. Meniu

Meniul este afișat pe ecran, numerotând opțiunile, folosind getkey() pentru a procesa alegerile jucătorului. Scriem bara de stare a personajului, implementăm meniul de upgrade, scriem povestea de fundal și obținem ceea ce am numit „Subsoil” („Subsol”).

Concluzie

Așadar, o astfel de minune. Puteți să vă jucați cu el, descărcând, dezarhivând și executând astfel:

$ sudo chmod +x Subsoil-1.0/Subsoil

$ Subsoil-1.0/Subsoil

, sau, în cele din urmă, inspirându-vă, să scrieți o aventură pe gustul vostru. Vă avertizez dinainte: jocul meu nu este ușor!

Linkuri

Generație procedurală, Inspirație.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster