endlose Maps in 2D

Übersicht BlitzBasic Allgemein

Neue Antwort erstellen

garret

Betreff: endlose Maps in 2D

BeitragSa, Apr 18, 2009 14:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Hey. Innerhalb des letzten Jahres habe ich immer wieder mal (bin jetzt beim siebenten Neuansatz Wink) versucht, eine unendlich große Karte zu realisieren. Das Prinzip dabei ist natürlich, dass mehrere kleine aneinander gereiht werden. Da mir das aber inzwischen immer noch nicht gelungen ist und ich langsam die Schnauze voll habe, zeige ich euch mal meinen Code, in der Hoffnung, dass ihr mir entweder einen besseren Ansatz oder die Fehler in meinem zeigt.

Kurz zur Erläuterung: Der Gesamtbildschirm kann immer aus höchstens vier Teilkarten bestehen. diese tragen die Namen Mitte, Rechts, Unten, Rechts_Unten und werden in einem großen Dim-Feld gespeichert. Statt bei einer Bewegung jedes Mal alle Karten neu einlesen zu müssen, habe ich mir gedacht, dass man praktisch nur die Zuweisung ändert. Wenn ich mich also nach rechts bewege und die Feldgrenzen überschreite, wird mein Feld_Rechts ja mein neues Feld_Mitte. Dieses hatte vorher die Zuweisung 0, sodass beim Lesen auf Feld(0,x,y) zugegriffen wird. Da die Daten für Feld_Rechts in 1 gespeichert sind, bekommt Feld_Mitte jetzt die 1 zugewiesen und es wird fortan auf Feld(1,x,y) zugegriffen. Die Zuweisung wechselt bei einer Bewegung nach Rechts also immer zwischen 0 und 1 bei Feld_Mitte und Feld_Rechts, und zwischen 2 und 3 bei Feld_Unten und Feld_Rechts_Unten.

Mein Problem liegt nun darin, dass bei manchen Bewegungen falsch gelesen wird, das heißt, es werden Reste der alten Karte gezeichnet.

Hoffe, das war wenigstens ein bisschen verständlich. Das Prinzip ist jedenfalls einfach und sollte beim Test ersichtlich sein. Wenn nicht fragt Smile

Das Paket inklusive Testkarten und 2 Grafiken (mit und ohne Bezifferung) ist hier zu finden: https://www.blitzforum.de/upload/file.php?id=5331


Der Code:
Code: [AUSKLAPPEN]
;####################################################################################################

; Aneinanderreihen mehrerer Maps um den Eindruck einer großen zu erzeugen

;####################################################################################################
;####################################################################################################
; Variablen
gGraphicsWidth=1024
gGraphicsHeight=768
Graphics gGraphicsWidth,gGraphicsHeight,32,2



Const cTILESIZE = 16   ; Größe der Tiles
Const gXmax = 199      ; max. Spalten pro Datei
Const gYmax = 199      ; max. Zeilen pro Datei


Global gFeld_Mitte = 0         ; relative Zuweisung der Felder
Global gFeld_Rechts = 1
Global gFeld_Unten = 2
Global gFeld_Rechts_Unten = 3

Global max_x_tiles = gGraphicsWidth / cTILESIZE      ; Anzahl der maximal gleichzeitig anzeigbaren tiles
Global max_y_tiles = gGraphicsHeight / cTILESIZE
Global vx = -160, vy = -180                     ; Verschiebung der Karte (immer <= 0)

Global sektor_x = 1; die momentan aktiven Sektoren
Global sektor_y = 0

IMG_Tiles = LoadAnimImage("test16_2.png", cTILESIZE, cTILESIZE, 0, 16)      ;das Bild, das die Einzel-Tiles enthält
Local IMG_Background      ; Bild, das zusammengesetzt den Hintergrund darstellt


Dim Feld(3, gXmax, gYmax)

t = MilliSecs(); zur Zeitmessung


;####################################################################################################
; Felder einlesen siehe Funktion Map_Einlesen

Map_Einlesen(gFeld_Mitte)
Map_Einlesen(gFeld_Rechts)
Map_Einlesen(gFeld_Unten)
Map_Einlesen(gFeld_Rechts_Unten)


;####################################################################################################
   ; das eigentliche Hintergrundbild erstellen
   IMG_Background = CreateImage(gGraphicsWidth, gGraphicsHeight)
   SetBuffer ImageBuffer(IMG_Background)
   
   ; Je nach Verschiebung der Karte (aus Speicherstand geladen) werden Teile aus bestimmten Feldern gebraucht
   
   If (-vx + max_x_tiles) <= gXmax
   
      ; nur Feld Mitte (Fall 1)
      If (max_y_tiles -vy) <= gYmax
      
         For i = 0 To (max_x_tiles - 1)
         
            For j = 0 To (max_y_tiles - 1)
         
               DrawBlock IMG_Tiles, i * cTILESIZE, j * cTILESIZE, Feld(gFeld_Mitte, i - vx, j - vy)

            Next
            
         Next
      
      ; Feld Mitte und Feld Unten (Fall 2)
      ElseIf (max_y_tiles - vy) > gYmax
      
         For i = 0 To (max_x_tiles - 1)
         
            ; Teil von Feld Mitte (oberer Teil)
            For j = 0 To (gYmax + vy);
                        
               DrawBlock IMG_Tiles, i * cTILESIZE, j * cTILESIZE, Feld(gFeld_Mitte, i - vx, j - vy)
               
            Next
            
            ; Teil von Feld Unten (unterer Teil)
            For j = 0 To ((max_y_tiles - 1) - (gYmax + vy))
            
               DrawBlock IMG_Tiles, i * cTILESIZE, (j + gYmax + vy) * cTILESIZE, Feld(gFeld_Unten, i - vx, j)
               
            Next
            
         Next      
      
      EndIf
   
   ElseIf (max_x_tiles - vx) > gXmax
   
      ; Feld Mitte und Feld Rechts (Fall 3)
      If (-vy + max_y_tiles) <= gYmax
      
         For j = 0 To (max_y_tiles - 1)
         
            ; Teil von Feld Mitte
            For i = 0 To (gXmax + vx)
            
               DrawBlock IMG_Tiles, i * cTILESIZE, j * cTILESIZE, Feld(gFeld_Mitte, i - vx, j - vy)
               
            Next
            
            ; Teil von Feld Rechts
            For i = 0 To ((max_x_tiles - 1) - (gXmax + vx))
            
               DrawBlock IMG_Tiles, (i + gXmax + vx) * cTILESIZE, j * cTILESIZE, Feld(gFeld_Rechts, i, j - vy)
               
            Next
            
         Next
      
      ; Teile aller vier Felder sichtbar (Fall 4)
      ElseIf (max_y_tiles - vy) > gYmax
      
         ; 1.) Teil von Feld Mitte und Feld Unten
         For i = 0 To (gXmax + vx)
         
            ; Teil von Feld Mitte (links oben)
            For j = 0 To (gYmax + vy)
            
               DrawBlock IMG_Tiles, i * cTILESIZE, j * cTILESIZE, Feld(gFeld_Mitte, i - vx, j - vy)
               
            Next
      
            ; Teil von Feld Unten (links unten)
            For j = 0 To ((max_y_tiles - 1) - (gYmax + vy))
            
               DrawBlock IMG_Tiles, i * cTILESIZE, (j + gYmax + vy) * cTILESIZE, Feld(gFeld_Unten, i - vx, j)
               
            Next
            
         Next
         
         ; 2.) Teil von Feld Rechts und Feld Rechts Unten
         For i = 0 To ((max_x_tiles - 1) - (gXmax + vx))

            ; Teil von Feld Rechts
            For j = 0 To (gYmax + vy)
            
               DrawBlock IMG_Tiles, (i + gXmax + vx) * cTILESIZE, j * cTILESIZE, Feld(gFeld_Rechts, i, j - vy)
            
            Next
         
            ; Teil von Feld Rechts Unten
            
            For j = 0 To ((max_y_tiles - 1) - (gYmax + vy))
            
               DrawBlock IMG_Tiles, (i + gXmax + vx) * cTILESIZE, (j + gYmax + vy) * cTILESIZE, Feld(gFeld_Rechts_Unten, i, j)

            Next
         
         Next
         
      EndIf
         
   EndIf
   
   DebugLog Str(MilliSecs()-t)+" ms:  Hintergrund erstellt."
   
   SetBuffer BackBuffer()


;####################################################################################################
Repeat : Cls

   ; Steuerung
   
   ; ############################################################

      ;Bewegung nach Rechts
      If KeyDown(205) Or JoyXDir() = 1
      
         vx = vx - 1; Verschiebung der Karte
         
         If -vx > gXmax
         
            ;Zuweisung ändern
            Tausch = gFeld_Rechts
            gFeld_Rechts = gFeld_Mitte
            gFeld_Mitte = Tausch
            
            Tausch = gFeld_Rechts_Unten
            gFeld_Rechts_Unten = gFeld_Unten
            gFeld_Unten = Tausch
            
   
            vx = 0
            sektor_x = sektor_x + 1
            
            ; verschobenen Feldern wieder neue Werte rechts und rechts unten zuweisen
            Map_Einlesen(gFeld_Rechts)
            Map_Einlesen(gFeld_Rechts_Unten)

         EndIf

         SetBuffer ImageBuffer(IMG_Background)
         ; der alte Bildschirm wird um eine Spalte verschoben und die neue Spalte drangezeichnet
         CopyRect cTILESIZE, 0, (max_x_tiles - 1) * cTILESIZE, max_y_tiles * cTILESIZE, 0, 0
         

         ; Feld Mitte sichtbar
         If -vx <= (gXmax - max_x_tiles)
         
            ; nur Feld Mitte sichtbar, Teil aus Feld Mitte ergänzen (Fall 1)
            If -vy <= (gYmax - max_y_tiles)
         
               For i = 0 To max_y_tiles;-vy To (-vy + max_y_tiles)

                  DrawBlock IMG_Tiles, (max_x_tiles) * cTILESIZE, (-vy + i) * cTILESIZE, Feld(gFeld_Mitte, (max_x_tiles) - vx, (-vy + i))

               Next
            
            ; + Feld Unten sichtbar, Feld Rechts aber nicht (Fall 2)
            ElseIf -vy > (gYmax - max_y_tiles)
            
               ;Teil des Feldes Mitte zeichnen (oberer Teil)
               For i = 0 To (gYmax + vy)

                  DrawBlock IMG_Tiles, (max_x_tiles) * cTILESIZE, i * cTILESIZE, Feld(gFeld_Mitte, (max_x_tiles) - vx, i - vy)

               Next
               
               ; Rest von Feld Unten dazuzeichnen (unterer Teil)
               For i = 0 To (max_y_tiles - (gYmax + vy))

                  DrawBlock IMG_Tiles, (max_x_tiles) * cTILESIZE, ((gYmax + vy) + i) * cTILESIZE, Feld(gFeld_Unten, (max_x_tiles) - vx, i)

               Next
            
            EndIf

         ; Feld Mitte + Feld Rechts sichtbar
         ElseIf -vx >= (gXmax - max_x_tiles)
         
            ; nur Feld Mitte und Feld Rechts sichtbar, Teil von Feld Rechts ergänzen (Fall 3)
            If -vy <= (gYmax - max_y_tiles)
         
               For i = 0 To max_y_tiles

                  DrawBlock IMG_Tiles, max_x_tiles * cTILESIZE, i * cTILESIZE, Feld(gFeld_Rechts, max_x_tiles - gXmax - vx, i - vy)

               Next
               
            ; Teile aller Felder sichtbar, Teil von Feld Rechts und Feld Unten Rechts ergänzen (Fall 4)
            ElseIf -vy > (gYmax - max_y_tiles)
            
               ;Teil des Feldes Rechts zeichnen (oberer Teil)
               For i = 0 To (max_y_tiles - (gYmax + vy))
   
                  DrawBlock IMG_Tiles, (max_x_tiles - 1) * cTILESIZE, i * cTILESIZE, Feld(gFeld_Rechts, (max_x_tiles - (gXmax + vx)), i )
               
               Next
                  
               ; Rest von Feld Rechts Unten dazuzeichnen (unterer Teil)
               For i = 0 To (max_y_tiles - (gYmax + vy))
   
                  DrawBlock IMG_Tiles, (max_x_tiles - 1) * cTILESIZE, (gYmax + vy + i) * cTILESIZE, Feld(gFeld_Rechts_Unten, (max_x_tiles - (gXmax + vx)), i )

               Next
               
            EndIf
            
         EndIf   
   
         SetBuffer BackBuffer()
         
      EndIf
      
      ; ############################################################
      
      ; Bewegung nach links
      If KeyDown(203) Or JoyXDir() = -1

         vx = vx + 1; Verschiebung der Karte
         
         If -vx < 0
         
            ;Zuweisung ändern * (Sternchen unten erläutert)
            Tausch = gFeld_Rechts
            gFeld_Rechts = gFeld_Mitte
            gFeld_Mitte = Tausch
            
            Tausch = gFeld_Rechts_Unten
            gFeld_Rechts_Unten = gFeld_Unten
            gFeld_Unten = Tausch
            
   
            vx = -gXmax
            sektor_x = sektor_x - 1
            
            ; verschobenen Feldern wieder neue Werte rechts und rechts unten zuweisen
            Map_Einlesen(gFeld_Mitte)
            Map_Einlesen(gFeld_Unten)

         EndIf
         

         SetBuffer ImageBuffer(IMG_Background)
         ; der alte Bildschirm wird um eine Spalte verschoben und die neue Spalte drangezeichnet
         CopyRect 0, 0, (max_x_tiles - 1) * cTILESIZE, max_y_tiles * cTILESIZE, cTILESIZE, 0
         
         
         ; nur Feld Mitte sichtbar, Teil aus Feld Mitte ergänzen (Fall 1 (und Fall 3))
         If -vy <= (gYmax - max_y_tiles)
      
            For i = 0 To max_y_tiles

               DrawBlock IMG_Tiles, 0, i * cTILESIZE, Feld(gFeld_Mitte, -vx, (i - vy))

            Next

         ; + Feld Unten sichtbar, Feld Rechts aber nicht (Fall 2 (und Fall 4))
         ElseIf -vy > (gYmax - max_y_tiles)
         
            ;Teil des Feldes Mitte zeichnen (oberer Teil)
            For i = 0 To (gYmax + vy); To max_y_tiles

               DrawBlock IMG_Tiles, 0, i * cTILESIZE, Feld(gFeld_Mitte, -vx, i - vy)

            Next
            
         ; Rest von Feld Unten dazuzeichnen (unterer Teil)
            For i = 0 To (max_y_tiles - (gYmax + vy))

               DrawBlock IMG_Tiles, 0, ((gYmax + vy) + i) * cTILESIZE, Feld(gFeld_Unten, -vx, i)

            Next
         
         EndIf
         
         ; Die Abfragen von Feld Mitte + Feld Rechts (Fall 3) sowie "alle Felder sichtbar" (Fall 4) entfallen hier,
         ; da die anzufügenden Tiles ausschließlich aus Feld Mitte und Feld Unten gelesen werden (aufgrund der
         ; Änderung der Zuweisung (mit * markiert)

         SetBuffer BackBuffer()
         
      EndIf

      ; ############################################################

      ;Bewegung nach Unten
      If KeyDown(208) Or JoyYDir() = 1
      
         vy = vy - 1; Verschiebung der Karte
         
         If -vy > gYmax
         
            ;Zuweisung ändern
            Tausch = gFeld_Unten
            gFeld_Unten = gFeld_Mitte
            gFeld_Mitte = Tausch
            
            Tausch = gFeld_Rechts_Unten
            gFeld_Rechts_Unten = gFeld_Rechts
            gFeld_Rechts = Tausch
            
   
            vy = 0
            sektor_y = sektor_y + 1
            
            ; verschobenen Feldern wieder neue Werte rechts und rechts unten zuweisen
            Map_Einlesen(gFeld_Unten)
            Map_Einlesen(gFeld_Rechts_Unten)

         EndIf
            
         SetBuffer ImageBuffer(IMG_Background)
         ; der alte Bildschirm wird um eine Spalte verschoben und die neue Spalte drangezeichnet
         CopyRect 0, cTILESIZE, max_x_tiles * cTILESIZE, (max_y_tiles - 1) * cTILESIZE, 0, 0
         
         ; Je nach Position der Spielfigur müssen verschiedene Teile des Feldes gezeichnet werden
         
         ; Feld Mitte sichtbar
         If -vx <= (gXmax - max_x_tiles)
         
            ; nur Feld Mitte sichtbar, Teil aus Feld Mitte ergänzen (Fall 1)
            If -vy <= (gYmax - max_y_tiles)
         
               For i = 0 To max_x_tiles

                  DrawBlock IMG_Tiles, (-vx + i) * cTILESIZE, (max_y_tiles) * cTILESIZE, Feld(gFeld_Mitte, (-vx + i), max_y_tiles -vy)

               Next
            
            ; + Feld Unten sichtbar, Feld Rechts aber nicht (Fall 2)
            ElseIf -vy > (gYmax - max_y_tiles)
               
               ; Teil von Feld Unten ergänzen
               For i = 0 To max_x_tiles

                  DrawBlock IMG_Tiles, i * cTILESIZE, (max_y_tiles) * cTILESIZE, Feld(gFeld_Unten, i - vx, (max_y_tiles - (gYmax + vy)))

               Next

            EndIf

         ; Feld Mitte + Feld Rechts sichtbar
         ElseIf -vx > (gXmax - max_x_tiles)
         
            ; nur Feld Mitte und Feld Rechts sichtbar, Teil von Feld Rechts ergänzen (Fall 3)
            If -vy <= (gYmax - max_y_tiles)

               ;Teil des Feldes Mitte zeichnen (linker Teil)
               For i = 0 To (gXmax + vx)

                  DrawBlock IMG_Tiles, i * cTILESIZE, (max_y_tiles) * cTILESIZE, Feld(gFeld_Mitte, i - vx, (max_y_tiles) - vy)

               Next
               
               ; Rest von Feld Rechts dazuzeichnen (rechter Teil)
               For i = 0 To (max_x_tiles - (gXmax + vx))

                  DrawBlock IMG_Tiles, ((gXmax + vx) + i) * cTILESIZE, (max_y_tiles) * cTILESIZE, Feld(gFeld_Rechts, i, (max_y_tiles - 1) - vy)

               Next

            ; Teile aller Felder sichtbar, Teil von Feld Unten und Feld Rechts Unten ergänzen (Fall 4)
            ElseIf -vy > (gYmax - max_y_tiles)

               ; Rest von Feld Unten dazuzeichnen (linker Teil)
               For i = 0 To ((max_x_tiles) - (gXmax + vx))
   
                  DrawBlock IMG_Tiles, i * cTILESIZE, (max_y_tiles) * cTILESIZE, Feld(gFeld_Unten, i, max_y_tiles - (gYmax + vy))

               Next
               
               ;Teil des Feldes Rechts Unten zeichnen (rechter Teil)
               For i = 0 To (max_x_tiles - (gXmax + vx))
   
                  DrawBlock IMG_Tiles, (gXmax + vx + i) * cTILESIZE, (max_y_tiles) * cTILESIZE,  Feld(gFeld_Rechts_Unten, i, max_y_tiles - (gYmax + vy))
               
               Next

            EndIf
            
         EndIf   
   
         SetBuffer BackBuffer()
         
      EndIf
      
      
      ; ############################################################
      
      ; Bewegung nach oben
      If KeyDown(200) Or JoyYDir()= -1


         vy = vy + 1; Verschiebung der Karte
         
         If -vy < 0
         
            ;Zuweisung ändern * (Sternchen unten erläutert)
            Tausch = gFeld_Unten
            gFeld_Unten = gFeld_Mitte
            gFeld_Mitte = Tausch
            
            Tausch = gFeld_Rechts_Unten
            gFeld_Rechts_Unten = gFeld_Rechts
            gFeld_Rechts = Tausch
            
   
            vy = -gYmax
            sektor_y = sektor_y - 1
            
            ; verschobenen Feldern wieder neue Werte rechts und rechts unten zuweisen
            Map_Einlesen(gFeld_Mitte)
            Map_Einlesen(gFeld_Rechts)

         EndIf
         

         SetBuffer ImageBuffer(IMG_Background)
         ; der alte Bildschirm wird um eine Spalte verschoben und die neue Spalte drangezeichnet
         CopyRect 0, 0, max_x_tiles * cTILESIZE, (max_y_tiles - 1) * cTILESIZE, 0, cTILESIZE
         
         
         ; nur Feld Mitte sichtbar, Teil aus Feld Mitte ergänzen (Fall 1 (und Fall 2))
         If -vx < (gXmax - max_x_tiles - 1)
         
            For i = 0 To max_x_tiles - 1
   
               DrawBlock IMG_Tiles, i * cTILESIZE, 0, Feld(gFeld_Mitte, (i - vx), -vy)
   
            Next

         ; + Feld Rechts sichtbar, Feld Unten aber nicht (Fall 3 (und Fall 4))
         ElseIf -vx >= (gXmax - max_x_tiles)
         
            ; Teil des Feldes Mitte zeichnen (linker Teil)
            For i = 0 To (gXmax + vx) - 1

               DrawBlock IMG_Tiles, i * cTILESIZE, 0, Feld(gFeld_Mitte, (i - vx), -vy)

            Next
            
            ; Rest von Feld Rechts dazuzeichnen (rechter Teil)
            For i = 0 To ((max_x_tiles) - (gXmax + vx))

               DrawBlock IMG_Tiles, (i - vx) * cTILESIZE, 0, Feld(gFeld_Rechts, i, -vy)

            Next
         
         EndIf
         
         ; Die Abfragen von Feld Mitte + Feld Unten (Fall 2) sowie "alle Felder sichtbar" (Fall 4) entfallen hier,
         ; da die anzufügenden Tiles ausschließlich aus Feld Mitte und Feld Rechts gelesen werden (aufgrund der
         ; Änderung der Zuweisung (mit * markiert)


         SetBuffer BackBuffer()
         
      EndIf


;##################################################
   ; Karte zeichnen
      DrawBlock IMG_Background, 0, 0

;##################################################
   ; Ausgabe
   Text 10,10, "Auflösung: " + gGraphicsWidth + "*" + gGraphicsHeight
   Text 10,25, "Größe der Einzeltiles: " + cTILESIZE
   Text 10,40, "Maximale Anzahl Tiles pro Bildschirm: " + max_x_tiles + "*" + max_y_tiles
   Text 500,10, "V: " + vx + " / "+vy
   Text 500,25, "Sektor: " + sektor_x + " / " + sektor_y
   Text 500,40, "Aktueller Testwert: "
   Text 10,55, "M"+ gFeld_Mitte
   Text 10,70, "R"+ gFeld_Rechts
   Text 10,85, "U"+ gFeld_Unten
   Text 10,100, "UR"+ gFeld_Rechts_Unten
   If (-vx > (gXmax - max_x_tiles)) Text 10,120,"Ja"


Flip
Until KeyHit(1)
;####################################################################################################
DebugLog Str(MilliSecs() - t)+" ms:  Spiel beendet."
End



Function Map_Einlesen(MapKennziffer)

Local f_sektor_x, f_sektor_y
Local f_Datei

   ; die jeweiligen Sektoren werden aus der relativen Mapbezeichnung ermittelt
   Select MapKennziffer

      Case gFeld_Mitte
         f_sektor_x = sektor_x
         f_sektor_y = sektor_y

      Case gFeld_Rechts
         f_sektor_x = sektor_x + 1
         f_Sektor_y = sektor_y

      Case gFeld_Unten
         f_sektor_x = sektor_x
         f_Sektor_y = sektor_y + 1

      Case gFeld_Rechts_Unten
         f_sektor_x = sektor_x + 1
         f_Sektor_y = sektor_y + 1

   End Select

   ; Karte laden
   f_Datei = ReadFile("x" + Str(f_sektor_x) + "y" + Str(f_sektor_y) + ".map")
   If f_Datei = 0   DebugLog ">> FEHLER: Datei  x" + Str(f_sektor_x) + "y" + Str(f_sektor_y) + ".map  nicht gefunden!"

      For i = 0 To gXmax

         For j = 0 To gYmax

            Feld(MapKennziffer, i, j) = ReadShort(f_Datei)

         Next

      Next

End Function



Gruß, garret
>>nec aspera terrent<< (Auch Widerwärtigkeiten schrecken nicht)

Xeres

Moderator

BeitragSa, Apr 18, 2009 15:43
Antworten mit Zitat
Benutzer-Profile anzeigen
Hab ich das richtig verstanden, dass du die Tiles immer in ein großes Hintergrundbild kopierst? Oo
Wenn das schneller ist als nur sichtbare Tiles zu zeichnen, okay. Das Problem scheint mir das verschieben nach oben und unten zu sein - aber durch den Code durchsteigen warum das so ist...
Eine viel bessere alternative habe ich grade aber auch nicht zur Hand.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)

garret

BeitragSa, Apr 18, 2009 17:57
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich denke schon, dass es schneller ist, an ein großes Hintergrundbild nur die benötigten Tiles anzuhängen, als jedesmal 32x24 Tiles zu zeichnen. Korrigiert mich wenn ich da falsch liege. Wenn ich also nach oben laufe, brauche ich eine Zeile Tiles aus Feld_Mitte und eventuell aus Feld_Rechts.

Und EBEN das Verschieben bereitet doch die Probleme...
>>nec aspera terrent<< (Auch Widerwärtigkeiten schrecken nicht)

kriD

BeitragSo, Apr 19, 2009 9:33
Antworten mit Zitat
Benutzer-Profile anzeigen
warum sollte es schneller sein, ein großes bild anzuzeigen (das man sogar noch andauern bearbeiten muss), als kleine bilder, die zusammen eine genausogroße fläche ergeben anzuzeigen? klingt unlogisch.

wenn jetzt dutzende layer übereinander gezeichnet werden müssten, könnte es einen performancevorteil bringen die ganzen layer in ein bild zu zeichenn, da sich ansonsten die tiles überlappen und somit stellen doppelt gezeichnet werden, was bei einem einzelnen bild nicht der fall wäre. aber ansonsten würde ich sagen, das das "normale" anzeigen von tiles schneller ist.

lg kriD
Wenn ich du wäre, wäre ich lieber ich!

garret

BeitragSo, Apr 19, 2009 13:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Nehmen wir doch mal einen Vergleich: Du hast ein Poster und willst rechts ein Stück mehr haben, dafür aber links etwas weg lassen. Schneidest du dafür links etwas weg und klebst rechts eine Spalte ran oder zeichnest du das ganze Poster komplett neu?
Und um zurückzukommen: Warum sollte es schneller sein, jedes Mal 32x24 kleine Tiles zu zeichnen, die zudem noch aus einem Dim-Feld gelesen werden müssen (2 x 768 Arbeitsschritte, Lesen und Zeichnen), statt ein großes Hintergrundbild anzuzeigen (1 Arbeitsschritt) und dieses nur wenn's nötig ist zu bearbeiten?
Programmiertechnisch halte ich Einzeltiles für einfacher, aber da sie (meiner Meinung nach) langsamer sind, bin ich den anderen Weg gegangen.

Würde mich trotzdem freuen, wenn sich jemand auf meinen Code bezieht, unabhängig der "Performancediskussion" Smile
>>nec aspera terrent<< (Auch Widerwärtigkeiten schrecken nicht)
 

BBPro2

BeitragSo, Apr 19, 2009 22:48
Antworten mit Zitat
Benutzer-Profile anzeigen
seit wann kann man zu einer laufzeitfrage ne "meinung" haben ? ^^
entweder das eine ist schneller oder das andere. das probiert man aus wenn die laufzeit wichitg ist bzw berechnet es mathematisch (was ohne genaurer kenntnisse über die nebenkosten der verwendeten blitzbasic befehle nicht möglich ist aufgrund fehlender informationen)
ich würde also zum ausprobieren tendieren - allerdings nur wenn die lz dir überhaupt wichtig ist. bei den heutigen rechnern und dem was du zu programmieren scheinst (keine praktische anwendung nehme ich an, mehr experimentieren (?)) sollte die lz dir vermutlich egal sein wodurch die diskussion redundant wird Wink

zum problem selbst hab ich kA, grad keinen bock den code zu lesen *g

garret

BeitragMo, Apr 20, 2009 10:38
Antworten mit Zitat
Benutzer-Profile anzeigen
Meine Meinung bezieht sich darauf, dass es bei früheren Versuchen unter Verwendung von Tiles beim Verschieben geruckelt hat, was bei einem großen Bild nicht der Fall war. Ich habe das also schon ausprobiert.

Allein theoretisch brauche ich bei einer 32x24 großen Karte zwei verschachtelte Schleifen und damit wie gesagt 768 Durchläufe, in denen ich jedes Mal
I) aus der Karte lesen
II) auf das Einzelbild zugreifen
III) es zeichnen muss.

I) entfällt bei einem reinen Anzeigen eines großen Hintergrundbildes. Und ansonsten wird der Rest nur einmal gemacht: einmal zugreifen, einmal zeichnen.

Die Laufzeit ist mir nicht egal, deswegen habe ich mich ja aufgrund meiner Erfahrung gegen Tiles entschieden. Der Code soll, wenn er fertig ist, ins Codearchiv. Eine praktische Anwendung wird es daher nicht, eher ein weiterer Teil meines gDKs (garrets Developer Kit Wink). Dessen Ziel ist es, mehrere Werkzeuge für ein großes Spiel zur Verfügung zu stellen. Meine wie ich finde zu Unrecht missachtete Ablaufautomatik (https://www.blitzforum.de/foru...fautomatik) stellt bereits den ersten Teil davon dar. Würde mich übrigens auch freuen, wenn dazu nach über einem Jahr mal Antworten kämen...
>>nec aspera terrent<< (Auch Widerwärtigkeiten schrecken nicht)

D2006

Administrator

BeitragMo, Apr 20, 2009 10:46
Antworten mit Zitat
Benutzer-Profile anzeigen
Es ist selbstverständlich bedeutend langsamer. Wenn das Bild einige Male größer ist als der Sichtbereich muss dennoch immer das komplette Bild gezeichnet werden. Außerdem dauert das zeichnen großer Bilder länger als das kleiner. Und das Verhältnis ist nicht proportional, d.h. wenn man ein Bild in 4 Teile teilt, heißt das nicht, dass das Zeichnen der vier kleinen Bilder genau so lange dauert wie das des großen.

Und mal ab davon, ist der Speicherverbrauch exorbitant höher. Ein Bild von 1024*1024 benötigt schon 4 MB im Speicher. Und wozu benutzt man Tilemaps vorallem: gleichaussehende Felder sind so wirklich nur einmal vorhanden und werden nur mehrfach gezeichnet.
Intel Core i5 2500 | 16 GB DDR3 RAM dualchannel | ATI Radeon HD6870 (1024 MB RAM) | Windows 7 Home Premium
Intel Core 2 Duo 2.4 GHz | 2 GB DDR3 RAM dualchannel | Nvidia GeForce 9400M (256 MB shared RAM) | Mac OS X Snow Leopard
Intel Pentium Dual-Core 2.4 GHz | 3 GB DDR2 RAM dualchannel | ATI Radeon HD3850 (1024 MB RAM) | Windows 7 Home Premium
Chaos Interactive :: GoBang :: BB-Poker :: ChaosBreaker :: Hexagon :: ChaosRacer 2

garret

BeitragMo, Apr 20, 2009 10:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich meine selbstverständlich ein Bild, das nur genau so groß ist wie die Auflösung / der Sichtbereich. Das Teilen in 4 Karten dient nicht der Geschwindigkeitsoptimierung, sondern um die Unendlichkeit zu verwirklichen.
Wie steht es denn aber mit meinem Argument, dass bei Tiles viel mehr Durchläufe erforderlich sind? Ihr bezieht euch bisher nur darauf, dass das Anzeigen eines großen Bildes langsamer ist. Wenn ich aber Zeit spare, weil ich nur das Nötige und nicht das ganze Bild ändere, relativiert sich das doch, oder?

...

Edit 1: Auf die Schnelle habe ich aus meinem Code mal einen Test gemacht. Leertaste schaltet zwischen Einzelbild und Tiles um. Auf den Zugriff aus einem Feld musste ich leider verzichten, weil es da Probleme mit dem durch CreateImage erstellten Tile-Bild gab.
Jedoch ist das Zeichnen einzelner Tiles langsamer. Bei mir: Gesamtbild: 0 ms, Tiles: 14 ms

Edit 2: Wenn jetzt bei meiner Methode das Lesen und Ändern des großen Bildes länger dauert als das Lesen und Anzeigen der Tiles, gebe ich mich geschlagen Very Happy Aber ich habe ja wie gesagt 14 ms Spielraum Wink

Edit 3: So und um es noch mal zu ändern: In meinem Code oben dauert das Verschieben der Karte nach Rechts zwischen 0 und 2 ms. Jetzt warte ich auf Gegenbeweise, warum ich aus Sicht höherer Geschwindigkeit Tiles nehmen sollte. Der Punkt für den Speicherbedarf geht natürlich an Tiles, da diskutiere ich auch nicht Wink

Code: [AUSKLAPPEN]
;####################################################################################################

; Zeittest großes Hintergrundbild vs. Tiles

;####################################################################################################
;####################################################################################################
; Variablen
Global gGraphicsWidth=1024
Global gGraphicsHeight=768
Graphics gGraphicsWidth,gGraphicsHeight,32,2


Const cTILESIZE = 16   ; Größe der Tiles

Global max_x_tiles = gGraphicsWidth / cTILESIZE      ; Anzahl der maximal gleichzeitig anzeigbaren tiles
Global max_y_tiles = gGraphicsHeight / cTILESIZE

; Bilder
Global IMG_Background                     ; Bild, das zusammengesetzt den Hintergrund darstellt
IMG_Tiles = CreateImage((cTILESIZE),cTILESIZE)   ;das Bild, das die Einzel-Tiles enthält

SetBuffer ImageBuffer(IMG_Tiles); Einzelbild mit Farbe füllen
Color 0,100,200
   For i = 0 To (cTILESIZE - 1)
   
      For j = 0 To cTILESIZE - 1
      
         Plot i,j
         
      Next
      
   Next
   
Color 255,255,255

;####################################################################################################
   ; das eigentliche Hintergrundbild erstellen
   IMG_Background = CreateImage(gGraphicsWidth, gGraphicsHeight)
   SetBuffer ImageBuffer(IMG_Background)
   
   ; Je nach Verschiebung der Karte (aus Speicherstand geladen) werden Teile aus bestimmten Feldern gebraucht
   
      For i = 0 To (max_x_tiles - 1)
      
         For j = 0 To (max_y_tiles - 1)
      
            DrawBlock IMG_Tiles, i * cTILESIZE, j * cTILESIZE, 0

         Next
      
      Next

   SetBuffer BackBuffer()


;####################################################################################################
Repeat : Cls

t1 = MilliSecs()
;##################################################
   ; Karte zeichnen
   
      If Modus = 0
      
         DrawBlock IMG_Background, 0, 0
         
      ElseIf Modus = 1
      
         For i = 0 To (max_x_tiles - 1)
      
            For j = 0 To (max_y_tiles - 1)
      
               DrawBlock IMG_Tiles, i * cTILESIZE, j * cTILESIZE
            
            Next
      
         Next
         
      EndIf
      
t2 = MilliSecs()

If KeyHit(57) Modus = 1 - Modus


;##################################################
   ; Ausgabe
   Text 10,10, "Auflösung: " + gGraphicsWidth + "*" + gGraphicsHeight
   Text 10,25, "Größe der Einzeltiles: " + cTILESIZE
   Text 10,40, "Maximale Anzahl Tiles pro Bildschirm: " + max_x_tiles + "*" + max_y_tiles
   Text 10,70, "Zeit: "+(t2-t1)+" ms"
   Text 10,100, "Modus: "+Modus
   Text 100,200, "Leertaste zur Modusänderung"
   Text 100,220, "0 = Gesamtbild, 1 = Tiles"

Flip
Until KeyHit(1)
End

SpionAtom

BeitragMo, Apr 20, 2009 12:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Wenn ich mal wild vermute, sind Tiles dazu da, um speichersparend auf das Spiel einzuwirken. Früher war dies notwendig, weil der Speicher doch sehr begrenzt war. Da lag es nahe, sich wiederholende Levelelemente nur einmal im Grafikspeicher abzulegen. Kürzere Ladezeiten bringt sowas auch mit sich. Auch wird der Levelaufbau einheitlicher und strukturierter.

Tiles sind aus heutiger Sicht irgendwie outdated. Es sei denn, du willst ein Spiel machen, dass auch auf älteren Systemen läuft, da ist es schonmal eine nette Herausforderung, die 16mb Grafik-Schranke nicht zu überschreiten.

Endlos-Maps wollt ich auch schon immer mal realisieren. Dabei wollte ich wie bei den großen Vorbildern die neuen Bilder immer nachstreamen. Aber leider bekommt man mit BB sowas nicht vernünftig hin, denn dazu bräuchte man meines Erachtens coole Nebenläufigkeit.
os: Windows 10 Home cpu: Intel Core i7 6700K 4.00Ghz gpu: NVIDIA GeForce GTX 1080

garret

BeitragMo, Apr 20, 2009 13:09
Antworten mit Zitat
Benutzer-Profile anzeigen
Es geht mir hier nicht darum, über Vorteile von Tiles zu sprechen, sondern um eben endlose Maps zu realisieren. Der Code funktioniert vom Prinzip (also dem "Streaming") her schon, nur überlappt es in der Darstellung an einigen Stellen noch.

Wenn also jemand die Güte hätte, sich meinen Code mal anzusehen, statt jetzt noch über die Methode zu diskutieren. Bis auf einen Beweis, dass meins schneller ist, bin ich kein Stückchen weiter Rolling Eyes
>>nec aspera terrent<< (Auch Widerwärtigkeiten schrecken nicht)

hectic

Sieger des IS Talentwettbewerb 2006

BeitragMo, Apr 20, 2009 13:33
Antworten mit Zitat
Benutzer-Profile anzeigen
garret

1. Gibt es einen guten Grund dafür, warum du alle Variablen als Global deklarierst? Das ist eine sehr schlechte Angewohnheit, welche man gleich eliminieren sollte.

2. Tiles mit 16x16 machen nicht unbedingt ein besseres Leveldesign aus. Oft werden Tiles so klein gewählt, um die eigene unzulänglichkeit beim pixeln durch hoches Tilesdichte zu kompensieren. Allerdings leidet dadurch das Leveldesign an sich. Denn spätestens dann, wenn man pro bildschirmfüllendes Leveldesign eine gewisse Zeit braucht, wird man auch hier lieber ''mal eben schnell'' daran arbeiten, als sinnvolles filigranes Leveldesign erstellen. Von ganzen Levels mit mehreren bildschirmfüllenden Design mal ganz abgesehen. Ansonsten werden so kleine Tiles nur bei portablen Spielegeräten gebraucht (z.B. Nintendo DS etc...).

3. Dein Testcode zeigt den Unterschied nur sehr schlecht. Deine 0 ms vs. 14 ms würden zeigen, dass das ''Ein-Bild-System'' ja 14x bis unendlich schneller ist. Ein FPS-Test zeigt allerdings ein Verhältnis 1:5. Nimmt man nun nicht mehr 16x16 Tiles, sondern 32x32 Tiles. Dann beträgt das Verhältnis nur noch 4:5 (also 160:200 FPS). Bei 64x64 Tiles beträgt das Verhältnis nur noch 184:200 FPS. Das Problem ist also nicht das Tilesystem an sich, sondern deine Minitiles die nur für Minibildschirme benutzt werden sollten (Siehe auch Punkt 2).

4. Außerdem sparst du dir ja keine doppelt verschachtelte Schleife dadurch, dass du dein ''Ein-Bild-System'' benutzt. Denn dann hast du ja überhaupt keine Kontrolle mehr darüber, wo Kollisionen und andere Sachen vorhanden sind. Bei einem Tilesystem hast du die Informationen direkt und ''für umsonst''.

5. Dein ''Ein-Bild-System''-Test, testet auch keine Updates, die beim scrollen durch die Map notwendig sind. Gerade solche Updates könnten sehr nervig auf den Spieler wirken. Ein Spieler wird lieber ewig auf 30 FPS spielen, als auf 60 FPS wo 3mal in der Sekunde ein Frame ausfällt, weil grad wieder ein Update durchgeführt wurde. Und beim scrollen durch die Map mit 16x16 Tiles, müsste man bei einer Ein-Pixel/Frame-Bewegung 3 bis 4 mal in der Sekunde updaten.

- - -

Alles in allem: Mir ist es egal wie du deine Map gestalltest. Aber generell würde ich mal behaupten, ein System welches sich über Jahrzehnte bewährt hat und immer noch praktiziert wird, und es als gut bezeichnen. Über andere Systeme würde ich mir nur Gedanken machen, wenn dadurch auch ein typisches und anderes Erscheinungsbild erreicht wird. So wie zum Beispiel beim Spiel ''Soldat'', wo eben mit Polygonen gearbeitet wird.

Edit1: Ich nehme an, dass keiner wirklich Lust hat, sich dieses Vorgehen vorzunehmen und den Code entsprechend zu bearbeiten. Ich würde dir einfach mal dazu raten, sich einem Tilesystem mit 32x32er Tiles anzunehmen.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D

Noobody

BeitragMo, Apr 20, 2009 13:54
Antworten mit Zitat
Benutzer-Profile anzeigen
So wie ich dein Problem verstehe, willst du einfach eine Map realisieren, die sich auf alle 4 Seiten unendlich weit wiederholt - sehe ich das richtig?

In diesem Falle ist die Lösung relativ einfach: BlitzBasic: [AUSKLAPPEN]
Const GWIDTH = 800
Const GHEIGHT = 600

Graphics GWIDTH, GHEIGHT, 0, 2
SetBuffer BackBuffer()

Const MAPWIDTH = 50
Const MAPHEIGHT = 50
Const TILESIZE = 16

Dim MapData( 0, 0 )

InitMap( MAPWIDTH, MAPHEIGHT )

Global ScrollX, ScrollY, Tileset = LoadAnimImage("test16_2.png", TILESIZE, TILESIZE, 0, 16 )

Timer = CreateTimer( 60 )

While Not KeyHit( 1 )
Cls

RenderMap( ScrollX, ScrollY )

ScrollX = ScrollX + ( KeyDown( 205 ) - KeyDown( 203 ) )*TILESIZE
ScrollY = ScrollY + ( KeyDown( 208 ) - KeyDown( 200 ) )*TILESIZE

Text 0, 0, ScrollX/TILESIZE + " " + ScrollY/TILESIZE

Flip 0
WaitTimer Timer
Wend
End

Function RenderMap( SX#, SY# )
Origin -SX#, -SY#

For X = SX#/TILESIZE To ( SX# + GWIDTH )/TILESIZE
For Y = SY#/TILESIZE To ( SY# + GHEIGHT )/TILESIZE
TileX = X Mod MAPWIDTH
TileY = Y Mod MAPHEIGHT

If TileX < 0 Then TileX = TileX + MAPWIDTH
If TileY < 0 Then TileY = TileY + MAPHEIGHT

DrawImage Tileset, X*TILESIZE, Y*TILESIZE, MapData( TileX, TileY )
Next
Next

Origin 0, 0
End Function

Function InitMap( Width, Height )
Dim MapData( Width - 1, Height - 1 )

For X = 0 To Width - 1
For Y = 0 To Height - 1
MapData( X, Y ) = ( X/10 + Y/10 ) Mod 16
Next
Next
End Function

Das verwendete Tileset ist das, was bei dir im Download beiliegt.

Das Prinzip ist so, dass der momentan sichtbare Bereich gezeichnet wird und negative Koordinaten bzw. zu grosse Koordinaten einfach von der anderen Seite her wieder reinkommen.
Falls du mehrere Maps aneinander reihen willst, musst du sie halt anfangs in das grosse Array reinladen, um diese Methode verwenden zu können.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

garret

BeitragMi, Apr 22, 2009 21:25
Antworten mit Zitat
Benutzer-Profile anzeigen
@ hectic:
1. Global ist wohl wirklich nur eine schlechte Angewohnheit...
2. Die Größe von 16 habe ich gewählt, weil ich später eine feinere Kollision wollte, als immer nur alle 32 Pixel. Der Gedanke ist eben, dass eine 32x32 Spielfigur nicht so eckig mit einem 96x32 Baum kollidieren soll Smile
Da die Tilegröße aber in der Konstanten cTILESIZE festgelegt ist, kann man das im Nachhinein leicht anpassen.
Es ging mir also nicht darum, das Tilesystem zu verteufeln, sondern einen Kompromiss zwischen feinerer 16x16-Tilekollision und dessen Anzeige zu finden. Und wenn niemand mal was anderes probieren würde, hätten wir doch nichts zu diskutieren Wink
3., 4. und 5.: Dass weniger Tiles schneller gezeichnet werden erscheint mir auch logisch. Sehe ich in meinem Test unter Verwendung von 32x32 und 64x64 doch. Allerdings gebe ich zu, dass lediglich die reine Dauer des Zeichnens getestet wird und dies nicht der einzige Faktor ist.


@ Noobody:
Ich meine unendliche, sich nicht wiederholende Maps, also Hintergründe. Die Verschiebung soll so schnell sein, dass ich meine Figur mit einem Vehikel fahren lassen kann, ohne dass es ruckelt. Eine Frage hätte ich noch zu deinem Code: Das eigentliche Tile wird doch in deiner Funktion InitMap in der Zeile

Code: [AUSKLAPPEN]
MapData( X, Y ) = ( X/10 + Y/10 ) Mod 16


festgelegt, so dass ich dort den Tiles ihren Wert zuweisen muss, oder?


MfG garret


P.S. Ohne aufdringlich wirken zu wollen - mir würde wirklich viel daran liegen, wenn ihr euch meine Ablaufautomatik mal ansehen würdet (Link sieben Posts weiter oben).

Noobody

BeitragMi, Apr 22, 2009 21:47
Antworten mit Zitat
Benutzer-Profile anzeigen
garret hat Folgendes geschrieben:
Ich meine unendliche, sich nicht wiederholende Maps, also Hintergründe.

Das musst du ein wenig genauer erklären. Wenn deine Maps sich unendlich weit ausdehnen, aber nicht wiederholen sollen, musst du sie ja ständig neu generieren. Ich glaube aber nicht, dass du das meinst, daher wäre eine besser Erklärung nicht schlecht Razz

Zu deiner Frage zum Code: Ja, das Tile wird in dieser Zeile eingesetzt. Ich hab einfach 10x10 Tiles grosse Blöcke erstellt, damit man die Wiederholung besser sieht (bei einer zufälligen Map ist das ja nicht so einfach zu erkennen).

Deine Ablaufautomatik habe ich mir angesehen, aber das Problem bei solchen Systemen ist immer, dass so etwas entweder zu allgemein oder zu spezialisiert gehalten ist.
Du hast sicher viel Arbeit reingesteckt, aber normalerweise schreibt man sich so ein System selbst, um es perfekt auf das eigene Projekt zuschneiden zu können.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

garret

BeitragMi, Apr 22, 2009 22:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Noobody hat Folgendes geschrieben:
Das musst du ein wenig genauer erklären. Wenn deine Maps sich unendlich weit ausdehnen, aber nicht wiederholen sollen, musst du sie ja ständig neu generieren. Ich glaube aber nicht, dass du das meinst, daher wäre eine besser Erklärung nicht schlecht


Ich meine eine ganz "normale" Welt, wo die Tiles nicht generiert, sondern z.B. aus einer Datei gelesen werden. Da wiederholt sich ein- und dasselbe Haus mit Brunnen ja auch nicht alle paar Karten. Also im Gegensatz zu einem scrollenden Himmel, wo alle 50 Tiles die gleiche Wolke vorbeizieht Wink



Und zur AA: Sie ist eigentlich so allgemein gehalten, dass man sie in fast jedes Spiel integrieren kann. Das hat bei einem alten Projekt, wo ihr Einsatz nicht von vornherein geplant war, problemlos geklappt und uns viel Arbeit und Zeit gespart. Außerdem ist sie ja individuell erweiterbar oder eben verringerbar, so dass man sie sich selbst spezialisieren kann. Genau DAS ist ja ihr Vorteil. Aber das sollte nicht in diesem Thema besprochen werden, dazu gibt's schon das andere. Das hier war nur Schleichwerbung Wink

Neue Antwort erstellen


Übersicht BlitzBasic Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group