Konsolroguelike på C++

Konsolroguelike på C++

Introduktion

"Linux är inte för spel!" — en föråldrad fras: nu finns det många fantastiska spel speciellt för detta underbara system. Men ibland vill man ha något särskilt som passar just en själv... Och jag bestämde mig för att skapa detta speciella.

Grunden

Jag tänker inte visa och berätta hela koden (det är inte så intressant) — bara de viktigaste punkterna.

1. Karaktär

Här listas alla karaktärens parametrar (hälsa, rustning, erfarenhet osv.) det intressanta är ritningen och rörelseriktningen (som ännu inte finns).

int x = 5, y = 5;
    hp = 100,
    maxhp = 100,
    dm    = 20,
    armor = 0,
    xp    = 0,
    level = 0,
    diff  = 10, // svårighetsgrad
    pos   = 0; // riktning

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

string color; // färgen kommer att användas som en indikator på hjälten tillstånd

void hero() // här sker hjälten rörelse till koordinater (x ; y)
{
  cout << "e[u " << "e[0;0H"; // återställ kursorns position, rensa med ett utrymme
  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 << "╬"; // spara kursorns position
}

2. Styrning

Hur man flyttar karaktären är uppenbart (x—++, y—++). Men hanteringen av tangentbordet är mer intressant:

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

Det återstår bara att definiera "kontrollsymbolerna". Man kan göra det med hjälp av switch, men jag hatar det.

switch(...) case .. : ... ; break bättre på det här sättet

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

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

Vackert! Vi cyklar funktioner och springer runt på skärmen! Men det är lite för hastigt... både kursorn blinkar och bokstäverna... Vi fixar 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 procent klar!

3. Omvärlden

Här gör vi arrayer för x, y bitar av världen och själva bitarna (char o[N]), samma för monster och bonusar.

Vi skapar en funktion world(int objx[N] .... objy[N] ... obj[N], ... objcolor[N]) i analogi med hero(), men med parametrar och en extra loop för att visa arrayen… vi ritar bara i synfältet (vis) (if (ox[k] < vis && oy[k]....))

Nu fyller vi skärmen med delar av världen med hjälp av en enkel for-loop och skapar rum och gångar procedurmässigt, samtidigt som vi lägger till fiender och föremål, för fullständig slumpmässighet glömmer vi inte bort 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

Nu behöver vi på något sätt undvika att gå igenom väggar och monster, få bonusar från föremål.

Våra älskade for-loopar och #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

Menyn visas enkelt på skärmen, vi numrerar punkterna och hanterar spelarens val med hjälp av getkey(). Vi skriver en statusrad för karaktären, implementerar en uppgraderingsmeny, skriver en bakgrundshistoria och får vad jag kallar «Subsoil».

Slutsats

Detta är något. Du kan spela det genom att ladda ner, packa upp det och köra det på följande sätt:

$ sudo chmod +x Subsoil-1.0/Subsoil

$ Subsoil-1.0/Subsoil

, eller kanske, inspirerad, skriva ett äventyr efter eget tycke. Jag varnar i förväg: mitt spel är inte lätt!

Länkar

Procedural generering, Inspirator.

Källa: habr.com

Köp pålitlig webbhotell med DDoS-skydd, VPS VDS-servrar 🔥 Köp pålitlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster