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.