Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: EppaBasic: 3D-animaatio

fergusq [30.07.2016 22:48:50]

#

Tässä pieni animaatio, jonka huvikseni väsäsin EppaBasicilla. Siinä pienet pyramidinmalliset sirut lentävät käyttäjää päin. Ne piirretään käyttäen hyväksi kirjastoa, jonka nimesin "EppaGL":ksi.

Alunperin tarkoituksenani oli tehdä jotain isompaa kuten esimerkiksi peli tai monimutkaisempi demo, mutta kielen rajoitukset tulivat taas vastaan: kieli ei tue taulukkoparametreja eikä edes funktion sisällä määriteltyjä paikallisia taulukoita, joten pistejoukkojen käsittely on vähintäänkin hankalaa. En jaksanut tällä erää miettiä mitään hyvää tapaa niitä varten.

Koska EB ei tue vaihtelevankokoisia tauluja, sisältää tämä ohjelma oman toteutukseni niistä (taulut EGL_KOLMIOT ja EGL_VAPAAT). Toisessa taulussa säilytetään itse dataa ja toinen on pino käyttämättömistä indekseistä ensimmäisessä taulussa.

Puutteistaan huolimatta kieli sopii kuitenkin jo nyt kehitysvaiheessaan hyvin pienten pelien väsäämiseen, joten saatan silti jossakin vaiheessa julkaista vielä jonkin hienomman 3D-ohjelman, kunhan ratkon ongelmat pistejoukkojen kanssa.

Ohjelmaa voi kokeilla osoitteessa http://eppabasic.fi/#ZZ7LHP tai kopioimalla koodin suoraan editoriin, jos ensimmäinen linkki ei toimi.

' Animaatio EppaBasicilla
' (c) Iikka Hauhio 2016

' Tiedosto koostuu kahdesta osasta: EppaGL-grafiikkakirjastosta ja sitä hyödyntävästä animaatiosta

''''''''''''''''''''''''''''''''''''''''''
''' EppaGL - 3D-kirjasto EppaBasicille '''
''''''''''''''''''''''''''''''''''''''''''

'' Muuttujadeklaraatiot ''

Dim EGL_H As Number = 100

' Kameran sijainti
Dim EGL_VX As Number = 0
Dim EGL_VY As Number = 0
Dim EGL_VZ As Number = 0

' Kameran kulma
Dim EGL_KX As Number = 0
Dim EGL_KY As Number = 0

'' Apufunktiot ''

Function EGL_KäännäXY(xy As Number, z As Number, kulma As Number) As Number
    Return xy*Cos(kulma)-z*Sin(kulma)
End Function

Function EGL_KäännäZ(xy As Number, z As Number, kulma As Number) As Number
    Return xy*Sin(kulma)+z*Cos(kulma)
End Function

Function EGL_LaskeSiirrosSyvyydessä(x_tai_y As Number, z As Number) As Number
    Return EGL_H*x_tai_y/z
End Function

' Laskee pisteen ruudulle tehdyn projektion X-koordinaatin
Function EGL_LaskeSiirrosX(x As Number, z As Number) As Number
    Dim uusiX = x-EGL_VX
    Dim uusiZ = z-EGL_VZ
    uusiX = EGL_KäännäXY(uusiX, uusiZ, EGL_KY)
    uusiZ = EGL_KäännäZ(uusiX, uusiZ, EGL_KY)
    Return CanvasWidth()/2+EGL_LaskeSiirrosSyvyydessä(uusiX, uusiZ)
End Function

' Laskee pisteen ruudulle tehdyn projektion Y-koordinaatin
Function EGL_LaskeSiirrosY(y As Number, z As Number) As Number
    Dim uusiY = y-EGL_VY
    Dim uusiZ = z-EGL_VZ
    uusiY = EGL_KäännäXY(uusiY, uusiZ, EGL_KX)
    uusiZ = EGL_KäännäZ(uusiY, uusiZ, EGL_KX)
    Return CanvasHeight()/2-EGL_LaskeSiirrosSyvyydessä(uusiY, uusiZ)
End Function

'' Varsinainen rajapinta ''

' Siirtää kameraa
Sub EGL_Kamera(x As Number, y As Number, z As Number, kulmaX As Number, kulmaY As Number)
    EGL_VX = x
    EGL_VY = y
    EGL_VZ = z
    EGL_KX = kulmaX
    EGL_KY = kulmaY
End Sub

' Kolmioiden maksimimäärä
DIM EGL_KPL_LKM = 200

' Kolmiot sisältävä taulu
Dim EGL_KOLMIOT As Number[EGL_KPL_LKM, 9]

' Indeksejä eri arvoille kolmiotaulussa
Dim EGL_X1 = 1
Dim EGL_Y1 = 2
Dim EGL_Z1 = 3
Dim EGL_X2 = 4
Dim EGL_Y2 = 5
Dim EGL_Z2 = 6
Dim EGL_X3 = 7
Dim EGL_Y3 = 8
Dim EGL_Z3 = 9

' Lista vapaista paikoista taulussa uusia kolmioita varten
Dim EGL_VAPAAT As Number[EGL_KPL_LKM]
EGL_VAPAAT[1] = 1
Dim EGL_LASKURI As Integer = 1

' Etsii vapaan paikan taulusta
Function EGL_UusiId() As Integer
    Dim id = EGL_VAPAAT[EGL_LASKURI]
    If EGL_LASKURI = 1 Then
        EGL_VAPAAT[1] = EGL_VAPAAT[1]+1
    Else
        EGL_LASKURI = EGL_LASKURI-1
    End If
    Return id
End Function

' Luo ja alustaa uuden kolmion
Function EGL_LisääKolmio() As Integer
    Dim id = EGL_UusiId()
    EGL_MuutaKolmiota(id, 0, 0, 0, 0, 0, 0, 0, 0, 0)
    Return id
End Function

' Muuttaa kolmion sijaintia
Sub EGL_MuutaKolmiota(id As Integer, x1 As Number, y1 As Number, z1 As Number, x2 As Number, y2 As Number, z2 As Number, x3 As Number, y3 As Number, z3 As Number)
    EGL_KOLMIOT[id, EGL_X1] = x1
    EGL_KOLMIOT[id, EGL_Y1] = y1
    EGL_KOLMIOT[id, EGL_Z1] = z1
    EGL_KOLMIOT[id, EGL_X2] = x2
    EGL_KOLMIOT[id, EGL_Y2] = y2
    EGL_KOLMIOT[id, EGL_Z2] = z2
    EGL_KOLMIOT[id, EGL_X3] = x3
    EGL_KOLMIOT[id, EGL_Y3] = y3
    EGL_KOLMIOT[id, EGL_Z3] = z3
End Sub

' Poistaa kolmion ja vapauttaa kohdan taulussa
Sub EGL_PoistaKolmio(id As Integer)
    EGL_MuutaKolmiota(id, 0, 0, 0, 0, 0, 0, 0, 0, 0)
    EGL_LASKURI = EGL_LASKURI + 1
    EGL_VAPAAT[EGL_LASKURI] = id
End Sub

' Piirtää kolmiot ruudulle
Sub EGL_PiirräKolmiot()
    For id = 1 To EGL_VAPAAT[1] - 1
        Dim x1 = EGL_LaskeSiirrosX(EGL_KOLMIOT[id, EGL_X1], EGL_KOLMIOT[id, EGL_Z1])
        Dim y1 = EGL_LaskeSiirrosY(EGL_KOLMIOT[id, EGL_Y1], EGL_KOLMIOT[id, EGL_Z1])
        Dim x2 = EGL_LaskeSiirrosX(EGL_KOLMIOT[id, EGL_X2], EGL_KOLMIOT[id, EGL_Z2])
        Dim y2 = EGL_LaskeSiirrosY(EGL_KOLMIOT[id, EGL_Y2], EGL_KOLMIOT[id, EGL_Z2])
        Dim x3 = EGL_LaskeSiirrosX(EGL_KOLMIOT[id, EGL_X3], EGL_KOLMIOT[id, EGL_Z3])
        Dim y3 = EGL_LaskeSiirrosY(EGL_KOLMIOT[id, EGL_Y3], EGL_KOLMIOT[id, EGL_Z3])
        DrawTriangle x1, y1, x2, y2, x3, y3
    Next id
End Sub

''''''''''''''''''''''
''' SIRU-ANIMAATIO '''
''''''''''''''''''''''

' Vaihda vastaamaan oman näyttösi mittoja
Dim WIN_SIZE_X = 1600
Dim WIN_SIZE_Y = 800

' Sirujen liikkumisnopeus
Dim NOPEUS = 0.5

' Sirujen kokonaismäärä. Tämän kasvattaminen saattaa vaatia myös
' kolmiomäärän kasvattamista eli muuttujan EGL_KPL_LKM muuttamista
Dim SIRUJA = 50

' Taulukko siruista
Dim SIRUT As Number[SIRUJA, 8]

' Alustetaan kaikki sirut satunnaisiin paikkoihin
For i = 1 To SIRUJA
    SIRUT[i, 1] = EGL_LisääKolmio() ' Sivu 1
    SIRUT[i, 2] = EGL_LisääKolmio() ' Sivu 2
    SIRUT[i, 3] = EGL_LisääKolmio() ' Sivu 3
    SatunnaistaSiru i
Next i

' Arvotaan annetulle sirulle uusi paikka
Sub SatunnaistaSiru(id As Integer)
    ' Siruja asetetaan siten, että niitä esiintyy vain näytön keskellä olevan
    ' suorakulmion sisällä, jonka reunat ovat kolmasosa ikkunan reunoista
    Dim areaSizeX = WIN_SIZE_X*0.3
    Dim areaSizeY = WIN_SIZE_Y*0.3
    SIRUT[id, 4] = Rnd()*areaSizeX-areaSizeX/2 ' X
    SIRUT[id, 5] = Rnd()*areaSizeY-areaSizeY/2 ' Y
    SIRUT[id, 6] = 100 + Rnd()*100 ' Z
    SIRUT[id, 7] = Rnd() ' Kulma X
    SIRUT[id, 8] = Rnd() ' Kulma Y
End Sub

' Siirtää sirun kolmioita
Sub Siirrä(id As Integer)
    ' Sirun 3D-malli             Skaalaus
    Dim p1x As Number = -0.5     *2
    Dim p1y As Number = -0.44    *2
    Dim p1z As Number = 0        *2
    Dim p2x As Number = 0.5      *2
    Dim p2y As Number = -0.44    *2
    Dim p2z As Number = 0        *2
    Dim p3x As Number = 0        *2
    Dim p3y As Number = 0.44     *2
    Dim p3z As Number = 0        *2
    Dim p4x As Number = 0        *2
    Dim p4y As Number = 0        *2
    Dim p4z As Number = 0.44     *2

    ' Nykyinen sijainti
    Dim x = SIRUT[id, 4]
    Dim y = SIRUT[id, 5]
    Dim z = SIRUT[id, 6]
    Dim kx = SIRUT[id, 7]
    Dim ky = SIRUT[id, 8]

    ' Pyöritetään 3D-mallia
    p1x = EGL_KäännäXY(p1x, p1z, ky)
    p2x = EGL_KäännäXY(p2x, p2z, ky)
    p3x = EGL_KäännäXY(p3x, p3z, ky)
    p4x = EGL_KäännäXY(p4x, p4z, ky)
    p1y = EGL_KäännäXY(p1y, p1z, kx)
    p2y = EGL_KäännäXY(p2y, p2z, kx)
    p3y = EGL_KäännäXY(p3y, p3z, kx)
    p4y = EGL_KäännäXY(p4y, p4z, kx)

    p1z = EGL_KäännäZ(p1x, p1z, ky)
    p2z = EGL_KäännäZ(p2x, p2z, ky)
    p3z = EGL_KäännäZ(p3x, p3z, ky)
    p4z = EGL_KäännäZ(p4x, p4z, ky)
    p1z = EGL_KäännäZ(p1y, p1z, kx)
    p2z = EGL_KäännäZ(p2y, p2z, kx)
    p3z = EGL_KäännäZ(p3y, p3z, kx)
    p4z = EGL_KäännäZ(p4y, p4z, kx)

    ' Asetetaan koordinaatit oikein
    EGL_MuutaKolmiota SIRUT[id, 1], x+p1x, y+p1y, z+p1z, x+p2x, y+p2y, z+p2z, x+p3x, y+p3y, z+p3z
    EGL_MuutaKolmiota SIRUT[id, 2], x+p1x, y+p1y, z+p1z, x+p2x, y+p2y, z+p2z, x+p4x, y+p4y, z+p4z
    EGL_MuutaKolmiota SIRUT[id, 3], x+p1x, y+p1y, z+p1z, x+p4x, y+p4y, z+p4z, x+p3x, y+p3y, z+p3z
End Sub

WindowSize WIN_SIZE_X, WIN_SIZE_Y
CanvasSize WIN_SIZE_X, WIN_SIZE_Y

DrawColor 255, 255, 255

' Pääsilmukka
Do
    ' Liikutetaan kaikkia siruja
    For id = 1 To SIRUJA
        Dim z = SIRUT[id, 6]
        ' Jos siru on mennyt ohi kamerasta, siirretään takaisin alkuun satunnaiseen paikkaan
        If z < 2 Then
            z = z + 100
            SatunnaistaSiru id
        End If
        ' Liikutetaan syvyydessä
        SIRUT[id, 6] = z - NOPEUS

        Siirrä id
    Next id

    ' Piirretään sirut näytölle
    ClearScreen
        EGL_PiirräKolmiot
    DrawScreen
Loop

Vastaus

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

Tietoa sivustosta