Softwareproject
JAMK / Olio ohjelmointi 2 lopputyö.
1. Projektin kuvaus
Päätimme tehdä Olio-2 projektiksi pienimuotoisen pelin, jossa olisi tarkoitus selviytyä laavakentällä mahdollisimman kauan.
Laava lähtee leviämään kentän laidoilta, ja pelaaja pystyy vesipyssyllä muuttamaan laavatiilejä takaisin kivitiiliksi.
Pelaajan kuoltua ennemmin tai myöhemmin suoritus pisteytetään sammutettujen tiilien sekä selvityn ajan mukaan.
Mukana pelissä olisi myös alkuvalikko, highscoret sekä mahdollisesti muita ominaisuuksia.
2. Projektin ominaisuudet
- Ohjelmointikieli: C/C++
- Kirjastot: SFML multimediakirjasto
- Koodirivejä C++: ~3800
- Koodirivejä PHP: ~250
- Koodirivejä yhteensä: ~4000
3. Käytännön toteutus
Valitsimme pelin toteuttamista varten pienen mietinnän jälkeen SFML-kirjaston, koska siitä oli molemmilla ryhmän jäsenillä jo hieman aiempaa kokemusta, ja se oli todettu toimivaksi ratkaisuksi.
Sovelluksen kehityksen elinkaaren loppupuolella kehittelimme MASA-ohjelmistokehityskehyksen (vrt. Scrum, DSDM). MASA-kehys (Mieskolainen Agile Software Assertion) yhdistää monien muiden ketterien ohjelmistokehitysmenetelmien parhaita puolia huipputehokkaaksi kokonaisuudeksi.
MASA :aa kehittäessä haimme paljon inspiraatiota Jyväskylän Ammattikorkeakoulun lehtorin Matti Mieskolaisen innovatiivisestä ja mullistavasta otteesta opettamiseen, joten kiitos siitä hänelle.
MASA voidaan kiteyttää lyhyesti seuraavaan loogiseen lauseeseen: Hyvin suunniteltu = Puoliksi tehty => Puoliksi tehty = Hyvin suunniteltu
Selkokielellä jos Hyvin suunniteltu on equivelantti Puoliksi tehdyn kanssa, niin sen seurauksena Puoliksi tehty equivelantti Hyvin suunnitellun kanssa.
4. Luokat
4.1 Game
Itse pelin pääluokka on Game.
Game ottaa parametreikseen osoittimen piirtoikkunaan, sekä charin, jonka avulla Game tietää, pyöritetäänkö täysinäistä versiota, vai graafisesti karsittua muunnosta.
Teimme karsitun version siksi että koulun koneet eivät jaksaneet enää pyörittää peliä 60 FPS.
Tämä johtuu siitä, että OpenGL Shading Languge, jota on käytetty laava-shaderissä, pyörii näytönohjaimella.
Koulun koneiden näytönohjaimet sattuvat olemaan kehnoja, tai sitten tarvittavia ajureita ei ole päivitetty.
Game-luokan tärkein metodi on Run.
Kun peli on käynnissä, suoritetaan aluksi pelin logiikan käsittely tapahtumien prosessointimetodeilla (esim. ProcessEvents), sitten päivitämme pelin logiikkaa (Update-metodit) ja lopuksi piirrämme näytölle pelin tilan render-metodissa.
Tämä kaikki suoritetaan 60 kertaa sekunnissa, jotta saadaan sujuva ja pelattava loppukokonaisuus.
Tämän perusrakenteen Game-luokan jakamisesta prosessointiin, päivittämiseen sekä piirtämiseen saimme SFML:n kehittäjän, Laurent Gomilian kirjasta SFML Game Development (ISBN: 1849696845, julkaisukuukausi 6.2013.)
4.2 World
World-luokka on itse pelikenttä.
Annamme sille osoittimina/viittauksina piirtoikkunan, tekstuurimanagerin, pelaajan,vesiprojektiilimanagerin, äänimanagerin, sekä scoren.
Worldissa hoidamme tärkeitä toimintoja kuten collision detectionin pelaajan, laavan sekä vesiprojektiilien välillä, sekä laavan leviämisen.
Worldin ylivoimaisesti tärkein metodi on update, jossa kaikki edellämainitut asiat tapahtumat. Se on rivimäärissä mitattuna sovelluksen isoin metodi.
4.3 Scene
Scene-luokka on sekä pelin että päävalikon kantaluokka, joka sisältää vain yhden virtuaalisen metodin, Runin.
Run palauttaa kokonaisluvun, jonka avulla pystymme hyppimään eri tapahtumista toiseen pelin main-metodissa.
Tämä mahdollistaa helposti uusien kokonaisuuksien lisäämisen peliin periyttämällä ne scenestä, esimerkiksi creditsit tai moninpeli olisi suhteellisen helppo lisätä.
Totta kai pelin eri tiloilla on muitakin samankaltaisuuksia kuin Run esimerkiksi piirtofunktio ja tapahtumienkäsittely, mutta emme nähneet käytännön kannalta tarpeelliseksi periyttää näitä abstraktista luokasta.
4.4 Player
Player-luokka kuvaa pelin pelaajaa, kuten nimestä voikin päätellä.
Pelaajalla on muunmuassa nopeus, kiihtyvyys, hitpointsit ja ammukset.
Pelaajan tärkeimmät metodit ovat liikkumisesta vastaava calculateVelocity(), ampumisesta vastaava shoot(), sekä pelaajan päivittämisestä pelimaailmassa vastaava update().
4.5 Entity
Entityjä ovat pelin objektit, kuten pelaajan projektiilit ja Powerupit.
Kaikille Entityille yhteistä on lähinnä elinaikaan liittyvät muuttujat/metodit.
Entityjä hallitaan puolestaan EntityManager-luokalla, joka on Entity-tyyppisen vektorin ympärille rakennettu wrapperi.
Entitymanager huolehtii Entityjen lisäämisestä ja kuolleiden Entityjen pois siivoamisesta
4.6 Score
Score-luokka pitää, yllätys yllätys, huolta pelaajien pisteistä ja niiden yleisestä hallinnasta kuten resetoinnista, lisäämisestä ja loppupisteiden laskemisesta. Tämän lisäksi Score luokka hoitaa scorejen hashauksen ja lähetyksen webbiin sekä POST-replyn vastaanottamisen ja käsittelyn.
4.7 Menu
Menu on oikeastaan aika pieni, mutta silti kompleksi luokka. Menu-luokka huolehtii päävalikon toiminnasta, versioncheckistä ja osittain myös pelin uudelleenkäynnistämisestä.
Tunnelman luomiseksi menuun on koodattu fade-in ja fade-out efektit, eli menu siis tulee esiin asteittan ja häipyy samalla tavalla.
4.8 Entitymanager
Entitymanager-luokka pitää sisällään entityvektorin ja hallitsee niitä.
Entitymanager on template-luokka ja näin ollen sama luokka voi pitää huolta erityyppisistä entityistä tai peliobjekteista.
Entitymanagerin ehkäpä tärkein metodi on clean-metodi, joka käy läpi oman vektorinsa kaikki entityt ja poistaa kuolleeksi merkatut entityt pelistä viemästä muistia.
4.9 Muut luokat
Muita vähäpätöisempiä(kö?) luokkia ovat Tile, Powerup ja Ammopowerup.
Nämä luokat ovat tietysti tärkeä osa kokonaisuutta, mutta samalla myös tylsiä ja melko tyhjiä, periaatteessa apuluokkia.
Sitten on vielä kaikki resurssimanagerit kuten Texturemanager ja Sfxmanager, joiden tehtävänä on pitää huolta että peli lataa käynnistyessään tarvitut kuvat ja äänet ja pitää ne muistissaan sulkemiseen asti.
5. Tietovarastot
Pelissä käytetyt resurssit (tekstuurit, ääniefektit) ladataan omiin manageriluokkiinsa, joista niitä voidaan hakea ID:n perusteella.
Näin kehittäjän ei tarvitse muistaa ulkoa resurssien tiedostopolkuja tai tyyppejä tms.
Toinen pelissä käyttämämme tietovarasto on Score-luokka, joka pelaajan kuoltua ottaa talteen pelaajan saaman pistemäärän sekä nimimerkin, ja lähettää ne Labranetillä pyörivälle palvelimelle POST-viestinä.
Ennen lähettämistä nimi puhdistetaan mahdollisista haitallisista merkeistä (esim. |, $), ja palvelinpäässä se tallennetaan yksinkertaiseen taulukkoon, jossa pelaaja voi vertailla kuinka on pärjännyt.
Koodista
Koodi on mitä se on ja sitä voi käydä lueskelemassa.. Esimerkiksi World-luokassa käytettiin paljon luuppeja ja muuta logiikkaroinaa, jotta laava saadaan leviämään hienosti ja optimoidusti, joten senkin läpikäyminen on paitsi aikaa vievää että yleisen ohjelmoinnin kannalta turhaa..
Peli ja luokat on rakennettu idealla "Game > World > Player", eli Game-luokka hoitaa suurimman osan asioista, sitten World, sitten Player.
Pidämme Game-luokkaa pelin niinsanottuna pääluokkana josta miltein kaikki lähtee ja johon miltein kaikki päätyy.
Onko tällainen ajattelutapa sitten olio-ohjelmoinnin kannalta sen parempi tai huonompi kuin mikään muukaan, niin vastauksena siihen että ainakin peli pyörii ja kaiken lisäksi vielä melkoisen hyvällä suorituskyvyllä ja muistin käytöllä.
Pelin teossa tavoitteena oli pääasiassa uusien asioiden keksiminen ja kokeileminen ja tässä onnistuttiin mitä loistavimmin.
7. Pelistä
7.1 Pelikuvaa
Seuraavassa videossa esitellään millainen softwareproject on pelinä. Peliä pelataan normaaleilla asetuksilla ja parhaimmilla grafiikoilla.
7.2 Highscoret
Softwareprojectin highscoret tallennetaan HTTP POST-requestilla web-palvelimelle, josta niitä voi selata web-käyttöliittymällä.
Kyseisen sivuston voi löytää esimerkiksi tästä linkistä.
7.3 Moninpeli
Moninpeli on viimeisimpiä lisäyksiä Softwareprojektiin. Moninpelissä peliin lisätään toinen pelaaja, jota on mahdollista ohjata esimerkiksi xbox-ohjaimella.
8. PHP:n käyttö
Softwareproject käyttää muutamaa eri PHP-skriptiä.
Pisteiden "kuuntelu"- ja tallennus-skripti parsettaa ja validoi Softwareproject.exen sille lähettämät pisteidenlisäys-requestit. Mikäli lisäyspyyntö ei jostain syystä mene läpi, lähettää tämä skripti siitä replyn takaisin Softwareproject.exelle.
Pisteiden lataus-skripti järjestää ja tulostaa web-sivulle sen hetkiset highscoret.
Versioncheck-skripti kertoo pyydettäessä Softwareproject.exelle nykyisen uusimman version hashin. Mikäli Softwareproject.exe on vanhentunut sille lähetetään latauslinkki uusimpaan versioon palvelimella.
9. Luokkakaavio
10. Mainittavia bugeja / ongelmia
Vaikkakin ohjelmistoprojektissa tulee aina ongelmia ja bugeja vastaan, niin tässä on muutama suurin:
Tilejen spritet katosivat muistista satunnaisesti. Tämä bugi johti texturemenagerin ja kaikkien muiden managerien suunnitteluun ja toteutukseen.
Väärä merkistökoodaus joissain tiedostoissa. Tämä ongelma oli erityisen ärsyttävä sillä koodi oli oikein, mutta esimerkiksi C++:n tietyt funktiot eivät ymmärtäneet ANSI-merkistökoodausta ja näin ollen lukivat mitä sattuu.
Joitain aikaongelmia. Nämä ongelmat liittyivät pelin päivitysnopeuteen ja tapahtumien kulkuun. Välillä jokin asia tapahtui hetkessä vaikka sen olisi pitänyt odottaa 15 sekuntia.
Virustorjunta. Kiitos Avastin "loistavan" virustentorjunnan, se ei antanut välillä ajaa koko ohjelmaa ollenkaan. Allekirjoittanut onkin nyt siirtynyt käyttämään MSE.
Teemun POST-request kaappaukset ja spooffaus. Tämä ongelma johti highscorejemme lähetysten suojaamiseen ylimääräisellä hashilla, jonka luonnin ja ns. purkamisen näkee vain plaintext-lähdekoodista
11. Itsearvio
Kaiken kaikkiaan olemme sitä mieltä että peli onnistui hyvin.
Toki aina leikkauspöydälle jää joitain ominaisuuksia joiden toteuttaminen katsottiin käytännössä olevan tarpeetonta, mutta silti pelistä tuli jokseenkin sellainen kuin sen aluksi olimme visualisoineet.
Joitakin ominaisuuksia emme edes osanneet alussa pohtia varteenotettavina, esimerkiksi scoren tallentaminen palvelimelle.
Puutteina kehitystyössä tulee päällimmäisenä mieleen kunnollisen projektinhallinnan puute.
Esimerkiksi GitHubin avulla ei tarvitsisi erikseen selvittää mitä muutettiin/lisättiin ja suorittaa sitten muutosten yhdistys, vaan kehitysprosessi nopeutuisi huomattavasti.
Onneksi peli olikin loppujen lopuksi vain 4000 riviä koodia, ja kahden ohjelmoijan kesken sen manageroimisessa ei esiintynyt huomattavia ongelmia.
Työn kesto
1,5 kuukautta
Tekijät
- Jonah Ahvonen
- Matti Jokitulppo
Lisenssijuttuja
Vastuuvapauslauseke: Kaikki lainatut resurssit on otettu vain opetuskäyttöä varten.
- Ohjelmointi: Jonah Ahvonen & Matti Jokitulppo.
- SFML multimedia library: Laurent Gomila (sfml-dev.org).
- Taustamusiikki: NES Silver Surfer (c) NINTENDO / Software Creations / Arcadia Systems.
- Ääniefektit: SFXR.
- Tile texturet: opengameart.org.
- Pelaajasprite: Dushan Chaciej | ANtY (everyday-im-drawing.blogspot.fi).
- Lava shader: glsl.heroku.com GLSL Sandbox.
- Palomiesko naama: (c) M. Mieskolainen.
- 04b.ttf fontti: dafont.com.
- Water droplet sprite: rock1111100 (piq.codeus.net).
- C++ md5 algoritmi: http://www.zedwood.com/article/cpp-md5-function
- C++ IniReader ja IniWriter: http://www.codeproject.com/Articles/10809/A-Small-Class-to-Read-INI-File
Muuta
Kiitos testaajille!