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 SubKun 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 FunctionDir-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 SubPelitason 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 SubEsimerkiksi 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.