Roguelike-opas:Taistelujärjestelmä ja kuolema
| Roguelike-oppaan sisältö |
|---|
|
Taistelujärjestelmä on hyvin yksinkertaistettu malli taistelutilanteesta. Tässä oppaassa pelaaja voi lyödä, kun on vihollisen vieressä ja samaten vihollinen voi lyödä pelaajaa jos tämä on vieressä. Kun vihollinen kuolee, tuhotaan sen tiedot muistista ja annetaan siitä piste pelaajalle. Jos pelaaja kuolee, poistutaan pelistä.
Pelaaja voi lyödä vihollisia ja nämä voivat myöskin lyödä pelaajaa. Mutta pelaaja tarvitsee voiman, jolla se lyö. Main-funktion alkuun voidaan kirjoittaa vaikkapa seuraavanlaiset rivit:
peli.pelaaja.voima = 5; peli.pelaaja.energia = 100;
Lisää myös PELI-struktuuriin seuraavanlainen rivi:
int pisteet;
Ensimmäinen rivi määrittelee pelaajan maksimivoiman ja toinen rivi pelaajan energiamäärän. Jos energiat on nolla tai alle, kuolee pelaaja.
Kuinka luoda tilanne, jossa pelaaja lyö vihollista?
Main-funktion sisällä olevassa silmukassa on lohko, jonka ehtona on, että onko edessä este (este-funktio). Muokataan sitä hieman seuraavanlaiseksi:
if (!este(peli.pelaaja.x + x, peli.pelaaja.y + y)) { peli.pelaaja.x += x; peli.pelaaja.y += y; } else { //Edessä on este. Tarkistetaan, että onko se vihollinen. jos vihollis_id saa luvuksi jonkin muun kuin -1, tässä on }
Seuraavaksi tarvitsemme muutaman funktion.
Else-lohkon tarkoitus on, että siinä kohtaa on este, josta ei pääse yli. Nyt tarkistetaan, että onko siinä vihollista, jonka vuoksi tarvitaan seuraavanlainen apufunktio, mikä kirjoitetaan ennen main-funktiota:
//palauttaa arvoksi vihollisen id-numeron sen perusteella, onko se kyseisessä koordinaatissa. Muussa tapauksessa palauttaa -1. int ota_vihulainen_tasta(int x, int y) { for (int i = 0; i < (int)peli.vihollinen.size(); i++) { if (peli.vihollinen[i].x == x && peli.vihollinen[i].y == y) return i; } return -1; }
Ja else-lohkon sisälle tehdään seuraavanlainenr rivi:
int vihollis_id = ota_vihulainen_tasta(peli.pelaaja.x+x, peli.pelaaja.y+y);
Jos vihollis_id-muuttujan arvo on -1, tässä ei ole vihollista. Muussa tapauksessa se sisältää tässä kohtaa olevan vihollisen id:n johon osoitetaan seuraavalla funktiolla:
if (vihollis_id >= 0) //lyödään vihollista, kun se kerta on vieressä. lyo_vihollista(vihollis_id);
Ennen kuin koodi käännetään toimivaksi, tarvitaan tietysti lyo_vihollista-funktio, joka voi olla seuraavanlainen:
//id on saatu vihollisen id. void lyo_vihollista(int id) { //rakennetaan lyöntivoima, mikä on pelaajan voima jaettuna kahdella ja siihen lisätään luku väliltä 0...pelaajan maksimivoima. int maara = (peli.pelaaja.voima / 2) + rand() % peli.pelaaja.voima; peli.vihollinen[id].energia -= maara; //vähennetään viholliselta määrän verran energiaa if (peli.vihollinen[id].energia <= 0) //energiaa on 0 tai vähemmän. { int x = peli.vihollinen[id].x; int y = peli.vihollinen[id].y; peli.kartta.vari[x][y] = punainen; //muutetaan tähän pieni läntti peli.kartta.merkki[x][y] = '#'; peli.vihollinen.erase(peli.vihollinen.begin()+id); //tuhotaan vihollinen vektorilistasta peli.pisteet++; //lisätään piste pelaajalle. Muistithan lisätä tämän peli-struktuuriin? mvprintw(2, 2, "Otus kuoli!"); //ilmoitetaan ruudulla tästä } else mvprintw(2, 2, "Osuma vihuun!"); //ilmoitetaan että osuttiin mörköön. getch(); //odotetaan yhtä näppäinpainallusta }
Nyt pelaaja voi tuhota vihollisia. Vielä tarvitaan kaksi olennaista funktiota:
- siirry_seuraavaan_kenttaan()
- lyo_pelaajaa
Siirry_seuraavaan_kenttaan on apufunktio, jolla luodaan kenttä uudestaan, kun kaikki viholliset ovat kuolleet. Se alustaa kartan ja viholliset ja rakentaa kaiken uusiksi hieman erilaisena.
Itse funktio voi näyttää tältä:
void siirry_seuraavaan_kenttaan() { erase(); //tyhjennetään tekstit pois attron(COLOR_PAIR(vihrea)|A_BOLD); mvprintw(2,2, "Siirryt seuraavaan kylaan!"); //tulostetaan teksti attroff(COLOR_PAIR(vihrea)|A_BOLD); getch(); //odotetaan näppäinpainallusta luo_kartta(); //luodaan kartta luo_olentoja(2 + rand() % 20); peli.pisteet += 4; //annetaan vielä ekstrapisteistä peli.pelaaja.x = 1; peli.pelaaja.y = 12; }
Ja sitä kutsutaan lyo_vihollista-funktiosta, ehdon sisältä: Lisää funktion loppuun tarkistus, että onko vihollisia enää kartassa. Jos ei ole, siirrytään seuraavaan kenttään:
if (peli.vihollinen.size() == 0) siirry_seuraavaan_kenttaan();
Vielä pitää tehdä, että vihollinen voi lyödä myös pelaajaa. Tätä varten kannattaa tosin tehdä valmiiksi myös palkki, mikä näyttää pelaajan energian.
Lisää esimerkiksi kentän piirtoon tai main-funktion silmukan loppuun seuraavanlainen rivi:
mvprintw(0, 0, "Energiaa: %i", peli.pelaaja.energia);
Jotta voidaan lyödä pelaajaa, on luotava aluksi funktio, joka tarkistaa onko pelaaja vieressä. Tätä varten voi tehdä vastaavanlaisen:
//tarkistetaan, että onko pelaaja vieressä bool vieressa_pelaaja(int x, int y) { for (int xx = x - 1; xx <= x + 1; xx++) { for (int yy = y - 1; yy <= y + 1; yy++) { if (peli.pelaaja.x == xx && peli.pelaaja.y == yy) return true; } } return false; }
Nyt hypätään takaisin vihollisten liikuttamisfunktioon ja etsitään kohta:
if (!este(px, py)) { peli.vihollinen[i].x = px; peli.vihollinen[i].y = py; }
Kirjoitetaan sen yläpuolelle seuraava:
//pelaaja on vieressä, jotenka voidaan koittaa lyödä sitä. if (vieressa_pelaaja(peli.vihollinen[i].x, peli.vihollinen[i].y)) { mvprintw(2 , 2, "ouh!"); getch(); }
Nyt aina kun vihollinen on vieressä, se lyö pelaajaa. Tämä ei tosin tee vielä vahinkoa pelaajalle, vaan ainoastaan tulostaa ruudulle "ouh!"-tekstin ja odottaa yhtä näppäinpainallusta.
Ehdon sisällön voi korvata tämmöisellä koodilla:
mvprintw(2 , 2, "ouh!"); peli.pelaaja.energia -= rand() % 3; getch(); if (peli.pelaaja.energia <= 0) //energiaa ei ole enää tai se on negatiivisen puolella, jotenka palautetaan arvoksi -1. return -1; //-1 kertoo, että pelaaja kuoli. Tämä tieto kuljetetaan aina pelisilmukan alkuun, ja siellä jos on -1, lopetetaan itse peli.
Nyt kun pelaajan energia on nolla tai alle, main-funktion while-silmukka on saanut käskyn loppua, jotenka päädytään ohjelman loppuun.