Paranna Morpion-pelin kansainvälisiä ennätyksiä!
Ohjeet | Nettipeli | Tuloslista
Suunnittele tiedosto, josta tulee suuri ZIP-paketti!
Vastauksia: 32
Paras: 1158
Millä tavalla aiemmissa keskusteluissa esitetyn formin sijoittaminen tuohon linkin paikalle tuottaa ongelmia? (Nettisivut ja -ohjelmointi) lisää...
Oppaat: Peliohjelmointi C++:lla: matopeli
Kirjoittaja: Metabolix
Edellinen opas – Seuraava opas
Tulostettava versio: tämä opas | koko opassarja
Osa 3 - Pelin raakaversio
Pääfunktion sisältö – Pelin nopeus – Ajan mittaaminen ja odottaminen – Pelin data – Pelin kiinteät asiat – Pelitilanteen piirtäminen – Toiminnalliset funktiot – Madon muokkaaminen – Pääfunktion toteutus – Esimerkkipelin tilanne
| Perusfunktioiden jälkeen päästään käsiksi itse peliin. Tarvittavat toiminnot tunnetaan jo: mato luodaan, se liikkuu, törmää seiniin ja itseensä, syö omenoita ja kasvaa. Tehdään jokaiselle toiminnolle oma funktio, jotta saadaan kirjoitettua pelin rakenne koodin muotoon. Funktioiden ei tarvitse alussa toimia: seuraava vaihe on toteuttaa funktiot loogisessa järjestyksessä niin, että välituloksia voi helposti testata.
Pääfunktion sisältö Kun valikosta siirrytään pelitilaan, täytyy ensiksi alustaa pelin muuttujat alkutilanteen mukaan. Koska matopelissä ei ole erilaisia pelikenttiä, ei tarvitse kuin luoda mato ja ensimmäinen omena. Tämän jälkeen suoritetaan silmukassa pelin perustoimintoja: luetaan käyttäjän syötteet, liikutetaan matoa, tehdään törmäystarkistukset ja piirretään tilanne. Kun peli päättyy, lopetetaan silmukka, tuhotaan mato ja omena ja palataan valikkoon. Tämä kaikki sijoitetaan funktioon peli::aja, joka toteutetaan tämän oppaan lopussa.
Pelin nopeus Pelin pitäisi toimia yhtä nopeasti kaikilla tietokoneilla, vaikka uudet tietokoneet ovat paljon tehokkaampia kuin vanhat. Tämän takia pelissä täytyy mitata aikaa, jotta mato liikkuisi aina samalla nopeudella. Kone voi olla joko liian nopea tai liian hidas. Liika nopeus on helppo korjata: ohjelma voi välillä odottaa hieman, jotta peli toimisi hitaammin. Liika hitaus vaatii paremman ratkaisun. Pienissä peleissä eniten aikaa kuluu yleensä piirtämiseen, joten ongelma ratkeaa, kun jätetään osa tilanteista piirtämättä. Esimerkkipelissä matoa liikutetaan 50 kertaa sekunnissa eli 0,02 sekunnin aika-askeleella. Jos ei ole vielä seuraavan liikutuskerran aika, ohjelma voi vaikka odottaa hetken, ja jos taas kone on niin hidas, että aikaa on ehtinyt kulua enemmänkin, voidaan matoa liikuttaa monta kertaa, ennen kuin tilanne piirretään uudestaan. Käytännössä säilytetään tietoa pelin kellosta ja todellisesta kellosta. Jos pelin kello edistää, ohjelman täytyy odotella hieman, ja jos taas pelin kello jätättää, täytyy kiriä oikea aika kiinni piirtokertojen välissä. Jos kone ei pysty suorittamaan laskuja tarpeeksi nopeasti, täytyy ehkä laskea tarkkuutta eli pidentää aika-askelta: matoa voitaisiin liikuttaa vaikka kymmenen kertaa sekunnissa hieman pitemmin loikkauksin, jolloin koneella olisi vähemmän laskettavaa. Samalla pelistä kuitenkin tulisi nykivä, ja liian pitkillä loikkauksilla esimerkiksi törmäykset voisivat jäädä huomaamatta: mato voisi vahingossa hypätä kokonaan omenan yli. Ajan mittaaminen ja odottaminen Esimerkkipelissä aikaa voidaan mitata SDL:n funktiolla SDL_GetTicks, joka kertoo ohjelman alusta kuluneen ajan millisekunteina, ja odottamista varten on funktio SDL_Delay. Tehdään molemmille toiminnoille vielä omat funktiot.
Ennen funktioiden kirjoittamista täytyy tehdä jonkinlaiset rakenteet, joihin pelin data tallennetaan. Matopelissä on kolme osaa: mato, omena ja pelialue. Tehdään siis jokaiselle näistä oma rakenne. Pelialue sisältää nyt vain kulmien koordinaatit. Omenallekin riittää yksinkertaisesti sijainti. Madolla on oltava kulkusuunta ja sijainti. Madon sijainti on mutkikas asia, koska mato voi olla mutkalla. Yksi mahdollisuus on ilmoittaa jokaisen madon jaokkeen ("pallon") sijainti erikseen. Madon edetessä taaemmat jaokkeet siirtyvät edempien paikalle ja etupää täysin uuteen paikkaan. Jotta madon saisi liikkumaan sulavasti, joka jaokkeelle tarvitaan kaksi sijaintia: kiinteä tukisijainti, jonka mukaan madon mutkat ja eteneminen toimivat, ja joustavampi sijainti, jota päivitetään sulavasti seuraavaa jaoketta kohti, kunnes on aika siirtää kaikkia jaokkeita eteenpäin. Syy on täysin matemaattinen, ja ongelman voi helposti nähdä, jos tekeekin pelin toisin. Seuraavassa kuvassa kaksi matoa on kulkenut samaa ympyrää. Sininen (ulompi) mato toimii oikein, mutta punainen (sisempi) on kiertynyt häntäpäästään kerälle, koska jaokkeet ovat liikkuneet aina suoraan seuraavaa jaoketta kohti ilman tukisijaintia.
Mato sisältää useita jaokkeita, eikä määrällä ei ole ennalta tunnettua ylärajaa. Yksi hyvä tietorakenne jaokkeiden säilyttämiseen on linkitetty lista, jossa peräkkäiset jaokkeet sisältävät linkit eli osoittimet toisiinsa. Uusia jaokkeita voidaan varata dynaamisesti new-operaattorilla, ja ne on helppo liittää listaan vain asettamalla linkit oikein, kuten myöhemmin matoja käsittelevissä funktioissa tehdään. Listan läpikäynti on helppoa: siirrytään aina seuraavaan jaokkeeseen, kunnes linkki on tyhjä. Ensimmäisen ja viimeisen jaokkeen osoittimet tallennetaan varsinaiseen matorakenteeseen.
Matopelissä on monta asiaa, jotka säilyvät läpi pelin mutta joita on hyvä pystyä kehitysvaiheessa muokkaamaan: toiminnan aika-askel, pelialueen koko, madon jaokkeen koko, omenan koko sekä madon nopeus ja käännösnopeus. Ne on selkeintä sijoittaa muuttujiin tai vakioihin, jotta niitä voi helposti muuttaa testatessa ja jotta koodissa on epämääräisten lukujen sijaan selkeitä nimiä, joista nähdään heti, mistä on kyse. Tässä vaiheessa voidaan määrätä toiminnan aika-askel ja pelialueen koko. Alue on mitoitettu niin, että se mahtuu mukavasti 640x480-kokoiseen ikkunaan, kun yksikkö on 32x32 pikseliä kooltaan.
Rakenteiden perusteella voidaankin jo toteuttaa funktio pelitilanteen piirtämiseen. Kuten suunnitelmaan kuului, piirretään ensin tausta ja pelialueen reunat, sitten mato ja lopuksi omena. Funktiossa tehdään joitakin laskelmia, jotta pelialue saataisiin koostaan riippumatta ruudun keskelle. Tällä kertaa oletetaan, että koko alue näkyy kerralla, mutta hyvin samantapaisilla laskelmilla saataisiin tehtyä myös laajempi maailma, josta piirrettäisiin aina oikea alue pelihahmon ympäriltä. Piirtelyn yhteydessä nähdään, kuinka madon linkitetty lista käydään läpi for-silmukalla: aloitetaan madon häntäjaokkeesta, siirrytään aina nenää kohti ja lopetetaan, kun on päädytty tyhjään osoittimeen.
Jokaiselle pelin toiminnolle on selkeintä tehdä oma funktio. Matopelin toimintoja ovat madon luominen, kasvattaminen ja lopussa tuhoaminen, törmäysten tarkistaminen, omenan luonti ja syönti sekä madon liikkuminen.
Peli vaatii testaamista varten madon. Nyt on sopiva aika kirjoittaa funktiot sen luomiseen, pidentämiseen ja tuhoamiseen. Kun mato luodaan, sille täytyy luoda ainakin yksi jaoke, johon nenä- ja häntäosoittimet voivat osoittaa. Tämän jälkeen matoa on helppo pidentää funktiolla, joka lisää jaokkeita. Tuhottaessa täytyy aina siirtyä askel eteen ja sen jälkeen tuhota edellinen jaoke, kunnes jäljellä on enää yksi. Uuden jaokkeen voisi lisätä madon kumpaan tahansa päähän. Nyt se lisätään etupäähän, koska näin omenoiden syöminen toimii hauskemmin: uusi jaoke tulee omenan kohdalle, jolloin syöntikohdassa on välissä ylimääräinen jaoke, kunnes madon häntä pääsee paikalle ja mato pitenee. Jos jaoke lisättäisiin takapäähän, mato pitenisi heti.
Lopultakin on pelin pääfunktion aika! Aiemmin käytiin jo rakenne läpi: alustus, silmukka, lopetus. Matopelin pääfunktio sisältää helppolukuisessa muodossa – funktiokutsuina – selostuksen koko pelin toiminnasta. Alustusten jälkeen käynnistyy pelisilmukka, ja pelin loputtua jäädään vielä odottamaan yhtä näppäimenpainallusta, jotta pelaaja ehtii rauhassa katsella, mikä meni pieleen. Lopussa palautetaan saavutettu pistemäärä ja ohjelma päätyy takaisin valikkoon.
Esimerkkipelin tilanne (Lataa koodipaketti!) Tässä vaiheessa peli voisi näyttää tältä:
Madon luova funktio tuottaa kolmen pallon madon, mutta kuvassa näkyy vain yksi pallo, koska kaikki kolme ovat samassa kohti. Onneksi tämä esteettinen virhe korjataan opassarjan seuraavassa osassa. Koska mato ei liiku eikä törmää, pelissä ei voi hävitä. Peli kuitenkin päättyy Esc-näppäimestä. Lauri Kenttä, 7.11.2009 |
Edellinen opas – Seuraava opas
ylläpito Antti Laaksonen, ulkoasu Otto Seiskari