Päätin tässä suomipelit.comin projektissa (peli päivässä), että opettelen edes jollain tavalla 3D-pelien saloja. Samalla tuli mietittyä että millä tavalla muinaisten pelien yksinkertaiset 3D-sokkelot oli oikein toteutettu; päädyin lopulta paperilla piirtelyn & suunnittelun sekä piirroksistani johdetuista kaavoista seuraavaan tuotokseen.
Eli, kyseessä on hyvin yksinkertainen, 4 suunnan 3D-sokkeloengine joka lataa karttansa tiedostosta. Seinät on väritetty etäisyytensä mukaan eri väreillä (voi vaihtaa). Teksturointi olisi ollut ehkä myös helppoa, mutta innostus loppui. Lisäksi tämä on fiksattu tietyyn näkösyvyyteen (näkee 4 askeleen päähän), ja tiettyjä arvoja on laskettu etukäteen taulukoihin kaiken nopeuttamiseksi (vaikkakin laskut tässä eivät monimutkaisuudellaan päätä huimaa); tuntujma on todellakin vähän kuin muinaisissa DOS-RPG-peleissä. Muokkaamalla voi tehdä ihmeitä ^_-.
Kenttä koostuu Integer-taulukosta, jonka 4 alinta bittiä kuvaavat seinien olemassaoloa. Ovet yms. voisivat sitten olla seuraavat 4 bittiä/tms.
Pitemmittä puheitta, there you go.Saa käyttää & parannella mielensä mukaan.
Tein tästä saman päivänä myös SDL:ää käyttävän version, jossa on myös monsusysteemi. Postitan sen ehkä myöhemmin.
HUOM! Kirjoitettu VB3:lla; vaatinee suuriakin muokkauksia uudemmille versioille. Ja lisäksi pahoittelen kommenttien suurta puutetta.
Formille:
PictureBox kuva; 320x320 pixel
PictureBox minwin; 160x160 pixel
CommanButton Command1
Formin KeyPreview = True
Näppäimiä
Vasen, oikea: käänny
Ylös: askel eteenpäin
Edit - lisätty vähäsen kommentteja
MAIN.FRM - formin kooditiedosto
'' Yleisiä muuttujia
Option Explicit
DefInt A-Z
Const MaXX = 8, MaXY = 8
' Bittikuviot
Const YlaSeina = 1, OikeaSeina = 2, AlaSeina = 4, VasenSeina = 8
Const Syvyys = 4
Dim Shared Kentta(1 To MaXX, 1 To MaXY) As Integer
Dim Shared Suunta, HX, HY, PiirJar(4), Maara(Syvyys)
Dim Shared DepCol(Syvyys) As Long
Sub FillVertical (bb As PictureBox, x1 As Integer, x2 As Integer, y1 As Integer, y2 As Integer, h1 As Integer, col As Long)
'' Täyttää nelikulmion tietyllä värillä; itse keksaistu koodi.
'' Melko nopea.
Dim ym As Double, x, xm, w
ym = CDbl(Abs(y2 - y1)) / CDbl(x2 - x1)
xm = Sgn(x2 - x1): w = (x2 - x1)
For x = 0 To w Step xm
bb.Line (x1 + x, y1 - (x * ym))-(x1 + x, y1 + h1 + (x * ym)), col
Next x
End Sub
Sub LataaKentta (tied As String)
'' Lataa kentän tiedostosta
Dim a, B, ff
ff = FreeFile
Open tied For Input As #ff
For a = 1 To MaXY: For B = 1 To MaXX
Input #ff, Kentta(B, a)
Next B
Next a
Close #ff
'' Tässä jäi ~kesken; katselupiste ja sen suunta.
HX = 4: HY = 4
Suunta = 2
End Sub
Sub Liiku ()
' Liikutaan suuntaan <Suunta>.
Dim xm, ym, a
xm = 0: ym = 0
Select Case Suunta
Case 0
ym = -1
a = 2
Case 1
xm = 1
a = 3
Case 2
ym = 1
a = 0
Case 3
xm = -1
a = 1
End Select
' Este?
If (Kentta(HX, HY) And (2 ^ Suunta)) <> 0 Then Exit Sub
' Rajan yli?
If HX + xm < 1 Or HX + xm > MaXX Or HY + ym < 1 Or HY + ym > MaXY Then
Exit Sub
End If
' ..este toiselta puolelta?
If (Kentta(HX + xm, HY + ym) And (2 ^ a)) <> 0 Then Exit Sub
HX = HX + xm: HY = HY + ym
End Sub
Sub Paivita ()
'' Piirtosuuntien & karttojen päivitystä suunnan mukaan.
Select Case Suunta
Case 0
PiirJar(0) = 1: PiirJar(1) = 8
PiirJar(2) = 2: PiirJar(3) = 4
Case 1
PiirJar(0) = 2: PiirJar(1) = 1
PiirJar(2) = 4: PiirJar(3) = 8
Case 2
PiirJar(0) = 4: PiirJar(1) = 2
PiirJar(2) = 8: PiirJar(3) = 1
Case 3
PiirJar(0) = 8: PiirJar(1) = 4
PiirJar(2) = 1: PiirJar(3) = 2
End Select
Kuva.Cls
MinWin.Cls
Piirrakentta3D Kuva
PiirraKenttaMin
End Sub
Sub Piirrakentta3D (MScreen As PictureBox)
'' Kaiken ydin - piirrä näkymä false 3D:nä.
'' Rautalankamalli: ota kommentit pois Line-käskyistä
'' ja kommentoi FillVertical-käsky.
Dim x, y, xx, yy, xm, ym, w, h, a, kx, ky, mw, mh
Dim B, xx2, yy2, mw2, mh2, pala, W2, h2
Dim kier, col As Long
xm = 0: ym = 0
col = QBColor(1)
'' Piirtosuunta
Select Case Suunta
Case 0: ym = -1
Case 1: xm = 1
Case 2: ym = 1
Case 3: xm = -1
End Select
'' Piirron alkuarvoja; palikoiden leveyksiä ja korkeuksia
w = MScreen.Width / 16
h = MScreen.Height / 16
W2 = w / 2: h2 = h / 2
kx = w * 8: ky = h * 8
' Rivit (takaa eteen)
For a = Syvyys - 1 To 0 Step -1
If ym <> 0 Then
y = HY + (a * ym): x = HX
Else
x = HX + (a * xm): y = HY
End If
mw = w * (2 ^ (Syvyys - a - 1)): mh = h * (2 ^ (Syvyys - a - 1))
mw2 = w * (2 ^ (Syvyys - a)): mh2 = h * (2 ^ (Syvyys - a))
yy = ky - (h2 * (2 ^ (Syvyys - a - 1)))
yy2 = ky - (h2 * (2 ^ (Syvyys - a)))
For B = -Maara(a) To Maara(a)
' Onko ruutu kentällä?
If (B + x > 0 And B + x <= MaXX And y > 0 And y <= MaXY And ym <> 0) Or (B + y > 0 And B + y <= MaXY And x > 0 And x <= MaXX And xm <> 0) Then
' Kierrä seinät järjestyksessä: taka, vasen, oikea, etu
xx = kx - (W2 * (2 ^ (Syvyys - a - 1)))
xx2 = kx - (W2 * (2 ^ (Syvyys - a)))
If ym < 0 Or xm > 0 Then
xx = xx + (B * mw)
xx2 = xx2 + (B * mw2)
Else
xx = xx - (B * mw)
xx2 = xx2 - (B * mw2)
End If
'' Piirretään seinät järjestyksessä
For kier = 0 To 3
If ym <> 0 Then pala = Kentta(B + x, y) Else pala = Kentta(x, B + y)
If pala And PiirJar(kier) Then
Select Case kier
Case 0 ' takaseinä
MScreen.Line (xx, yy)-(xx + mw, yy + mh), DepCol(a), BF
Case 1 ' vasen seinä
' MScreen.Line (xx, yy)-(xx2, yy2), DepCol(a)
' MScreen.Line (xx, yy + mh)-(xx2, yy2 + mh2), DepCol(a)
' MScreen.Line (xx2, yy2)-(xx2, yy2 + mh2), DepCol(a)
' MScreen.Line (xx, yy)-(xx, yy + mh), DepCol(a)
FillVertical MScreen, xx, xx2, yy, yy2, mh, DepCol(a)
Case 2 ' oikea seinä
' MScreen.Line (xx + mw, yy)-(xx2 + mw2, yy2), DepCol(a)
' MScreen.Line (xx + mw, yy + mh)-(xx2 + mw2, yy2 + mh2), DepCol(a)
' MScreen.Line (xx2 + mw2, yy2)-(xx2 + mw2, yy2 + mh2), DepCol(a)
' MScreen.Line (xx + mw, yy)-(xx + mw, yy + mh), DepCol(a)
FillVertical MScreen, xx + mw, xx2 + mw2, yy, yy2, mh, DepCol(a)
Case 3 ' etuseinä
If a <> 0 Then MScreen.Line (xx2, yy2)-(xx2 + mw2, yy2 + mh2), DepCol(a), BF
End Select
End If
Next
End If
Next B
Next a
End Sub
Sub PiirraKenttaMin ()
'' Minikartta.
Dim w, h, x, y, col As Long
col = QBColor(1)
w = MinWin.Width / MaXX
h = MinWin.Height / MaXY
MinWin.Cls
'' Piirretään viiva, jos seinä on olemassa.
For y = 1 To MaXY: For x = 1 To MaXX
If Kentta(x, y) And YlaSeina Then MinWin.Line ((x - 1) * w, (y - 1) * h)-(x * w, (y - 1) * h), col
If Kentta(x, y) And OikeaSeina Then MinWin.Line (x * w, (y - 1) * h)-(x * w, y * h), col
If Kentta(x, y) And AlaSeina Then MinWin.Line ((x - 1) * w, y * h)-(x * w, y * h), col
If Kentta(x, y) And VasenSeina Then MinWin.Line ((x - 1) * w, (y - 1) * h)-((x - 1) * w, y * h), col
Next x
Next y
'' Piirrä katselupiste & suunta
MinWin.Circle ((HX - 1) * w + (w / 2), (HY - 1) * h + (h / 2)), w / 5, col
Select Case Suunta
Case 0: MinWin.Circle ((HX - 1) * w + (w / 2), (HY - 1) * h + (h / 2) - 5), 2, col
Case 1: MinWin.Circle ((HX - 1) * w + (w / 2) + 5, (HY - 1) * h + (h / 2)), 2, col
Case 2: MinWin.Circle ((HX - 1) * w + (w / 2), (HY - 1) * h + (h / 2) + 5), 2, col
Case 3: MinWin.Circle ((HX - 1) * w + (w / 2) - 5, (HY - 1) * h + (h / 2)), 2, col
End Select
End SubFormin objektien koodit
Sub Command1_Click ()
LataaKentta app.Path & "\kentta1.txt"
Paivita
End Sub
Sub Form_Load ()
'' Initiaatiohässäkkä
' Perspektiivi...
Maara(0) = 1: Maara(1) = 2: Maara(2) = 4: Maara(3) = 8
'' Eri syvyyksien värit; muuttaa saa ja sopii
DepCol(0) = RGB(128, 128, 128): DepCol(1) = RGB(64, 64, 64)
DepCol(2) = RGB(32, 32, 32): DepCol(3) = RGB(0, 0, 0)
End Sub
Sub Form_KeyDown (KeyCode As Integer, Shift As Integer)
'' Näppäimet
Select Case KeyCode
Case 37
Suunta = Suunta - 1
If Suunta < 0 Then Suunta = 3
Paivita
Case 39
Suunta = Suunta + 1
If Suunta > 3 Then Suunta = 0
Paivita
Case 38
Liiku
Paivita
End Select
End Subkentta1.txt
0, 0, 1, 10, 1, 1, 0, 0 1, 15, 15, 10, 0, 1, 3, 0 0, 1, 0, 10, 0, 0, 2, 0 0, 15, 0, 0, 5, 5, 5, 0 0, 8, 0, 1, 0, 0, 2, 0 4, 15, 0, 0, 0, 0, 2, 0 4, 12, 4, 15, 4, 4, 6, 0 0, 4, 4, 0, 0, 0, 0, 0
Koodi toimii suoraan VB6:lla, mutta tärkeää on vaihtaa formin ja kuvien mittayksiköksi pikseli (ScaleMode-ominaisuus). Kelpo koodivinkki muuten!
Tack tack. Kannattaisikohan laittaa myös se SDL-versio? Tai no, se on sitten se suomipelit.com:iin tehty pikapeli...
Miten tuo kentta1.txt on määritelty? Tähän mennessä on tullut tutuksi perus ruudukko mappi, tuo taitaa olla enempi niitä matriisi hommia? :)
Missä olisi joku hyvä opas tällaiseen? Joskus vuosi sitten jotain katselin, mutta sillon meni vähän yli hilseen. Nyt varmaan onnistuisi paremmin.
Kenttä on määritelty siten, että luku kuvastaa ruudussa olevien seinien olemassaoloa.
Yksi bitti/seinä eli 1, 2, 4, 8 (binääriliput). Järjestys kiertää myötäpäivään; 1 = yläseinä, 2 = oikea seinä, 4 = alaseinä ja 8 = vasen seinä.
15 = 1+2+4+8 = suljettu laatikko. Mutta että tarkistus toimisi molempiin suuntiin, täytyy vierekkäisten ruutujen seinien täsmätä. Muuten seinästä pääsee läpi määrittelemättömältä puolelta.
Nice.
Ah aivan.. fiksua :)
1337!
Ja laita se SDL-versio!
Aihe on jo aika vanha, joten et voi enää vastata siihen.