Alkuvalikko ja pelitila
Nyt päästään kunnon hommiin, nimittäin pelimme varsinaiseen koodaukseen! Ensin toteutetaan alkuvalikko ja pelitila, joiden pohjalta voidaan koodata peli kuin peli.
Suunnitelma on seuraava:
- Kun ohjelma käynnistetään, näytetään alkuvalikko.
- Alkuvalikossa on kohteet "New Game", "Options" sekä "Quit to DOS", jotka voi valita nuolinäppäimillä ylös ja alas;
- kun on valittu New game ja painetaan Enter, siirrytään pelitilaan
- kun on valittu Quit to DOS ja painetaan Enter, suljetaan ohjelma
- jos valinta on Optionsissa ja painetaan Enter, mitään ei tapahdu (koodataan kolme alkuvalikon kohdetta ihan vain, jotta voimme nähdä valikon selaamisen toimivan oikein)
- jos valinta Quit to DOSissa ja painetaan nuolinäppäintä alas, siirretään valinta New Gameen ja päinvastoin.
- Kun pelitilassa painetaan Esc, siirrytään alkuvalikkoon.
Luodaan lähdekooditiedostot ja sisällytetään kirjastot
Ihan ensimmäiseksi tehdään muutama tiedosto-operaatio;
- Luo kansioon C:\DOSDEV kansio GAME.
- Luo GAME-kansioon tiedostot main.c ja main.h.
- main.c on lähdekooditiedosto, jossa määritetään ja kutsutaan funktiot sekä määritetään niiden paikalliset muuttujat
- main.h on otsikkotiedosto, jossa esitellään funktiot sekä määritetään vakiot ja globaalit muuttujat.
Seuraavaksi avaa kumpikin kooditiedosto valitsemassasi tekstieditorissa, sillä lisäämme koodia kumpaankin aina kun tarve vaatii.
Lisää tiedostoon main.c kaikkein ylimmäksi seuraavat rivit, jotta päästään käsiksi kirjastojen stdio.h ja allegro.h funktioihin kuten myös otsikkotiedostomme main.h sisältöön.
Seuraavaksi avaa main.h-otsikkotiedosto ja lisää siihen alla olevat rivit, jotta kaikki otsikkotiedostoon määritellyt vakiot ja muuttujat sekä esitellyt funktiot sisällytetään lähdekooditiedostoon vain kerran. Huomaa, että kaikki lisäykset main.h-otsikkotiedostoon on tultava rivien #define MAIN_H sekä #endif väliin.
Jostain syystä kääntäjä haluaa yhden tyhjän rivin viimeisen koodirivin jälkeen sekä main.c-lähdekooditiedostoon että main.h-otsikkotiedostoon, sillä kääntäjä antaa varoituksen, jos tyhjää koodiriviä ei lopusta löydy. Lisää siis vielä se kumpaankin tiedostoon.
Koodataan alkuvalikko
Avaa main.h-otsikkotiedosto ja lisää sinne seuraavat rivit:
- määritellään lueteltu tyyppi GameState, sille arvot MENUSTATE ja GAME ja muuttuja activeGameState
- määritellään muuttuja exitProgram
- esitellään funktiot SetupProgram(), DrawMenu(), DrawGame(), FadeAndBlit(), MenuKeyInput() ja Terminate().
Muista tehdä lisäys rivien #define MAIN_H sekä #endif väliin!
Lisää main.c-tiedostoon alla oleva main-funktion määrittely #include-rivien jälkeen. Tämä on siis ohjelmamme varsinainen, suoritettava osuus, jonka while-silmukkaa toistetaan niin kauan kunnes ohjelma päätetään sulkea.
Seuraavaksi määritellään esitellyt ja kutsutut funktiot. Funktioiden määrittelyt lisätään main-funktion ja END_OF_MAIN()-makron alapuolelle.
SetupProgram() – alustetaan ohjelma
Määritä main.h-otsikkotiedostoon vakiot SCREEN_WIDTH ja SCREEN_HEIGHT sekä niiden arvoiksi 320 ja 240; näillä arvoilla määritetään ruudun pikselien määrä leveys- ja pystysuunnassa.
"Mutta hei!" joku DOS-pelejä tunteva ajattelee. "Eikös klassinen VGA-resoluutio ole Mode 13h, jossa pystypikselien määrä on 200 pikseliä? Miksi meidän pelimme on resoluutiossa Mode X, eli pystypikseleitä on 240?" Lyhyt vastaus: kuvasuhde. DOS-pelien valtakaudella tietokonenäyttöjen kuvasuhde oli 4:3 – tiedäthän, se melkein neliön muotoinen. Resoluution 320 × 200 kuvasuhde on kuitenkin 16:10, ja kun se esitetään 4:3-kuvasuhteen näytössä, kaikkea näytön esittämää sisältöä yksittäisiä pikseleitä myöten venytetään pystysuunnassa. Tämä saa aikaan sen, että esim. koodiin kirjoitettu täydellisen ympyrän piirtäminen saa ruudulla aikaan soikion. "Mutta mikä ongelma tässä on? Eihän nykynäyttöjen kuvasuhde ole 4:3 vaan yleensä joko 16:10 tai 16:9, joihin resoluutio 320 × 200 sopii hyvin." Totta, mutta minulle DOS-pelien ainoa oikea kuvasuhde on 4:3, näytöstä riippumatta. Ja resoluution 320 × 240 kuvasuhde on aina 4:3, pikselit neliöitä ja ympyrät ympyröitä.
Alla olevista kuvista ylempi esittää väärässä, 16:10-kuvasuhteessa esitetyn kuvakaappauksen Commander Keen -pelistä. Alempi kuva on oikeassa kuvasuhteessa eli 4:3. Huomaa punaiset tikkarit, jotka ylemmässä kuvassa ovat väärän kuvasuhteen takia soikeita; tikkari-spritejä piirrettäessä on siis pitänyt ottaa tämä kuvasuhdekikkailu huomioon ja piirtää ne soikeiksi, jotta ne esitetään 4:3-näytössä täydellisinä ympyröinä, kuten alempi kuva osoittaa.
Määrittele myös lueteltu tyyppi MenuItem, sille arvot NEW_GAME, SETTINGS, EXIT ja NUM_MENU_ITEMS sekä lopuksi muuttuja selectedMenuItem. Nämä ovat alkuvalikon kohteet sekä niiden määrä.
Määrittele myös BITMAP-osoitinmuuttuja *buffer, jonka muistiin kaikki grafiikka piirretään ennen sen siirtämistä varsinaiseen näyttömuistiin eli monitorin ruudulle.
Lisää sitten main.c-lähdekooditiedostoon SetupProgram-funktion määrittely, jossa tehdään ohjelman toiminnan kannalta tarpeelliset alustukset:
DrawMenu() – piirretään alkuvalikko
Lisää main.h-otsikkotiedostoon alla olevat vakiot, joiden arvoiksi annetaan alkuvalikon tekstit ja värit.
Lisää sitten DrawMenu-funktion määrittely main.c-tiedostoon SetupProgram-funktiomäärityksen alapuolelle.
DrawGame() – piirretään pelitila
Toistaiseksi pelitilassa ei tehdä muuta kuin tyhjennetään buffer-näyttömuisti ja täytetään se harmaalla värillä, ihan vain jotta voimme siirtyä tilasta toiseen ja nähdä sen sujuvan niin kuin pitää.
Lisää siis main.h-otsikkotiedostoon vakio pelitilan taustavärille ja määritä se harmaaksi.
Lisää sitten main.c-lähdekooditiedostoon funktion DrawGame määrittely, jossa on vain clear_to_color-funktiokutsu buffer-näyttömuistin tyhjentämiseksi ja täyttämiseksi COLOR_GAME_BG-vakioon määritetyllä värillä.
FadeAndBlit() – siirretään buffer-näyttömuistin sisältö ruudulle
FadeAndBlit-funktion määrittelyssä varmistetaan grafiikan päivitys synkronissa monitorin virkistystaajuuden kanssa (vsync()) sekä suoritetaan ns. blit- eli block image transfer -operaatio, jossa buffer-näyttömuistin sisältö siirretään screen-näyttömuistiin, mikä saa piirtämämme grafiikan näkymään ruudulla.
MenuKeyInput() – näppäinkomennot
Määritellään näppäinkomennot näppäimille Enter (key[KEY_ENTER]) ja Esc (key[KEY_ESC]) sekä nuolille ylös ja alas (key[KEY_UP] ja key[KEY_DOWN]).
Terminate() – suljetaan Allegro
Terminate-funktiossa suljetaan Allegro.
Käännä ja suorita!
No niin, olemme lisänneet kaiken tarvittavan alkuvalikon toteuttamiseksi sekä alkuvalikosta pelitilaan ja takaisin siirtymiseksi! Seuraavaksi tallenna lähdekoodi- ja otsikkotiedosto ja käännä ne DOSBoxissa käskyllä gcc main.c -o -game.exe -lalleg. Jos kaikki meni hyvin, ei virheilmoituksia eikä varoituksia tule, ja sinulla on suoritettava ohjelma GAME.EXE. Meidän pelimme!
Ekstrakikkailua!
Pienellä lisävaivalla saamme ohjelmaamme vähän visuaalista lisämaustetta: häivytyksen mustaan ja takaisin tilojen välillä siirryttäessä sekä ns. loppuruudun. Nämä eivät ole ohjelman toiminnan kannalta välttämättömiä kikkoja mutta ovat osaltaan antamassa pelistä viimeistellyn vaikutelman.
Häivytys mustaan ja takaisin
Nyt, kun ohjelmassa siirrytään eri tilojen välillä, siirtyminen tehdään salamana. Onneksi siirtymiin saadaan kuitenkin pieni mutta merkittävä Allegron tarjoama erikoistehoste, nimittäin häivytys mustaan ja takaisin.
Lisää main.h-otsikkotiedostoon alla olevat rivit. Määritellään siis vakio häivytyksen kestolle (#define FADE_DURATION) ja valitaan sen arvo väliltä 1–64; tässä tapauksessa arvo on 8. Määritellään myös muuttujat häivytyksille sisään (allowFadeIn ja allowStartupFadeIn) ja ulos (allowFadeOut) sekä sille, onko häivytys parhaillaan käynnissä (fadeInProgress).
Lisää main.c-lähdekooditiedoston SetupProgram-funktiomääritykseen seuraava rivi, jotta sallitaan alkuvalikon häivytys sisään kun pelin käynnistää:
Lisää SetupProgram-funktioon myös fade_out-funktiokutsu, jolloin peliä käynnistettäessä jopa DOS häivytetään hienosti pois.
Tee FadeAndBlit-funktioon seuraavat lisäykset, jotta häivytys tapahtuu siirryttäessä alkuvalikosta pelitilaan ja takaisin sekä kun pelin käynnistää.
Kun peli käynnistetään, suoritetaan siis allowStartupFadeIn-ehtolausekkessa oleva fade_interpolate-häivytys, paletin asettaminen ja blit-operaatio, mutta tilojen välillä siirryttäessä toteutetaan sitten allowFadeOut- ja allowFadeIn-ehtolausekkeissa olevat fade_out- ja fade_in-häivytykset. Pelin käynnistämiselle on oma häivytyksensä siksi, koska fade_in-häivytystä käytettäessä grafiikkatilan asettamisessa välähtää ikävää väri- ja symbolitauhkaa, mitä ei fade_interpolate-häivytystä käytettäessä tapahdu.
Tee MenuKeyInput-funktioon seuraavat lisäykset; sallitaan siis häivytykset, kun siirrytään tilasta toiseen.
Lisää vielä fade_out-funktiokutsu Terminate-funktion määrittelyyn, jotta alkuvalikko häivytetään pois kun ohjelma suljetaan.
Nyt, kun peli käynnistetään, DOS häivytetään pois ja alkuvalikko häivytetään sisään. Lisäksi häivytykset sisään ja ulos tehdään myös pelitilan ja alkuvalikon välillä siirryttäessä sekä vielä häivytys ulos, kun ohjelma suljetaan. Peli tuntuu heti paljon ammattimaisemmalta, ja ensiaskel kotikutoisesta indiekötöstyksestä kohti kolmen A:n taideteosta on otettu!
Loppuruutu
Yksi erityinen piirre vanhoissa hyvän ajan DOS-peleissä oli loppuruutu, eli kun peli suljettiin ja siirryttiin takaisin DOSiin, tulostettiin jopa kokonainen ruudullinen tekstiä ja ASCII-grafiikkaa. Esim. alla olevassa kuvassa on Rise of the Triad -pelin loppuruutu, jossa soimautetaan warettajien omatuntoa ja mainostetaan muita Apogee Softwaren pelejä.
Meidän loppuruutumme on toistaiseksi vain yksi nöyrä rivi, joka lisätään main.h-otsikkotiedostoon vakion TEXT_ENDMESSAGE arvoksi. Laita lainausmerkkien väliin oma viestisi; viimeiset merkit \n tekevät tyhjän rivin loppuruudun ja DOSin komentorivin väliin.
Lisää alla olevat rivit Terminate-funktioon, jolloin kun peli suljetaan, grafiikkatila asetetaan tekstimuotoon ja tulostetaan vakiossa TEXT_ENDMESSAGE määritetty teksti ruudulle.
Näin on koodattu alkuvalikko ja pelitila muutamin lisämaustein. Tästä on hyvä jatkaa!
Kommentit
Lähetä kommentti