Kirjoittaja: Antti Laaksonen (2003).
⚠ Huomio! Tämä opas on vanhentunut. Oppaan sisältöön ei voi enää luottaa. Opas on säilytetty vain sen historiallisen arvon vuoksi. ⚠
Jalokivijahdissa kaikki pelin yleiset aliohjelmat ja funktiot ovat moduulissa. Samassa moduulissa on myös muutaman WinAPI-funktion, vakioiden sekä globaalien muuttujien määrittelyt. Globaali muuttuja on näkyvissä kaikissa ohjelman moduuleissa ja formeissa. Tällaiset osat kannattaa koota moduuliin erityisesti silloin, kun pelissä on mukana useampia formeja.
Tavallisesti ohjelman suoritus alkaa formista, mutta se voi yhtä hyvin alkaa myös moduulissa olevasta Main-aliohjelma. Tällöin Project->Properties-valikosta avautuvasta ikkunasta on valittava Startup Objectiksi Sub Main. Jalokivijahdissa Main-aliohjelma näyttää seuraavalta:
Sub Main() 'näytetään peli-ikkuna jakija.Show 'annetaan hetki aikaa järjestelmän tapahtumille, jotta 'äskeinen ikkuna todella ilmestyy näkyviin DoEvents 'jos ohjelman hakemistosta löytyy kuvat.bmp-tiedosto... If TiedostoOlemassa(App.Path & "\kuvat.bmp") Then '...ladataan se peli-ikkunan näkymättömään kuvakehykseen jakija.pKuvat.Picture = LoadPicture(App.Path & "\kuvat.bmp") Else '...muussa tapauksessa näytetään virheilmoitus... MsgBox "Tiedostoa 'kuvat.bmp' ei löydy pelin hakemistosta!" '...ja suljetaan ohjelma heti alkuunsa End End If 'aloitetaan uusi peli UusiPeli End Sub
Kun peli-ikkuna on avattu, sen näkymättömään kuvakehykseen ladataan ohjelman kanssa samassa hakemistossa oleva BMP-kuva, jossa on kaikki pelissä käytettävät palikat. pKuvat-kuvakehyksen AutoRedraw-ominaisuuden arvo täytyy olla True, jotta kuva pysyy tallessa formin alla. Pelin hakemisto on tietystikin eri jokaisella pelaajalla, minkä vuoksi se täytyy hakea App.Path-muuttujasta. TiedostoOlemassa on funktio, joka on tosi, jos parametrina annettu tiedosto on olemassa.
Function TiedostoOlemassa(nimi As String) As Boolean 'Dir-funktion varsinainen käyttötarkoitus on hakemiston 'tiedostojen läpikäyminen, mutta samalla Dir(tiedosto) on 'tyhjä merkkijono, jos tiedostoa ei ole olemassa If Dir(nimi) <> "" Then TiedostoOlemassa = True Else TiedostoOlemassa = False End If End Function
Dir-funktion varsinaisesta käyttötarkoituksesta on lisää tietoa hakemistossa.
Kuvakehystä (PictureBox) tai kuvaa (Image) ei kannata koskaan käyttää liikkuvan kuvan näyttämiseen, koska ne ovat hitaita ja vilkkuvat ja välkkyvät. WinApin BitBlt-funktio on sen sijaan hyvä valinta tähän tarkoitukseen. BitBlt kopioi kuvan tai osan kuvasta toiseen kuvaan. Funktio ja siihen liittyvä vakio täytyy määritellä moduulin alussa:
Public Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long Public Const SRCCOPY = &HCC0020
On myös kätevää määritellä joukko vakioita, jotka kuvaavat palikoiden kuvien järjestystä tiedostossa. Vakioiden ansiosta vaikeasti muistettavilla numerotunnuksilla on nyt helposti muistettavat kirjaintunnukset.
Public Const KAYTAVA = 0 Public Const AVAINP = 1, AVAINS = 2, AVAINV = 3, AVAINK = 4 Public Const LUKKOP = 5, LUKKOS = 6, LUKKOV = 7, LUKKOK = 8 Public Const SEINA = 9 Public Const PALLO = 10 Public Const LOPPU = 11 Public Const JALOKIVI = 12
Kuvan piirtävästä aliohjelmasta on tehty helppokäyttöinen. Parametrit ovat kuvan tunnus (joku ylläolevista vakioista), pelitason sarake ja pelitason rivi. Esimerkiksi seuraavalla komennolla voidaan piirtää jalokiven kuva kolmannen rivin viidennen sarakkeen kohdalle:
PiirraKuva JALOKIVI, 5, 3
Aliohjelma itsessään on tässä. Jokaisella formilla ja kuvakehyksellä on oma kahva eli hDC. Kahvojen avulla Windowsin grafiikkafunktiot tietävät, minne kuva täytyy piirtää tai mistä se täytyy kopioida. Visual Basicissa kahva on luettavissa oleva ominaisuus. Palikka siis kopioidaan näkymättömästä kuvakehyksestä (pKuvat) pelitasolle (pTaso). Piirtokohdan laskeminen on kuvattu koodissa.
Sub PiirraKuva(tunnus As Integer, x As Integer, y As Integer) 'tähän muuttujaan tallennetaan funktion palautusarvo, 'jolla ei kylläkään tee tässä tapauksessa mitään Dim a As Long 'BitBlt-funktion parametrit: ' o jakija.pTaso.hDC on kohteena olevan kuvakehyksen kahva ' o x * 32 ja y * 32 määrittävät palikan piirtokohdan, joka ' riippuu annetuista parametreista ja palikan koosta ' o palikan leveys ja korkeus ovat 32 ' o jakija.pKuvat.hDC on sen kuvakehyksen kahva, josta ' piirrettävä kuva kopioidaan ' o tunnus * 32 + tunnus laskee kopioitavan palan sijainnin ' kuvassa ottaen huomioon palikoiden välillä olevan ' yhden pikselin levyisen suikaleen ' o y-koordinaatti on aina 0, mikä tarkoittaa kuvan ylälaitaa ' o SRCCOPY merkitsee tavallista kopiointia a = BitBlt(jakija.pTaso.hDC, x * 32, y * 32, 32, 32, jakija.pKuvat.hDC, tunnus * 32 + tunnus, 0, SRCCOPY) End Sub
Tällaisten aliohjelmien käyttäminen selkeyttää koodia huimasti.
Seuraavaksi lisätään moduulin alkuun pari pelin kulkuun liittyvää taulukkoa. Kaksiulotteiseen Taso-taulukkoon tallennetaan tieto jokaisesta pelitason palikasta (edelleen yksi yllä määritellyistä vakioista). Koska taulukon indeksointi aloitetaan nollasta, sen koko on 10 x 10. Avaimet-taulukkoon taas tallennetaan punaisten, sinisten, keltaisten ja vihreiden avainten lukumäärä. Taulukko indeksoidaan vakioiden avulla.
'10x10-taulukko, joka sisältää tiedon jokaisesta pelitason palikasta Public Taso(9, 9) As Integer 'taulukko, jossa on kunkin väristen avaimien lukumäärä Public Avaimet(AVAINP To AVAINK) As Integer
Tämän lisäksi määritellään joukko muuttujia: Jalokivet kuvaa pelitasolla jäljellä olevia jalokiviä. Kun puuttuvien jalokivien määrä on nolla, pallo saa jatkaa seuraavalle tasolle. NTaso on senhetkinen pelitason numero. Aika on jäljellä oleva aika sekunteina. Jos aika loppuu, peli päättyy. Kaynnissa on joko True (tosi) tai False (epätosi). PalloX ja PalloY ovat pallon koordinaatit.
'puuttuvien jalokivien määrä Public Jalokivet As Integer 'tämänhetkinen pelitaso Public NTaso As Integer 'jäljellä oleva aika Public Aika As Integer 'tosi, jos peli on käynnissä Public Kaynnissa As Boolean 'pallon x- ja y-koordinaatti Public PalloX As Integer, PalloY As Integer
Main-aliohjelman viimeisellä rivillä kutsuttiin UusiPeli-aliohjelmaa, joka näyttää seuraavalta:
Sub UusiPeli() 'ladataan ensimmäinen taso LataaTaso 1 'piirretään palikat ikkunaan PiirraTaso 'näytetään ylälaidassa olevat tiedot NaytaTiedot 'peli on nyt käynnissä Kaynnissa = True End Sub
Nyt on aika ottaa selville, miten pelitasot tallennetaan tiedostoon, luetaan sieltä taulukkoon ja lopuksi näytetään peli-ikkunassa.
Pelitasot on tallennettu erillisiin tiedostoihin, jotka ovat muotoa [tason numero].tas. Tiedoston päätteellä ei ole mitään väliä, mutta kannattaa valita sellainen pääte, joka ei sekoitu johonkin yleiseen tiedostotyyppiin. Pelitasot on tallennettu tekstimuodossa, jolloin niitä on helppo muokata Windowsin Notepadilla tai millä tahansa muulla tekstieditorilla. Tässä on pelin toinen taso, tiedosto 2.tas:
########## # p ## # ##### ## #l##### ## ####### ## ### ## ### ###P## ### ### ## ### ### ## a ###j##
Risuaidat kuvaavat seiniä ja välilyönnit käytävää. a on aloituspaikka (pallo) ja l on lopetuspaikka (l). Avaimet merkitään pienillä kirjaimilla ja lukot isoilla kirjaimella. p on siis punainen avain ja P punainen lukko. Tämä taso tulee näyttämään pelissä seuraavalta:
Tällaista tiedostoa voi lukea Visual Basicissa Input-tilassa. Rivin lukemiseen on käytettävä nimenomaan Line Input -lausetta Inputin sijaan, koska muuten rivien alussa olevat välilyönnit aiheuttaisivat ongelmia. Paras tapa muuttaa tiedostossa käytetyt kirjaintunnukset ohjelman käyttämään numerointiin on muodostaa merkkijono, jossa kirjaimet on lueteltu samassa järjestyksessä kuin niitä vastaavat palikat ovat kuvatiedostossa. Tämän jälkeen kirjainta vastaavan tunnuksen selvittäminen onnistuu helposti InStr-funktiolla ja se tallennetaan Taso-taulukkoon.
Jos luettu palikka on jalokivi, puuttuvien jalokivien määrää kasvatetaan yhdellä. Jos taas palikka on pallo, asetetaan sen aloituskoordinaatit muuttujiin PalloX ja PalloY. Tämän lisäksi aliohjelmassa vaihdetaan kunkin avaimen määräksi nolla, lasketaan pelaajan käytössä oleva aika tason numeron perusteella ja käynnistetään sekunnin välein reagoiva ajastin.
Tässä on koko pitkä LataaTaso-aliohjelma, jonka parametrina on ladattavan tason numero:
Sub LataaTaso(num As Integer) 'silmukassa käytettävät muuttujat Dim i As Integer, j As Integer 'luettu rivi ja palikoita vastaavat merkit tiedostossa Dim rivi As String, merkit As String 'tässä muuttujassa on tiedostossa käytetyt palikoiden 'merkit samassa järjestyksessä, kuin palikat ovat kuvassa merkit = " psvkPSVK#alj" 'kerättävien jalokivien määrä on aluksi nolla Jalokivet = 0 'avataan pelitason sisältävä tiedosto lukemista varten Open App.Path & "\" & num & ".tas" For Input As #1 'luetaan tiedostosta yhdeksän riviä For i = 0 To 9 'kukin rivi luetaan vuorollaan rivi-muuttujaan Line Input #1, rivi 'luetaan riviltä yhdeksän merkkiä For j = 0 To 9 'Mid-funktio palauttaa merkkijonon yksittäisen merkin; 'merkin paikka merkit-muuttujassa, joka taas saadaan 'selville Instr-funktiolla, kertoo suoraan palikan 'sijainnin kuvatiedostossa ja näin ollen sen tunnuksen Taso(j, i) = InStr(merkit, Mid(rivi, j + 1, 1)) - 1 'jos luettu palikka on jalokivi... If Taso(j, i) = JALOKIVI Then '...kasvatetaan kerättävien jalokivien määrää yhdellä Jalokivet = Jalokivet + 1 'jos luettu palikka on pallo... ElseIf Taso(j, i) = PALLO Then '...asetetaan sen aloituskoordinaatit PalloX = j PalloY = i End If Next Next 'suljetaan tiedosto, kun kaikki tiedot on luettu Close #1 'tyhjennetään taulukko, koska avaimia ei ole alussa laisinkaan For i = AVAINP To AVAINK Avaimet(i) = 0 Next 'tallennetaan ladatun tason numero muuttujaan NTaso = num 'lasketaan pelaajalle annettava aika aloitusarvon 'ja tason numeron perusteella (1. taso 30 s, '2. taso 40 s, 3. taso 50 s jne.) Aika = 20 + NTaso * 10 'käynnistetään ajan vähennyksestä huolehtiva ajastin '(1000 ms = 1 s) jakija.Timer1.Interval = 1000 End Sub
Pelitason piirtäminen on helppoa, kun se on kerran luettu. Aluksi piirretään pelitason reunat yhdellä For-silmukalla. Sen jälkeen piirretään kaikki muut palikat, jotka löytyvät nyt siis Taso-taulukosta.
Sub PiirraTaso() 'silmukoiden käyttämät muuttujat Dim i As Integer, j As Integer 'piirretään pelitason reunoilla olevat kiinteät seinäpalikat For i = 0 To 11 'yläseinä PiirraKuva SEINA, i, 0 'alaseinä PiirraKuva SEINA, i, 11 'vasen seinä PiirraKuva SEINA, 0, i 'oikea seinä PiirraKuva SEINA, 11, i Next 'piirretään muut palikat For i = 0 To 9 For j = 0 To 9 'seinien vuoksi piirtokohtaan lisätään 1 PiirraKuva Taso(i, j), i + 1, j + 1 Next Next End Sub
Esimerkiksi kuvakehyksellä olevaan AutoRedraw-ominaisuuteen kannattaa kiinnittää erityistä huomiota. Jos ohjelmaikkunan päälle tulee muita ikkunoita, kuvakehykseen piirretty kuva ei automaattisesti pysy tallessa. AutoRedraw-ominaisuuden ollessa True Visual Basic huolehtii itse kuvan tallentamisesta ja palauttamisesta. Kuitenkaan AutoRedraw-ominaisuutta ei voi käyttää "ulkopuolisen" BitBlt-funktion kanssa. Siispä kuvan päivittämisestä tarvittaessa täytyy huolehtia itse. Tämä tapahtuu kuvakehyksen Paint-tapahtuma-aliohjelmassa:
Private Sub Form_Paint() 'annetaan hetki aikaa järjestelmälle... DoEvents '...ja piirretään koko pelitaso uudestaan PiirraTaso End Sub
Peli-ikkunan ylälaidassa näkyvät tason numero, puuttuvien jalokivien määrä sekä jäljellä oleva aika. Näiden tietojen päivittäminen tapahtuu NaytaTiedot-aliohjelman avulla:
Sub NaytaTiedot() 'NTaso on pelitaso, Jalokivet puuttuvien jalokivien määrä 'ja Aika jäljellä oleva aika; Space(43) vastaa 43 välilyöntiä jakija.lTiedot.Caption = NTaso & Space(43) & Jalokivet & Space(43) & Aika End Sub
Muuttujat, aliohjelmat ja funktiot kannattaa nimetä huolella. Näin ohjelman kulusta saa hyvän kuvan ilman kommenttejakin, ja kunnolliset nimet helpottavat itse ohjelmointiakin. Suomenkielisten nimien käyttäminen on muuten erinomainen idea.
Jokaisen formin ja moduulin alkuun on hyvä kirjoittaa Option Explicit. Määritys tarkoittaa sitä, että kaikki muuttujat on määriteltävä ennen niiden käyttöä. Tämä saattaa kuulostaa vaivalloiselta, jos niin ei ole ennen tehnyt, mutta vaiva kannattaa: kirjoitusvirheet muuttujien nimissä eivät enää aiheuta kummallisia virheitä ohjelmassa. Variant-tietotyyppiä – joka on määrittelemättömien muuttujien oletustyyppi – kannattaa välttää viimeiseen saakka. Tällaiset muuttujat vievät paljon tilaa muistissa ja niiden käsittely on hidasta. Muuttujan tyyppi täytyy valita aina käyttötarkoituksen mukaan.
Muuttujat, jotka on määritelty moduulissa Public- tai Global-avainsanan avulla, ovat käytössä kaikissa ohjelman formeissa ja moduuleissa. Muuttujat, jotka on määritelty Private- tai Dim-avainsanan avulla ovat käytössä ainoastaan samassa formissa tai moduulissa. Sama pätee WinAPI-määrittelyihin, vakioihin, aliohjelmiin ja funktioihin. Jos aliohjelman tai funktion sisällä määrittelee muuttujan Static-avainsanalla, muuttujan arvo säilyy kutsukertojen välillä.
lainaus:
Public Const SRCCOPY = &HCC0020x
Se väittää tuota "Const" -sanaa vääräksi. Miten tuonkin ongelman pystyy ratkaisemaan?
jaa empä tiiä... kandies ehkä koittaa pelin tekoo cool basicilla ja kartat tilesterillä. (tilester tulee mukana)
sami m, mikä vb sulla on? kai nyt vakiot pitäisi olla mahdollisia...
pitää vääntää qbeelle UGLlän kans
Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.