Luolalentely

Image
Monille teistä ovat epäilemättä tuttuja tietokone- ja videopelit. Yhtään monimutkaisemman pelin ollessa kyseessä pelin koodi menee äkkiä käsittämättömäksi kaikille, paitsi alaan vihkiytyneille. Voidaan kuitenkin pohtia tämän matematiikan kurssin algoritmiikan tasolla erästä pelityyppiä, joka oli omana aikanaan hyvin suosittu. Kyseessä olivat niin sanotut "luolalentelyt". Pelin idea on yksinkertainen: ohjaat avaruusalusta luolastossa. Tehtävänä on olla osumatta seiniin, ja pelistä tai pelityypistä riippuen tuhota vastustaja, tai selvitä sokkelosta hengissä. Tämäntyyppisen pelin suurinta antia näinä päivinä on epäilemättä se, että aloitteleva pelikoodaaja voi tehdä tälläisen pelin ilokseen ja harjoituksena yhtenä sunnuntaina, kunhan on opetellut pelikoodauksen perusjutut, kuten kuvaobjektien piirtämisen ruudulle. Jos pohdimme 2-ulotteisia pelejä (jotka siis tapahtuvat "litteässä maailmassa" kuvaruudun pinnalla), voimme tietenkin nähdä xy-koordinaatiston ja tietokoneen näytön keskenään samana asiana. Ajatellaan nyt pelin sankaria, pientä avaruusalusta, pisteenä ruudulla. Aluksesi lähtee liikkeelle origosta, keskeltä ruutua. Näemme näytöllä jotakin tämän kaltaista:
Image
Kirjoitetaan ensin peliohjelmasilmukka, timmimmältä nimeltään GameLoop. Peli siis pyörii yhden ainoan loputtoman ohjelmasilmukan pyörittämänä, kunnes käyttäjältä tulee käsky katkaista pelisilmukka. Voimme käyttää GameLoopin kirjoittamiseen tuikitavallista for-lausetta. Katsotaan silmukan rakennetta kohta tarkemmin. Määritellään nyt käytettävät muuttujat. Kutsutaan aluksen koortinaatteja yksinkertaisesti x ja y. Aluksen halutaan liikkuvan Newtonin lakien mukaisesti : alus liikkuu intertian viemänä, eikä pysähdy tilanteessa, jossa käyttäjä ei tee mitään. Aluksella on paikkansa lisäksi kulma, johon nokka osoittaa. Tämä kulma kannattaa määritellä niinkuin 2D-Vektorien kurssissa opittiin, eli mitattuna suhteessa positiiviseen x-akseliin, ja positiivinen kiertosuunta positiivisena lukuna. Jotta voimme toteuttaa inertiaan perustuvan ohjauksen, tarvitsemme vielä aluksen nopeutta merkitsevät muuttujat (x-suuntaan ja y-suuntaan). Meillä on nyt siis käytössämme muuttujat x y nopx nopy angle Näissä muuttujissa nopx ja nopy ovat inetriaan perustuvan ohjauksen muuttujat, nopeuden x-komponentti ja y-komponentti. Viimenen muuttuja "angle" on aluksen kulma. Mietitään kokeilumielessä silmukkaa, joka ei pyöritä mitään muuta kuin hiljalleen ylös liikkuvaa alusta. Määritellään muuttujat x=0 y=0 nopx=0 nopy=.01 angle=0 Nyt siis alus lähtee liikkeelle origosta, ja sillä on pieni y-suuntainen nopeus (ylöspäin) Toista_kunnes ( käyttäjä_painaa_esciä ) { x = x + nopx y = y + nopy Piirrä_alus(x,y,angle) } Tässä viimeinen käsky, "Piirä_alus", oletettavasti piirtää aluksen ruudulle, haluttuihin koortinaatteihin, ja haluttuun asentoon pyöritettynä. Jos siis muuttuja angle saa eri arvoja, alus piirretään osoittamaan siihen suuntaan. Jos siis angle=0, aluksen nokka osoittaa suoraan oikealle, jos taas angle=90, aluksen nokka osoittaa suoraan ylös, ja niin edelleen. Tämän loopin 2 ensimmäistä riviä pitävät sisällään inertiaohjauksen "salaisuuden". Pelaajan ohjauskäskyt eivät siis koskaan vaikuta x:ään ja y:hyn, ainoastaan muuttujiin {angle, nopx, nopy}. Katsotaan pelaajan antamia syötteitä seuraavana tarkemmin. Tässä vaiheessa huomataan siis se, että aluksella on koko ajan olemassa nopeusvektori (nopx,nopy). Tämä nopeusvektori muuttaa aluksen paikkaa (x,y). GameLoop pyörii ikuisesti, ja x:n ja y:n arvot muuttuvat jokaisella kierroksella riippuen siitä, mitkä nopeusmuuttujien arvot ovat. Katsotaan seuraavaksi, miten käyttäjän ohjauskäskyt kannattaa koodata vaikuttamaan aluksen nopeuteen ja kulmaan. Oletetaan, että käyttäjän antamista ohjauskäskyistä saadaan arvot seuraaville muuttujille {oikealle, vasemmalle, kiihdytys}. Tämä ovat siis ainoat syötteet, joita käyttäjä voi antaa. Halutaanko aluksen pyörivän oikealle (negatiiviseen kiertosuuntaan), halutaanko aluksen pyörivän vasemmalle (positiiviseen kiertosuuntaan), ja halutaanko aluksen kiihdyttävän. Nämä muuttujat saavat arvon 0 tai 1, riippuen tuleeko käyttäjältä kyseinen käsky vai ei. Jos siis käyttäjä ei tee mitään, näiden muuttujien arvot ovat oikealle=0 vasemmalle=0 kiihdytä=0 Käyttäjän syötteet sitten vaihtavat näitä tiloja ykköseksi näppäintä painamalla (tai muulla syötteellä). Syötteen katketessa tila palautuu nollaksi. Toista_kunnes ( käyttäjä_painaa_esciä ) { Poimitaan_käyttäjän_ohjauskäskyt() jos ( vasemmalle=1 ) { angle = angle +1 } jos ( oikealle=1 ) { angle = angle -1 } jos ( kiihdytä=1 ) { nopx = nopx + 0.01* cos ( angle ) nopy = nopy + 0.01* sin ( angle ) } x = x + nopx y = y + nopy Piirrä_alus(x,y,angle) } Käyttäjän käskyt {oikealle, vasemmalle} muuttavat siis muuttujan "angle" arvoa, eivät mitään muuta. Jos käyttäjä painelisi vain oikealle ja vasemalle, alus pyörisi akselinsa ympäri, eikä tekisi mitään muuta. Mutta jos käyttäjä antaa "kiihdytä"-käskyn, niin silloin nopeusvektorin {nopx, nopy} arvot muuttuvat. Nopeutta tulee lisää siihen suuntaan, johon nokka näyttää, ikäänkuin aluksen perässä olisivat jonkinnäköiset työntävää voimaa tuottavat raketi. Tämän pelisilmukan sisälle voitaisiin sitten alkaa kehitellä muita pelin elementtejä, mutta tämä esimerkki esittelee tapauksen, missä algoritmiikalla voidaan todellakin tehdä jotakin mielenkiintoista ja hyödyllistä. Tämänkaltaisten esimerkkien koodaamisesta alkaa jokaisen pelikoodaajan uratarina.