Aktuelle Zeit: 06.08.2020 00:57

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]




Ein neues Thema erstellen Auf das Thema antworten  [ 22 Beiträge ]  Gehe zu Seite 1, 2, 3  Nächste
Autor Nachricht
 Betreff des Beitrags: 2D Spiel Engine
BeitragVerfasst: 10.10.2006 19:48 
Offline
Benutzeravatar

Registriert: 08.04.2006 16:00
Wohnort: Heidekreis
Hallo!

Ich habe mich nach Plankton etwas hingesetzt und mal das und das gemacht, experimentiert und so. Und natürlich, wie von euch empfohlen, mich etwas mit Listen bzw. Strukturen vertraut gemacht. Nun hatte ich auch mal experimentiert, eine 2D Spiel Engine zu machen. So eine, dass man alles von oben sieht, eigentlich so wie bei Dune. Hier ist der Code (PureBasic 4.00!):

Code:
Global ScreenWidth = 800
Global ScreenHeight = 600
Global Mapsize = 64 ; more than 64 are too CPU/GPU intensive

InitSprite()
InitMouse()
InitKeyboard()
UsePNGImageDecoder()
OpenScreen(ScreenWidth, ScreenHeight, 32, "2D Felder")

LoadSprite(1, "a.png")
LoadSprite(2, "unit.png")
LoadSprite(3, "cursor_house.png")
LoadSprite(4, "cursor_pointer.png")
LoadSprite(5, "b.png")

MouseLocate(ScreenWidth/2, ScreenHeight/2)

Structure Mapfield
  UniqueID.l        ; The unique identification number for the field
  XPosition.l       ; Y Position of the Field
  YPosition.l       ; X Position of the Field
  Type.l            ; The Type
EndStructure

Global NewList Mapfield.Mapfield()

Element = 0
XPosition = -1
YPosition = 0

While CountList(Mapfield()) < Mapsize*Mapsize

  Element = Element+1
  XPosition = XPosition+1
 
  If XPosition = Mapsize
    YPosition = YPosition+1
    XPosition = 0
  EndIf
 
  AddElement(Mapfield())
    Mapfield()\UniqueID = Element
    Mapfield()\XPosition = XPosition*64
    Mapfield()\YPosition = YPosition*64
    Mapfield()\Type = 0
   
Wend

Repeat
  ExamineKeyboard()
  ExamineMouse()
  ClearScreen(RGB(127, 127, 127))
 
  ForEach Mapfield()
    DisplaySprite(1, Mapfield()\XPosition, Mapfield()\YPosition)
   
    If MouseX() < 10
      Mapfield()\XPosition = Mapfield()\XPosition+7
    ElseIf MouseX() > ScreenWidth-10
      Mapfield()\XPosition = Mapfield()\XPosition-7
    ElseIf MouseY() < 10
      Mapfield()\YPosition = Mapfield()\YPosition+7
    ElseIf MouseY() > ScreenHeight-10
      Mapfield()\YPosition = Mapfield()\YPosition-7
    EndIf
   
    If KeyboardPushed(#PB_Key_Up)
      Mapfield()\YPosition = Mapfield()\YPosition+10
    ElseIf KeyboardPushed(#PB_Key_Down)
      Mapfield()\YPosition = Mapfield()\YPosition-10
    ElseIf KeyboardPushed(#PB_Key_Left)
      Mapfield()\XPosition = Mapfield()\XPosition+10
    ElseIf KeyboardPushed(#PB_Key_Right)
      Mapfield()\XPosition = Mapfield()\XPosition-10
    EndIf
   
    If Mapfield()\Type = 1
      DisplaySprite(5, Mapfield()\XPosition, Mapfield()\YPosition)
   
    ElseIf SpriteCollision(4, MouseX(), MouseY(), 1, Mapfield()\XPosition, Mapfield()\YPosition) And MouseButton(#PB_MouseButton_Left)
      DisplaySprite(5, Mapfield()\XPosition, Mapfield()\YPosition)
      ; Listenelement auswählen und bearbeiten
      ;   
      ;   Durch die SpritePixelCollision() muss die UniqueID herausgefunden werden.
      ;   Dann muss jenes Listenelement ausgewählt werden.
      ;   Wenn möglich, werden die Werte geändert,
      ;   andernfalls muss jenes Element gelöscht bzw. durch eines mit geänderten Werten ersetzt werden
      ;   
      ;   
           
    ElseIf SpriteCollision(4, MouseX(), MouseY(), 1, Mapfield()\XPosition, Mapfield()\YPosition)
      DisplayTranslucentSprite(5, Mapfield()\XPosition, Mapfield()\YPosition, 64)
    EndIf
  Next
 
  DisplayTransparentSprite(3, MouseX(), MouseY())
  DisplayTransparentSprite(4, MouseX(), MouseY())
 
  StartDrawing(ScreenOutput()) : DrawingMode(1)
    DrawText(0, 0, Str(Mapsize)+"x"+Str(Mapsize)+" = "+Str(Mapsize*Mapsize), RGB(255, 0, 0))
    DrawText(0, 20, "Currently are "+Str(CountList(Mapfield()))+" Elements in the 'Mapfield' List/Structure", RGB(255, 0, 0))
    DrawText(0, 40, "Current selected List Element: "+Str(ListIndex(Mapfield())), RGB(255, 0, 0))
  StopDrawing()
 
  FlipBuffers()
  ClearScreen(0)

Until KeyboardReleased(#PB_Key_Escape)


Und hier könnt ihr euch das fertige Pack downloaden:
http://www.thenameless.de/engine.zip

Jetzt wollte ich fragen, was ihr davon haltet. Ich glaube, ich hab da fundamental was falsch gemacht, denn wenn ich mehr als 64x64 Felder mache (Also nächste größe wäre 128 (Zweierpotenzen)), dann stottert mein PC schon. Es ist einfach lahm... Ist der Ansatz, bzw. der Gedanke der Engine richtig?
Ich hatte mir vorgestellt, dass man später halt durch klicken(SpriteCollisson) das geklickte Listenelement bearbeitet und somit den Status verändert, dass der PC z.B.

_________________
Bild

Immer die neueste PureBasic Version. Auf allem Betriebssystemen. Ich bin ein OS-Nomad!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 10.10.2006 20:43 
Offline
Benutzeravatar

Registriert: 14.09.2006 17:33
Wohnort: Oktoberfest
hi the Nameless,

ich glaub wenn du nur die auf dem bildschirm dargestellten felder auf kollision prüfst sparst du der cpu viel arbeit.
dann hab ich 2 mal die selbe kollisionsprüfung entdeckt, wenn man die so zusammenfasst gewinnt man sicher auch wieder etwas zeit:
Code:
    ElseIf SpriteCollision(4, MouseX(), MouseY(), 1, Mapfield()\XPosition, Mapfield()\YPosition)
      If MouseButton(#PB_MouseButton_Left)
        DisplaySprite(5, Mapfield()\XPosition, Mapfield()\YPosition)
        ; Listenelement auswählen und bearbeiten
        ;   
        ;   Durch die SpritePixelCollision() muss die UniqueID herausgefunden werden.
        ;   Dann muss jenes Listenelement ausgewählt werden.
        ;   Wenn möglich, werden die Werte geändert,
        ;   andernfalls muss jenes Element gelöscht bzw. durch eines mit geänderten Werten ersetzt werden
        ;   
        ;   
      EndIf
      DisplayTranslucentSprite(5, Mapfield()\XPosition, Mapfield()\YPosition, 64)
    EndIf

_________________
PureBasic 4.40 (Windows - x86)


Zuletzt geändert von tobe am 10.10.2006 21:03, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Danke
BeitragVerfasst: 10.10.2006 20:51 
Offline
Benutzeravatar

Registriert: 08.04.2006 16:00
Wohnort: Heidekreis
Jo, stimmt :allright: Ich sehe solche Sachen nicht immer :oops:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 10.10.2006 20:54 
Offline

Registriert: 10.11.2004 03:22
kannst auch mal überlegen, ob dir ein purer koordinaten check auch ausreicht..

und mal performance-mäßig vergleichen...

http://www.purebasic.fr/german/viewtopic.php?t=9093

PS:
davon ab... wenns ne tilemap ist, brauchst du keine koordinaten speichern, die ergeben sich aus dem index...

_________________
... machts gut und danke für den fisch ...


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 11.10.2006 08:05 
Offline
Benutzeravatar

Registriert: 20.04.2006 09:50
# berechne am schleifen-begin einmal
Code:
ExamineMouse()
mx=MouseX()
my=MouseY()
und benutzte im programm überall statt der prozeduren die variablen, ..denn deutschland muß sparen.

# bestimme am anfang die koordinaten jedes tiles nur relativ in der map, also erstes_element\x=0 ... zweites_element()\x=64 ..was du ja auch machst, aber für das scrollen solltest du auf keinen fall die koordinaten-einträge für jedes tile ändern, sondern beim "display'n" ( :roll: ) den koordinaten eine x- und y-koordinate für die map selbst hinzuaddieren, und nur diese beiden mapX und mapY koordinaten änderst du beim scrollen (also 2 variablen, anstatt 600x800x2 :wink: )
also in pseudoCode etwa so:
Code:
DisplaySprite(spriteNr, mapX+tile\x, mapY+tile\y)


# desweiteren ist eine 600x800 map sowieso ziemlich groß, aber auf jedenfall zu groß um sie vollständig zu zeichnen. vor dem zeichnen jedes tiles, überprüfe, ob die anzeige-koordinaten letzendlich im sichtbaren bereich liegen, damit sortierst du schonmal sehr viele unützte DisplayIrgendwas() -aufrufe aus.

+tip:
wenn du statt sowas
Code:
    If MouseX() < 10
      Mapfield()\XPosition = Mapfield()\XPosition+7
    ElseIf MouseX() > ScreenWidth-10
      Mapfield()\XPosition = Mapfield()\XPosition-7
    ElseIf MouseY() < 10
      Mapfield()\YPosition = Mapfield()\YPosition+7
    ElseIf MouseY() > ScreenHeight-10
      Mapfield()\YPosition = Mapfield()\YPosition-7
    EndIf
..sowas nimmst..
Code:
    If MouseX() < 10
      Mapfield()\XPosition = Mapfield()\XPosition+7
    ElseIf MouseX() > ScreenWidth-10
      Mapfield()\XPosition = Mapfield()\XPosition-7
    EndIf
    If MouseY() < 10
      Mapfield()\YPosition = Mapfield()\YPosition+7
    ElseIf MouseY() > ScreenHeight-10
      Mapfield()\YPosition = Mapfield()\YPosition-7
    EndIf
..dann kann man im spiel auch diagonal scrollen (nur allgemein, da diese code in dem zusammenhang sowieso nicht sehr günstig ist, wie bereits gesagt)

_________________
my pb stuff..
Bild..jedenfalls war das mal so.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 11.10.2006 20:56 
Offline
Benutzeravatar

Registriert: 08.04.2006 16:00
Wohnort: Heidekreis
Erstmal Danke für die Hilfe! :wink:

1. Das mit dem Cursor hab ich gemacht! :)

2. @Kaeru: Naja, ich glaub nicht, dass das mit dem Macro so eine gute Idee ist... :|

3. Naja, ich hätte es halt bloß gern, dass sich der Bildschirm flüssig bewegt. Deswegen is des Offset Zeug nicht so gut :|

4. Tut mir leid, dass ich das jetzt schon wieder nicht begreife, aber wie sortier ich jetzt die Sprite, die nicht angezeigt werden aus? Bzw. wie kann ich überprüfen, ob ein Sprite angezeigt wird? Ich hab schon drüber nachgedacht, und bin auf sowas gekommen:

Code:
If Mapfield()\XPosition > -64 And Mapfield()\XPosition < ScreenWidth And Mapfield()\YPosition > -64 And Mapfield()\YPosition < ScreenHeight
      DisplaySprite(1, Mapfield()\XPosition, Mapfield()\YPosition)
    EndIf


Is das richtig? Also bei mir gehts jedenfalls nicht flüssiger davon. Des weiteren muss ich noch sagen, dass die geplante Tile Größe nicht bei 64*64 Pixel liegen soll, sondern bei 16*16.

5. Vielleicht hilft es ja weiter: Ich will so eine Engine (vom Gameplay her, das Rumlaufen und so) wie bei Diablo II hinkriegen. Ist dazu der Ansatz einer Felderengine überhaupt richtig? Bzw., könnte man die dazu auch nutzen? Ich habe mal gehört, dass das Konzept eine ganz andere Idee sein, sowas wie Labyrinth oder so. Bei einem Neuen Spiel werden die Maps dort immer neu generiert, was ich aber nicht vorhabe, wollte ich nur mal sagen, falls das eine Rolle spielt.

_________________
Bild

Immer die neueste PureBasic Version. Auf allem Betriebssystemen. Ich bin ein OS-Nomad!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 12.10.2006 03:50 
Offline

Registriert: 10.11.2004 03:22
also...

wenn du ne Map aus 16x16 tiles machen willst, dann nimmst du ein 2D Array, wo die tilenummern drinstehen
Code:
Dim Map.l(1023,1024)

füllen tust du das per laden von platte.
natürlich musst du das vorher designen, das kannst du,
indem du dir in data-zeilen nen wolf schreibst,
nen map editor schreibst/benutzt,
oder so ein mini-tool wie bmp2map ( http://www.purebasic.fr/german/viewtopic.php?t=2131 )

im game selber führt du nun zwei koordinaten mit, MapX und MapY.
die geben an, welces Tile in der oberen linken ecke des screens als erstes angezeigt werden soll.
damit kannst du den momentanen kartenausschnitt ändern.
diese Karten-Koordinaten werden oft in relation zu deinen Spielfigur-koordinaten stehen,
aber bei vielen games kann man auch scrollen per maus am screenrand,
also solltest du extra-variablen nehmen dafür.

dann zeigst du ausgehend von diesen MapKoordinaten einen karten ausschnitt an, der so groß ist wie der screen.
bei 16x16tiles auf nem 800x600 screen wären das 51x39 tiles.
(beide eins mehr, damit beim feinscrollen keine lücke am rand entsteht.)

so, dann mal ne mini-demo.
male mal 8 tiles in der größe 16x16, und speicher sie als 001.bmp bis 008.bmp
oder nimm auf die schnelle dieses, halt ausschneiden und einzeln als bmp abspeichern:
Bild
und hier die demo:
Code:
InitSprite()
InitKeyboard()
OpenScreen(800,600,32,"Tiledemo")

For n=1 To 8
  LoadSprite( 100+n, Right("00"+Str(n),3)+".bmp")
Next

Dim Map(1023,1023)

For n=0 To 1023
  For t=0 To 1023
    Map(n,t) = Random(7)+1
  Next
Next

Repeat
  ExamineKeyboard()
  ClearScreen(0)

  If KeyboardPushed(#PB_Key_Left)
    FineX-2
    If FineX < 0
      FineX = 14
      MapX-1
      If MapX < 0
        MapX = 0
        FineX = 0
      EndIf
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Right)
    FineX+2
    If FineX > 14
      FineX = 0
      MapX+1
      If MapX > 1023-50
        MapX = 1023-50
        FineX = 14
      EndIf
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Up)
    FineY-2
    If FineY < 0
      FineY = 14
      MapY-1
      If MapY < 0
        MapY = 0
        FineY = 0
      EndIf
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Down)
    FineY+2
    If FineY > 14
      FineY = 0
      MapY+1
      If MapY > 1023-38
        MapY = 1023-38
        FineY = 14
      EndIf
    EndIf
  EndIf

;***********************************
;*** Tile Engine
  For SY=0 To 38
    For SX = 0 To 50
      DisplaySprite(100+Map(MapX+SX,MapY+SY), 16*SX - FineX , 16*SY - FineY )
    Next
  Next
;***********************************

  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)

_________________
... machts gut und danke für den fisch ...


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 12.10.2006 11:42 
Offline

Registriert: 10.11.2004 03:22
the Nameless hat geschrieben:
2. @Kaeru: Naja, ich glaub nicht, dass das mit dem Macro so eine gute Idee ist... :|

sollte es dir entgangen sein, da sind auch procedures dabei.
würde mich trotzdem mal interessieren, wieso du glaubst, es sei keine gute idee...


...da die frage zweifelsohne kommen wird, habe ich den code noch etwas erweitert.

hier kannst du sehen, dass man
überhaupt keine kollisionsabfrage braucht, um die mausposition zu ermitteln,
sondern nur eine rechnung mit bereits vorhandenen variablen.

[edit]
außerdem habe ich die schrittweite des feinscrollings in eine variable gepackt.
Code:
InitSprite()
InitKeyboard()
InitMouse()
OpenScreen(800,600,32,"Tiledemo")

For n=1 To 8
  LoadSprite( 100+n, Right("00"+Str(n),3)+".bmp")
Next
CreateSprite(109,16,16)
StartDrawing(SpriteOutput(109))
  Box(0,0,16,16,$808000)
  For n=0 To 2
    Line(n-1,  0, 16, 16,$FFFF00)
    Line(n-1, 15, 16,-16,$FFFF00)
  Next
StopDrawing()

Dim Map(1023,1023)

For n=0 To 1023
  For t=0 To 1023
    Map(n,t) = Random(7)+1
  Next
Next

MouseLocate(400,300)
FineStep = 4
Repeat
  ExamineKeyboard()
  ExamineMouse()
  MauX = MouseX() : MauY = MouseY()
  ClearScreen(0)

  If KeyboardPushed(#PB_Key_Left) Or MauX < 8
    FineX-FineStep
    If FineX < 0
      FineX = 16-FineStep
      MapX-1
      If MapX < 0
        MapX = 0
        FineX = 0
      EndIf
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Right) Or MauX > 792
    FineX+FineStep
    If FineX > 16-FineStep
      FineX = 0
      MapX+1
      If MapX > 1023-50
        MapX = 1023-50
        FineX = 16-FineStep
      EndIf
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Up) Or MauY < 8
    FineY-FineStep
    If FineY < 0
      FineY = 16-FineStep
      MapY-1
      If MapY < 0
        MapY = 0
        FineY = 0
      EndIf
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Down) Or MauY > 592
    FineY+FineStep
    If FineY > 16-FineStep
      FineY = 0
      MapY+1
      If MapY > 1023-38
        MapY = 1023-38
        FineY = 16-FineStep
      EndIf
    EndIf
  EndIf

;***********************************
;*** wo ist die maus?
ActTileX = (MauX+FineX) / 16 + MapX
ActTileY = (MauY+FineY) / 16 + MapY

; um zu beweisen, dass es funktioniert,
; ersetze ich direkt im Array das Tile
; über dem sich die Maus befindet.
Buff = Map(ActTileX,ActTileY)   ; Rückspeichern
Map(ActTileX,ActTileY) = 9      ; ne 9 reinschreiben
;***********************************
;*** Tile Engine
  For SY=0 To 38
    For SX = 0 To 50
      DisplaySprite(100+Map(MapX+SX,MapY+SY), 16*SX - FineX , 16*SY - FineY )
    Next
  Next
;***********************************
Map(ActTileX,ActTileY) = Buff   ; den alten Wert wiederherstellen.


  StartDrawing(ScreenOutput())
    DrawingMode(1)
    DrawText( 8, 8,"X: "+Right("000"+Str(ActTileX),4))
    DrawText( 8,24,"X: "+Right("000"+Str(ActTileY),4))
    For n=0 To 2
      Line(MauX+n,MauY  , 8,32,$00FFFF)
      Line(MauX  ,MauY+n,32, 8,$00FFFF)
    Next
  StopDrawing()

  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)

_________________
... machts gut und danke für den fisch ...


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: 0.0
BeitragVerfasst: 12.10.2006 19:53 
Offline
Benutzeravatar

Registriert: 08.04.2006 16:00
Wohnort: Heidekreis
Ui, danke erstmal wieder, ich werde mir das erstmal in Ruhe anschauen, und dein BMP2MAP Tool testen, aber ich glaube, ich hab langsam, was ich will :wink:
Jedenfalls poste ich morgen oder so nochmal hier rein...


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: 13.10.2006 20:01 
Offline
Benutzeravatar

Registriert: 08.04.2006 16:00
Wohnort: Heidekreis
Also wenn ich dein Tool BMP2MAP verwende, dann funktionierts, aber wenn ich dann die Map laden will, mithilfe der Procedure, funktionierts nicht. :cry:

Naja, mal zu dem: Ich hab endlich so ziemlich das was ich mir vorstelle gefunden:

http://www.christian-gleinser.de/prog/isodemo.zip

(http://www.purebasic.fr/german/viewtopic.php?t=5293&postdays=0&postorder=asc&highlight=timebased&start=20)

So, soweit erstmal, jetzt eine fette Frage (ich weiß... :roll: ):
Wie mach ich das?

Naja, ich will jetzt nicht unbedingt Code von euch gepostet haben, es geht jedenfalls auch darum, wie ich sowas mache. Denn die Felder sind ja versetzt und die zugehörigen Sprites überlappen sich (oder nich?).

_________________
Bild

Immer die neueste PureBasic Version. Auf allem Betriebssystemen. Ich bin ein OS-Nomad!


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 22 Beiträge ]  Gehe zu Seite 1, 2, 3  Nächste

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 32 Gäste


Sie dürfen keine neuen Themen in diesem Forum erstellen.
Sie dürfen keine Antworten zu Themen in diesem Forum erstellen.
Sie dürfen Ihre Beiträge in diesem Forum nicht ändern.
Sie dürfen Ihre Beiträge in diesem Forum nicht löschen.

Suche nach:
Gehe zu:  

 


Powered by phpBB © 2008 phpBB Group | Deutsche Übersetzung durch phpBB.de
subSilver+ theme by Canver Software, sponsor Sanal Modifiye