Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: VB6: Yksinkertainen 3D-sokkelo

Sivun loppuun

sqwiik [17.03.2007 23:16:11]

#

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 Sub

Formin 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 Sub

kentta1.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

Antti Laaksonen [18.03.2007 00:23:22]

#

Koodi toimii suoraan VB6:lla, mutta tärkeää on vaihtaa formin ja kuvien mittayksiköksi pikseli (ScaleMode-ominaisuus). Kelpo koodivinkki muuten!

sqwiik [18.03.2007 13:37:25]

#

Tack tack. Kannattaisikohan laittaa myös se SDL-versio? Tai no, se on sitten se suomipelit.com:iin tehty pikapeli...

msdos464 [21.03.2007 09:53:57]

#

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.

sqwiik [21.03.2007 16:59:08]

#

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.

moptim [21.03.2007 20:38:10]

#

Nice.

msdos464 [22.03.2007 08:28:16]

#

Ah aivan.. fiksua :)

moptim [23.03.2007 15:59:13]

#

1337!

moptim [25.03.2007 17:40:11]

#

Ja laita se SDL-versio!


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta