Projektin loppuraportti

Ohjelma : BlackOut
Tekijä: Juho Vehviläinen

Sisällysluettelo

Kohdeohjelman kuvaus

Tekninen toteutus

Kokemukset projektista

Yhteenveto

Koodit

Kohdeohjelman kuvaus

Yleiskuvaus

Ohjelmointiprojektini oli graafinen seikkailupeli. Tavoitteena oli tehdä seikkailu- ja ongelmanratkaisupeli, jossa pelaaja pääsee liikkumaan maailmassa, joka koostuu eri paikoista. Eri paikat sisältävät tehtäviä, jotka pelaajan on ratkaistava edetäkseen pelissä. Tarkoitus oli tehdä yksinkertainen, mutta viihdyttävä seikkailupeli.

Ajattelin alun alkaen tekeväni projektissa pelin, koska peliä tehdessä on vapaat kädet juonen ja muiden kiinnostavien asioiden luomisessa, mutta alustavan projektisuunnitelman DL:n lähestyessä älysin, että en ollut keksinyt hyvää juonta pelilleni. Lopulta mieleeni juolahti parin viikon takainen tapahtuma, jossa etsiskelin tavaroitani ympäri Otaniemeä edellisen illan Bordelli-bileiden johdosta ja päätin tehdä tositapahtumiin perustuvan pelin. Pelissä päähenkilömme herää sängystään lauantai-iltapäivällä arveluttavassa olotilassa ja hänen takki, lompakko ja kännykkä ovat karkuteillä. Pelaajan tehtävä on etsiä kadonneet tavarat pelimaailmasta ja niiden löytämiseksi täytyy pelaajan suorittaa erinäisiä tehtäviä.

 

Toiminnallisuus

Pelimaailman tausta koostuu digitaalikameralla otetuista kuvista, jotka on muokatta sarjakuvamaisiksi Adobe Photoshop-ohjelman avulla. Pelissä voi liikkua liikkua paikasta toiseen katsomalla karttaa ja klikkaamalla haluttua kohdetta. Kohteeseen ei välttämättä pääse jos ei ole suorittanut vaadittuja tehtäviä ennen sitä. Pelin tehtäviin kuuluu mm. käsitekarttapelin ratkaiseminen, joka on yksinkertaiselta idealtaan siltikin hauska(tai ärsyttävä jos sitä ei pääse millään läpi) peli jossa täytyy ruudulle ilmestyviä värikkäitä nappeja painaa sitä mukaan kun niitä ilmestyy. Vaikeimmalla vaikeustasolla peli saattaa jopa yltää oikean käsitekartan tekemisen ärsyttävyystasolle. Ongelmanratkaiseminen on toinen pääasiallinen tehtävä pelissä. Henkilöille täytyy puhua, jotta saa selville enemmän edellisen illan tapahtumista ja heiltä saa myös tietoa siihen mistä kadonneet tavarat voisi löytyä. Usein pelin henkilöillä on hallussaan kadonnut tavara ja pelaajan täytyy tehdä henkilön puolesta eri tehtäviä esineen takaisin saamiseksi.

Pelimaailman tunnetta pyritään luomaan taustamusiikilla, joka vaihtuu aina kun vaihdetaan sijaintia. Taustamusiikin yritin valita niin, että se joko tukee tarinaa tai luo oikeanlaista tunnelmaa siirryttäessä paikasta toiseen. Pelissä mielikuvat ja mielleyhtymät vaikuttavat paljon pelinautintoon ja mielestäni musiikin tuominen peliin oli ehdoton edellytys pelinautinnon saavuttamiseksi.

Kun tietyissä sijainneissa käydään ensimmäistä kertaa, nähdään videokuvaa siitä mitä edellisenä iltana on tapahtunut, eli pelaajan muisti edellisestä illasta alkaa pätkittäin muistumaan mieleen. Tämä rakentaa mielestäni pelaajalle hyvän kuvan pelin juonesta ja rikastuttaa pelikokemusta entisestään. Seikkailupeleissä tarinan juoni on yleensä etusijalla, sillä hienosti toteutettu seikkailupeli ei ikinä tuota suurempaa mielihyvää jos juoneen ei ole panostettu. Juoni on yksinkertainen ja peli on suhteellisen lyhyt, mutta juoni noudattaa silti selkeää loogisuutta ja peliympäristö antaa tarpeeksi viitteitä eri tehtävien ratkaisemiseen.

Ohjelman toiminnallisuus siis koostuu pelimaailmassa liikkumisesta, tutkimisesta ja puhumisesta eri henkilöiden kanssa.

 

Käyttöliittymän kuvaus

Käyttöliittymä koostuu ikkunasta (JFrame), joka sisältää pelissä tarvittavat komponentit. Ikkunan keskellä on pelialue, jossa varsinainen pelinäkymä on esillä. Yläreunassa on tekstialue, jossa annetaan informaatiota esineistä ja henkilöhahmojen puheet ilmestyy sinne. Teksti ei ole pelaajan muokattavissa. Ikkunan oikeassa laidassa on sivupaneeli, josta löytyy pelissä tarvittavia nappeja kuten karttanappi ja ohjenappeja.

Ohessa on pelin perusnäkymä jossa näkyy keskipaneeli(kuva), sivupaneeli(sisältää napit) ja yläpaneeli, jossa on tekstialue. Perusnäkymä himademopysyy samana koko pelin ajan. Keskipaneeliin vaihtuu kuva aina kun siirrytään paikasta toiseen ja käsitekarttapelissä, kassakaapilla ollessa ja videota pyörittäessä keskipaneeli vaihtuu kokonaan toiseen paneeliin. Kuvassa näkyvät esineet(kaljapullo ja paita) ovat lisätty taustakuvan päälle JPanel-komponentteina ja ne on aseteltu oikeille paikoilleen GridBagLayoutin avulla. Kun hiiren vie niiden päälle niin yläpaneeliin vaihtuu teksti, joka kertoo tietoja valitusta esineestä. Esinettä painamalla voi sen kerätä itselleen, mutta jos pelaajalla ei vielä pysty esinettä keräämään, ilmoitetaan siitä yläpaneelin tekstialueessa. Paitaa esimerkiksi ei pysty ottamaan ennen kuin on juonut pullon virkistykseksi. Kun pelaaja on ottanut esineen, niin se poistetaan kuvasta ja lisätään pelaajan tietoihin lisätään että hän on poiminut sen.

kartta

 

Kun sivupaneelissa olevaa karttanappia painetaan ilmestyy näkyviin karttanäkymä. Tässä näkymässä pelaaja pystyy liikkumaan paikasta toiseen klikkaamalla kuvassa näkyviä kohteita. Kohteet eivät ole erillisiä komponentteja, vaan paneelilta on valittu pikselin tarkkuudella alueita joita painamalla sijainti vaihtuu. Tähän on käytetty MouseMotionListener-rajapintaluokan point-olion toimintoja, jotka kertovat missä hiiren kursori milloinkin liikkuu ja minkä koordinaatin kohdalla hiirtä on painettu alas.
Pelissä on viisi eri paikkaa, joiden välillä pelaajan täytyy liikkua. Paikkoja on viisi: Hima, josta peli alkaa, Käsitekarttapeli(tietokone), Gangsta(hattu), Tytsy(pullo) ja Bussipysäkki(pysäkin merkki). Kuva on piirretty käsin, ja siitä on otettu digikameralla kuva, siitä johtuu kartan kellertävä väri. Muut kuvat pelissä on otettu kameralla tai sitten screenshotteina tietokoneen näytöltä.  
 

 

 

Tekninen toteutus

Pelin luokkarakenne perustuu pitkälti sen komponentteihin. Esittelen luokat ja kerron niistä niiden toiminnat pääpiirteittäin. Luokkien luomiseen on käytetty runsaasti valmiita luokkia(esim. java.awt- ja java.swing-luokat)..

kaavio

Ohessa todella pelkistetty kaavio luokkien välisistä suhteista.

 

 

 

 

 

 

 

 

Paaikkuna-luokka periytyy luokasta JFrame ja on pelin päänäkymä. Se hoitaa peli-ikkunan ja kaikkien siihen lisättävien paneelien luomisen. Paaikkuna-luokka toteuttaa Mouselistener-rajapinnan ja huolehtii sivupaneelin nappien toiminnoista niitä painettaessa. Se on pelin suurimpia luokkia, sillä se huolehtii myös musiikin luomisesta ja toistamisesta, videopaneelin ja muiden yksittäisten paneelien luomisesta ja asettamisesta. Luokka sisältää runsaasti julkisia metodeja. Luokka huolehtii myös JOptionPane-tyyppisten ikkunoiden luomisesta, joilla annetaan pelaajalle informaatiota pelin eri vaiheissa.

Keskipaneeli-luokka hoitaa kaikki päänäkymän keski-ikkunassa olevat toiminnot. Luokka toteuttaa MouseListener- ja MouseMotionListener- rajapinnat, ja ottaa parametrikseen paaikkuna- ja tarina oliot. Tässä näkymässä tapahtuu pelin varsinainen eteneminen. Luokassa luodaan pelimaailman esineet ja asetellaan ne paikoilleen. Sijainnit ovat staattisia int-tyyppisiä arvoja. Luokan keskeisimmät metodit ovat MouseListener-rajapinnan vaatima mouseClicked-metodi ja MouseMotionListener-rajapinnan vaatima mouseMoved-metodi. MouseClicked-metodilla kontrolloi hiirenpainamisesta seuraavia tapahtumia, kuten esineen poiminen toiseen sijaintiin siirtyminen.

Keskipaneelin sijainti vaihdetaan, kun siirrytään paikasta toiseen ja tällöin myös taustakuva täytyy vaihtaa. Tämä käy kätevimmin ylikirjoittamalla paintComponent-metodi, jolla piirretään taustakuva uudelleen aina tarvittaessa.

Luokka hoitaa käsitekarttapelin toiminnot. Se toteuttaa Mouselistener-rajapinnan ja luo Timer-olion, jonka avulla käsitekarttapeli toteutetaan. Paneeli koostuu ruudukosta johon on sijoitettu näkymättömiä nappeja(Nappi-luokan oliota). Ruudukko luodaan GridBagLayout:n avulla ja napit asetellaan ruudukkoon for-lauseen avulla. Ajan käynnistyessä jokin nappi laitetaan näkyväksi tietyn aikaviiveen ajaksi, jolloin pelaajan täytyy painaa nappia edetäkseen pelissä. Napit ilmestyvät satunnaisesti ruudukon eri koordinaatteihin ja napin väri määräytyy satunnaisesti kahdeksan eri värin väliltä. Pelaajan painaessa nappia lisääntyy osumalaskuri, joka kontrolloi milloin pelaaja voi siirtyä seuraavalle vaikeustasolla. Hutilaskurin tullessa täyteen käsitekarttapeli loppuu ja sen joutuu aloittamaan alusta.

Vaikeustasoja on kolme. Pelin edetessä nappien aikaviive pienenee, eli napit ovat vähemmän aikaa näkyvissä, ja lisäksi niiden koko on muuttunut pienemmäksi. Tämä toteutetaan luomalla uusi Kasitekartta-paneeli, jossa on isompi ruudukko ja aikaviive asetettu pienemmäksi.

Kassakaappi-luokka toimii pitkälti samalla periaatteella kuin Kasitekartta-luokka. Kassakaapin napit asetellaan paikoilleen for-lauseen ja GridBagLayout:n avulla, ja lisäksi lisätään "0"- nappi erikseen. Kassakaapin ideana on, että sen saa auki oikealla kolminumeroisella yhdistelmällä. Kassakaapin napit on numeroitu nollasta yhdeksään, ja niitä painamalla tallentuu painettu luku taulukkoon. Sivupaneeliin on sijoitettu Avaa-nappi, joka tarkistaa näppäillyn numerokoodin ja ilmottaa jos koodi on oikein tai väärin. Jos valitsee enemmän kuin kolme lukua, niin silloinkin tulee ilmoitus ylimääräisistä numeroista

Nappi-luokka on yksinkertainen Kassakaappi- ja Kasitekartta-luokassa tarvittavien nappien luomista varten kirjoitettu luokka. Luokka periytyy luokasta JButton. Nappi-luokan tärkein ominaisuus on se, että napit tuntevat sijaintinsa. Tämän avulla Kassakaappi-ja Kasitekarttaluokasta voidaan kysyä, että mitä nappia on milloinkin painettu. Lisäksi käsitekarttapeliä varten napit voivat olla joko aktiivisia tai ei-aktiivisia, jolla säädellään sitä että pelissä painetaan oikeita nappeja oikeaan aikaan. Napit saadaan näkymättömiksi metodeilla setBorder(BorderFactory.createEmptyBorder()) ja setContentAreaFilled(false), joiden toteutuksen hoidin aluksi Nappi-luokassa, mutta Kassakaappi-luokkaa kirjoittaessa siirsin toteutuksen Kasitekarttaluokkaan, sillä kassakaapin napit täytyy olla näkyviä koko ajan.

Sound-luokka hoitaa pelin musiikin soittamisen. Suurimmat ongelmani projektissa liittyikin musiikin toistamiseen. Ensin yritin toistaa musiikkia Audioclip-oliona Applet-luokan avulla, mutta tämä tuotti ongelmia suurien wav-tiedostojen takia. Javan virtuaalikoneen muisti loppui aina kun yritti vaihtaa kappaletta, joten oli löydettävä parempi ratkaisu. Sound-luokassa jokaista kappaletta varten avataan uusi säie, jossa musiikki toistetaan. Luokka on toteutettu valmiista koodinpätkästä, jonka löysin netistä ja se on muokattu pelin tarpeisiin sopivaksi. Alkuperäisen koodin lähde löytyy Sound-luokan Javadoc-kommentista.

Luokka on tarkoitettu pelkästään videon toistamista varten. Kun pelissä päästään tilanteeseen, jolloin videon tulisi näkyä, poistetaan Paaikkunalta Keskipaneeli ja tilalle asetetaan Videopaneeli. Videopaneelissa luodaan Player-tyyppinen olio, jota tarvitaan videoiden toistamiseen. Luokka vaatii parametrikseen videon hakemistopolun, jotta se voi muodostaa tiedostosta mediaplayerin ja asettaa sen näkyväksi.

Myös videoiden kanssa ajauduin erinäisiin ongelmiin, kun Java ei suostunut toistamaan kuin muutamaa video-formaattia(mm.mpg ja avi), joten Windowsin MovieMaker-ohjelmalla tekemäni tiedostot eivät suostuneet toimimaan. Tämä olisi tietysti kannattanut tarkistaa ennen kuin aloin editoimaan videoita, mutta kaikkea ei aina tule ajatelleeksi. Lopulta sain editoitua videot Pinnacle Studio-ohjelmalla, jolla videot sai myös tallennettua mpg-formaattiin, joten ongelma ratkesi.

Pelin alkunäkymä. Aloituspaneelilla on tarina-nappi, josta painamalla ilmestyy JOptionPane-ikkuna, jossa kerrotaan pelin tarinan alustus. Aloitapeli-napista poistetaan Aloituspaneeli ja siirrytään itse peliin.

Luokka sisältää boolean arvoja, jotka määräävät pelin etenemistä. Luokka toimii pelin logiikkakoneistona, josta kysymällä peli päättää mitä pelaaja seuraavaksi voi tehdä ja minne edetä. Jokaiselle boolean-muuttujalle on metodit, joita kutsumalla voi toisista luokista käsin joko kysyä muuttujan arvoa tai muuttaa arvon true-arvoksi. Kaikki boolean-muuttujat ovat pelin alussa oletusarvoisesti false.

Kokemukset projektista

Projekti oli antoisa, todella työläs ja opettava. Suunnitteluvaiheessa olin todellakin pihalla projektin toteutuksesta ja se näkyi ehkä eniten luokkarakenteessa. Siinä vaiheessa kun ymmärsin, että luokkarakenteeni ei ollut parhainta olio-ohjelmointia, niin oli turhan työlästä enää muuttaa sitä. Suunnitteluvaiheen tärkeyttä painotettiin paljon, mutta jostain syystä se ei silloin tuntunut niin olennaiselta. Paremmalla suunnittelulla olisin säästänyt varmasti tuntikausia turhaa työtä. Varsinainen koodausvaihe ei lopulta kuitenkaan tuntunut niin raskaalta kuin odotin, mutta koska en ollut päättänyt koodausta aloittaessani edes juonta loppuun asti, niin jouduin pitkin matkaa aina tehdä muutoksia sitä mukaan kun juoni päässäni kehkeytyi.

Projektin aikana opin paljon enemmän kuin osasin alunperin kuvitella. Koodausrutiini parani huimasti, API:n käyttö tuntuu nykysin lastenleikiltä. Opin myös paljon muuta kuin pelkkää koodausta. Musiikin nauhoittamiseen tarkoitettu ACID-ohjelma tuli tutuksi kun nauhoitin pelin taustamusiikit. Toisaalta jos olisin tiennyt, että tulen käyttämään niin paljon aikaa M-audion breakbox:n säätämisen kanssa niin olisin varmaan harkinnut musiikin tuottamista jollain toisella tapaa. Lopuksi silti olen tyytyväinen siihen, että jaksoin nähdä vaivan musiikin soittamiseen, koska projekti tuntuu nyt paljon enemmän "omalta" kun siihen on tehnyt kaiken itse.

Kuvien muokkaaminen oli erittäin työlästä, kun käytin vanhaa Photoshop 7 -ohjelmaa, mutta helpottui huomattavasti kun sain käyttöönhimakuvai Photoshop 9 - ohjelman. Vanhalla softalla kuvien tekeminen sarjakuvamaiseksi kävi erilaisten layer:n lisäämisillä ja värikorostuksilla, ja ensimmäisen kuvan tekemiseen taisi mennä minulta ainakin tunnin verran. Ajattelin, että siihen täytyy löytää helpompi konsti ja onneksi Photoshop 9-ohjelmassa tämä toiminto oli tehty valmiiksi yhteen nappiin. Eri esineiden leikkeleminen ja editointi alkoikin tulla rutiiniksi siinä vaiheessa kun olin saanut kuvat valmiiksi.

Ohessa on digikameralla otettu kuva, josta sivun ylälaidan kuvassa voi nähdä editoidun version. Kuvassa näkyvät esineet on leikattu kuvasta erilleen ja lisätty pelissä taustakuvalle, joka on toinen kuva samasta kohteesta ilman esineitä.

Halusin peliini jotain erikoisempaa mitä projekteissa yleensä ei ollut käytetty ja sain mieleeni lisätä videomateriaalia pelin eri tilanteisiin. Tässäkin tuli muutama ongelma vastaan kun en ollut ennen käyttänyt Windows-pohjaisia editointiohjelmia ja jouduin opettelemaan niidenkin käytön aivan alusta. Halusin videoklipit alunperin mustavalkoisiksi, mutta editointiohjelma oli pelkästään trial-versio joten kaikki parhaimmat ja käytännöllisimmät erikoistehosteet oli tietysti jätetty pois. Videot kuvasin DV-videokameralla, jonka lainasin kaverilta ja siirsin kuvamateriaalin USB:n kautta koneelleni. Olen kohtalaisen tyytyväinen lopputulokseen, vaikka muutama erikoistehoste jäikin videoista pois, mutta pelin kannalta ne toi hauskan lisän juonen kulkuun ja rakenteeseen.

Projektipäiväkirjaa kirjoitin harmillisen harvoin sillä sinne olisi tullut varmasti enemmän kiroilua ja riemunhuutoja kuin sieltä nyt pystyy lukemaan. Projektin alussa tiedon etsiminen oli pienoinen pulma, mutta projektin edetessä sekin helpottui. Yleensä yritin lähestyä ongelmaa aluksi niillä taidoilla, joita olin kurssin harjoituksissa haalinut itselleni ja sen jälkeen vasta etsin tietoa netistä jos ongelma ei ratkennut. Lopulta en ajatunut kovinkaan usein ylitsepääsemättömältä tuntuvaan koodausongelmaan, vaan ratkaisut löytyi useimmissa tapauksissa suhteellisen helposti.Muutaman kerran tosin ajauduin debuggaamaan jotain ongelmaa tovin jos toisenkin, mutta ongelmat olivat yleensä vain omasta huolimattomuudesta johtuneita pikkuvirheitä.

Oma työskentely ja eteneminen oli silti hitaampaa kuin osasin odottaa. Ensimmäinen oma deadline projektille oli 22.12, mutta siinä vaiheessa projekti oli todellisuudessa ehkä puolessa välissä. Seuraava deadline 27.12 ylittyi sekin roimasti, joten jouduin palaamaan vielä koneen ääreen kahtena viimeisenä päivänä ennen projektin palautusta. Muutama harmiton pikkubugi projektiin taisi jäädä ja muutaman metodin olisin halunnut kirjoittaa järkevämmiksi, mutta loppuvaiheessa päätin laittaa kaiken energiani pelin toimivuuden testaamiseen ja pahimpien bugien karsimiseen. Projektisuunnitelmassa olin suunnitellut lukuisia kahdeksan tunnin työpäiviä, jotka osoittautuivat aika raskaiksi. Muutaman päivän ajan koodausta voi harrastaa täyspäiväisesti, mutta viikon jälkeen alkaa se maistuu sen verran puurolta, että työtehokkuus laskee roimasti. Mielestäni etenin suhteellisen hyvin suunnitelman mukaan, mutta olin arvioinut ajankäytön väärin. Sekin vaikutti aika paljon, että koodasinko Paniikissa vai kotona, sillä kotona oli sen verran paljon muita virikkeitä jotka usein veivät huomion aivan toisaalle ja täyspäiväisen koodauksen todellinen koodauspanostus saattoi jäädä muutamaan tuntiin. Kun palasin virkistyneenä viikon lomaltani, niin sain kahden viimeisen päivän aikana enemmän tehtyä kuin ennen lomaa viikon aikana. Eli työn rytmittäminen ja oman pään pitäminen virkeänä vaikutta selkeästi ainakin minun ohjelmointitaitoihini, mutta toisaalta silloin tiesin myös että palautus-deadline lähestyy vääjäämättä ja tämä varmaan antoi lisäpotkua perseelle.

Yhteenveto projektista

Voin sanoa, että olen projektiin tyytyväinen. Kurssia aloittaessani ajattelin, että projektin läpäiseminen tulee olemaan suurin saavutukseni sillä koodauskokemusta ei minulla ollut laisinkaan, joten oman pelin toteuttaminen tuntui utopistiselta ajatukselta. Lopulta kun siihen sitten ryhtyi, niin ei se niin vaikeaa ollutkaan. Sain peliin toteutettua kaikki ominaisuudet, jotka olin suunnitelmassa ajatellut tekeväni ja peli näytti ulkoisesti siltä kun sen mielessäni näin kuukausi takaperin.

Projektisuunnitelmassa olin arvioinut ajankäytöksi n. 100 h. Todellisuudessa varsinaisen koodin kirjoittamiseen ja debuggaukseen meni varmaan 80h, mutta kaikki muut projektiin vaadittavat osaset kuten kuvat, äänet, videot ja suunnittelu veivät yhteensä paljon enemmän aikaa.

Jos lähtisin uudestaan toteuttamaan projektia niin laittaisin ehdottomasti enemmän aikaa suunnitteluun ja saattaisin priorisoida ajankäyttöäni paremmin. Projekti antoi itselleni hyvän kuvan omista työskentelytavoista ja niiden puutteista. Javaa ajatellen opin paljon lisää sen graafisen puolen ominaisuuksista, Timer-luokan käytöstä, erilaisista Layout:sta ja niiden käytöstä ja lukuisista muista. Halusin tehdä graafista käyttöliittymää käyttävän pelin, sillä mielenkiintoni koodaukseen nousi huomattavasti kurssin viidennessä harjoituksessa, jossa pääsimme luomaan muutakin kuin tekstiä ruudulle.

Projekti aiheutti kaikkia tuntemuksia epätoivon hetkistä voiton tunteeseen ja kaikkea siltä väliltä. Projekti pyöri ihan tiedostamattakin päässä koko joulukuun sillä usein ratkaisut ongelmaan saattoivat tulla mieleen juuri silloin, kun oli tekemässä jotain muuta kuin koodaamassa. Vähän traumatisoituneenkin voin sanoa, että oli silmiä avaava kokemus ohjelmoida täysin omatoimisesti peli ja tekisin sen milloin tahansa uudestaan...ehkä parin vuoden lepoloman jälkeen..

Java-koodit:

  1. Paaikkuna.java
  2. Keskipaneeli.java
  3. Kasitekartta.java
  4. Kassakaappi.java
  5. Nappi.java
  6. Sound.java
  7. Videopaneeli.java
  8. Aloituspaneeli.java
  9. Tarina.java

Lataa peli jar-pakettina täältä!