Flugbahn von Gegnern vorgeben

Anfängerfragen zum Programmieren mit PureBasic.
obar
Beiträge: 111
Registriert: 22.11.2007 19:47

Flugbahn von Gegnern vorgeben

Beitrag von obar »

Hallo zusammen,

kann mir jemand erklären wie man die Flugbahn für Gegner vorgeben kann? Die Basis ist das 2D-Shooter Tutorial. Habe aber diverse Veränderungen vorgenommen. Es ist nun ein Vertikalshooter . Die Gegner schiessen usw. Ich habe hier im Forum keine Informationen dazu gefunden.

Ich wäre froh, wenn mir jemand aufzeigen könnte, wie man das realisiert.

Im Moment ist es so, dass die Gegner Zufallsgeneriert auftauchen und dann gerade nach unten fliegen.

Code: Alles auswählen

enemy:
  If enemyDelay = 0
    AddEnemy(Random(780), 1, 0, -2-Random(1)) 
    enemyDelay = enemySetDelay
  Else
    enemyDelay - 1
  EndIf
  
  ForEach enemy()
    If enemy()\y > 580-SpriteHeight(#Sprite_Enemy) : DeleteElement(enemy()) : EndIf
  Next
  ForEach enemy()
    If enemy()\treffer = #True
      score + 50
      DeleteElement(enemy())
    EndIf
  Next
  ForEach enemy()
    DisplayTransparentSprite(#Sprite_Enemy, enemy()\x, enemy()\y)
    enemyshotdelay + 1
    If enemyshotdelay = 50
      AddEnemyshot(enemy()\x, enemy()\y, 0, 3)
      enemyshotdelay = 0  
    EndIf
    enemy()\y - enemy()\speedy  
  Next
Return
Benutzeravatar
Laurin
Beiträge: 1639
Registriert: 23.09.2004 18:04
Wohnort: /dev/eth0

Beitrag von Laurin »

Man könnte sich mehrere Flugbahnen vorstellen.

- direkt auf den Spieler fliegen (Kamikaze-like)
- Schreibmaschinen-like, die Gegner bewegen sich von links nach rechts, kommen sie am Bildschirmrand an, bewegen sie sich ein Stück nach unten, dann fliegen sie wieder seitwärts bis zum anderen Bildschrimrand usw. Alternativ geht das auch umgekehrt (sie fliegen nach oben statt nach unten).
- oft werden Sinus/Cosinus- und auch Tangenskurven genommen.
- Parabeln
- Umkreisung anderer Gegner (orbitale Flugbahn)
- vorgegebene Flugbahnen, die keiner mathematischen Funktion entsprechen

Du müsstest dann für jedes feindliche Raumschiff speichern, welche der Varianten es befolgen soll und wie weit es die Wege schon abgeflogen hat (damit man den weiteren Weg bestimmen kann).

Modifizieren müsstest du nur diesen Abschnitt:

Code: Alles auswählen

  ForEach enemy() 
    DisplayTransparentSprite(#Sprite_Enemy, enemy()\x, enemy()\y) 
    enemyshotdelay + 1 
    If enemyshotdelay = 50 
      AddEnemyshot(enemy()\x, enemy()\y, 0, 3) 
      enemyshotdelay = 0  
    EndIf 
    enemy()\y - enemy()\speedy  
  Next
Man könnte die Liste enemy() erweitern:

Code: Alles auswählen

enemy()\Flugbahn ; Art der Flugbahn (0 = starr nach unten, 1 = Sinus etc.)
Dann haust du ein If für jede Flugbahn rein, worin dann eben diese Flugbahn berechnet wird.
Now these points of data make a beautiful line.
And we're out of beta. We're releasing on time.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

mal kurz gefaßt:

du musst halt die x-koordinate auch verändern,
ggf. auch die y-koordinate anders verändern als einfach nur hochzählen.

grundsätzlich wird dein enemy ja an den koordinaten enemy()\x, enemy()\y angezeigt.
diese koordinaten manipulierst du nun in der form, dass du die gewünschte bewegung herausbekommst.

zur übung mach mal ein extra proggi, wo du nur ein einziges sprite hast,
also keine enemy-liste und keinen player mur ein einzelnes sprite,
und das beweg mal auf die unterschiedlichsten arten und weisen.
dann kommst du schnell dahinter, wie du bewegungen machen kannst.

eine möglichkeit ist z.b. auch, dass du ein Array an koordinaten erstellst,
die eine richtige flugbahn bilden, und dein sprite diesem array folgen läßt.
so wird das z.b. bei "Phoenix" gemacht.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
obar
Beiträge: 111
Registriert: 22.11.2007 19:47

Beitrag von obar »

@Laurin

Also wenn ich das Richtig verstanden habe erweitere ich meine Structure mit Flugbahn. Dann könnte ich mit einem
Zufallsgenerator jedem Gegner eine Flugbahn zuweisen. z.B. 0 - 5. Dann Frage ich diese ab mit IF, wo dann die
entsprechende Flugbahn berechnet und ausgeführt wird.

Ich denke ich versuchs mal so.

@Kaeru Gaman

Ich werde es so versuchen wie du vorgeschlagen hast, damit ich die Flugbahnen testen kann. Wäre es beispielsweise
auch möglich die Flugbahn in einer LinkedList abzulegen und diese dann abzuarbeiten?

Danke für eure Antworten
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> auch möglich die Flugbahn in einer LinkedList abzulegen und diese dann abzuarbeiten?
wäre natürlich auch möglich, halte ich aber für die weniger gute lösung.
es ist langsamer und benötigt per element noch 2pointer = 8byte zusätzlich.
bei elementen die nur koordinaten sind, ist das übertrieben.

hatte grad spaß dran, hab ich mal ein kleines beispiel gedaddelt.
meine elemente sind vom typ COORD, das ist ne vordefinierte Struct die ein x-word und ein y-word hat.
damit brauche ich 4byte per element.

außerdem kannst du so ein array mehrdimansional anlegen.
du könntest also z.b. Pos(5,1000) dimensionieren,
dann kannst du deine 6 verschiedenen flugbahnen ins selbe array packen.

hier mal zum rumspielen:

Code: Alles auswählen

; *******************************
; **
; ** FlyWay.pb
; ** Path Demo
; ** by Kaeru Gaman, 2007-12-07
; ** PB Ver. 4.10
; **
; *******************************

EnableExplicit

Define EXIT.l = 0
Define MX.l, MY.l, MBL.l, MBR.l, MBLF.l, MBRF.l
Define n.l, col.l, can.l, Counter.l =1, Mover.l

Dim Pos.COORD(1000)

InitSprite()
InitKeyboard()
InitMouse()
OpenScreen(800,600,32,"bla")

CreateSprite(0,32,32)
CreateSprite(1,64,64)

; *******************************
; ** Creating Mouse Pointer
StartDrawing(SpriteOutput(0))
  For n=0 To 3
    can = 255-48*n
    col = can << 16 + can << 8 + can
    Line(0,n,16-n,0,col)
    Line(n,0,0,16-n,col)
    Line(0,n,28,28,col)
    Line(n,0,28,28,col)
  Next
StopDrawing()

; *******************************
; ** Creating Flyer Sprite
StartDrawing(SpriteOutput(1))
  For n=0 To 8
    col = ( 30*n + 15 ) << 8 + 255
    can = 32-n
    Line(31,35-n, can, -8, col)
    Line(31,35-n,-can, -8, col)
  Next
  For n=0 To 8
    col = ( 30*n + 15 ) << 8 + 255
    Circle( 31-n/3,31-n/2,9-n,col)
  Next
StopDrawing()

; *******************************
; ** Main Loop
Repeat

  ClearScreen($402010)
  ExamineKeyboard()
  ExamineMouse()

  ; *******************************
  ; ** Get Mouse State
  MX = MouseX() : MY = MouseY()
  MBL = MouseButton(1)
  MBR = MouseButton(2)

  If MBL                ; Left Button pressed?
    If Not MBLF         ; first press?
      MBLF = 1          ; set pressed-flag
      Counter = 0       ; reset Counter
      Mover = 0         ; reset Move-Counter
    EndIf
    Pos(Counter)\x = MX ; set actual element
    Pos(Counter)\y = MY ; to actual mouse-coordinates
    Counter +1          ; count up
    If Counter > 1000   ; don't save more than 1000 positions
      Counter = 1000
    EndIf
  Else
    MBLF = 0            ; reset pressed-flag if Button released
  EndIf


  ; *******************************
  ; ** Drawing the stuff

  ; *******************************
  If MBLF
  ; if mouse-button is pressed,
  ; we are currently drawing the path.
  ; so we also display it  
    StartDrawing(ScreenOutput())
      ; one cross at the start
      Line( Pos(0)\x   , Pos(0)\y-4 , 0, 9, $00F080)
      Line( Pos(0)\x-4 , Pos(0)\y   , 9, 0, $00F080)
      ; one cross at the end
      Line( Pos(Counter-1)\x   , Pos(Counter-1)\y-4 , 0, 9, $00F080)
      Line( Pos(Counter-1)\x-4 , Pos(Counter-1)\y   , 9, 0, $00F080)
      ; and dots along the path
      For n = 1 To Counter -2
        Plot(Pos(n)\x,Pos(n)\y,$00C040)
      Next
      ; also show current number of elements
      DrawText(0,0,Str(Counter))
    StopDrawing()
  ; *******************************
  Else
  ; if mouse-button is NOT pressed,
  ; the Flyer can follow the path
    DisplayTransparentSprite(1,Pos(Mover)\x-31,Pos(Mover)\y-31)
    Mover +1              ; count the moving steps
    If Mover > Counter-1  ; not further than we have elements
      Mover = 0           ; start over from beginning
    EndIf
  ; *******************************
  EndIf
  
  DisplayTransparentSprite(0,MX,MY)   ; this is the mouse pointer

  If KeyboardPushed(#PB_Key_Escape)   ; check for ESC to exit
    EXIT = 1
  EndIf
  
  FlipBuffers()
Until EXIT
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
#NULL
Beiträge: 2238
Registriert: 20.04.2006 09:50

Beitrag von #NULL »

das fetzt :D
my pb stuff..
Bild..jedenfalls war das mal so.
obar
Beiträge: 111
Registriert: 22.11.2007 19:47

Beitrag von obar »

@Kaeru Gaman

Super Programm.

Ich hab mein Programm mal so abgeändert das nur noch ein Sprite angezeigt wird. Nun habe ich einen Array eingebaut für die Flugbahn. Das läuft alles einwandfrei. Ich würde das auch noch mit dem 2 Dimensionalen Array verstehen und könnte dies einbauen.

Aber ich habe noch keine Ahnung wie ich das in mein Bestehendes Programm einbinden soll. Da arbeite ich ja nur mit LinkedList.
Wie geht den dass, wenn mehrere Gegner auf dem Bildschirm sind die die gleiche Bewegung ausführen sollen?

Ich hab mal gedacht ich zeig Dir wies aussieht.


Code: Alles auswählen

Structure enemy    
  x.l          
  y.l
  speedX.l
  speedY.l
  treffer.b  
EndStructure 
Global NewList enemy.enemy() 

Procedure AddEnemy(x, y, speedX, speedY)
  AddElement(enemy())  
  enemy()\x = x
  enemy()\y = y
  enemy()\speedX = speedX
  enemy()\speedY = speedY
  enemy()\treffer = treffer
EndProcedure

enemy:
  If enemyDelay = 0
    AddEnemy(Random(780), 1, 0, -2-Random(1)) 
    enemyDelay = enemySetDelay
  Else
    enemyDelay - 1
  EndIf
  
  ForEach enemy()
    If enemy()\y > 580-SpriteHeight(#Sprite_Enemy) : DeleteElement(enemy()) : EndIf
  Next
  ForEach enemy()
    If enemy()\treffer = #True
      score + 50
      DeleteElement(enemy())
    EndIf
  Next
  ForEach enemy()
    DisplayTransparentSprite(#Sprite_Enemy, enemy()\x, enemy()\y)
    enemyshotdelay + 1
    If enemyshotdelay = 50
      AddEnemyshot(enemy()\x, enemy()\y, 0, 3)
      enemyshotdelay = 0  
    EndIf
    enemy()\y - enemy()\speedy  
  Next
Return

Nun hab ich deinen Code geprüft mit einem Sprite.

Code: Alles auswählen

Dim Pos.COORD(24)
pos(0)\x =100
pos(0)\y =100
pos(1)\x =103
pos(1)\y =100
pos(2)\x =106
etc.

counter=25
mover=0


Repeat
  ExamineKeyboard()
  ClearScreen(0)
   
  Gosub enemy
 
  FlipBuffers()
  If KeyboardPushed(#PB_Key_Escape)
    End
  EndIf
ForEver

enemy:
    DisplayTransparentSprite(#Sprite_Enemy, Pos(Mover)\x-16,Pos(Mover)\y-16)
    mover+1
    If mover > counter -1
      mover=0
    EndIf
Return
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

du könntest in die struct 'enemy' ein feld 'mover' hinzufügen,
damit kann sich dann jeder enemy an einer anderen stelle der flugbahn befinden.
du kannst die flugbahn auch als positionsveränderungen erzeugen,
und dann in die felder speedx/speedy einsetzen anstatt in x/y,
dann kann die selbe flugbahn an unterschiedlichen positionen beginnen usw...

grundsätzlich für das rumprobieren:
schau mal, dass du die werte per Read und Data einpflegst,
das ist komfortabler als die vielen = hinzuschreiben.
du kannst die werte auch mit sinusschleifen erzeugen,
oder dir ne routine schreiben, die dir die mausbewegung aus meinem beispiel irgendwie speichert...
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
obar
Beiträge: 111
Registriert: 22.11.2007 19:47

Beitrag von obar »

Erst einmal möchte ich mich bei dir Bedanken für deine Hilfe.

Bezüglich Read und Data hast du da an sowas gedacht?

Code: Alles auswählen

For i = 0 To 5
  For k = 0 To 9
        Read Flugbahn1y
    pos(i,k)\y = Flugbahn1y
  Next 
Next

For i = 0 To 5
  For k = 0 To 9
    Read Flugbahn1x
    pos(i,k)\x = Flugbahn1x
  Next 
Next


DataSection
Flugbahn1x:
Data.l 11,22,33,44,55,66,77,88,99,00
Data.l 00,99,88,77,66,55,44,33,22,11
Data.l 55,44,33,22,11,22,33,44,55,66
Data.l 23,23,23,23,23,32,32,32,32,32
Data.l 10,20,30,40,50,60,70,80,90,100
Data.l 200,210,220,230,240,250,260,270,280,290
Flugbahn1y:
Data.l 11,22,33,44,55,66,77,88,99,00
Data.l 00,99,88,77,66,55,44,33,22,11
Data.l 55,44,33,22,11,22,33,44,55,66
Data.l 23,23,23,23,23,32,32,32,32,32
Data.l 10,20,30,40,50,60,70,80,90,100
Data.l 200,210,220,230,240,250,260,270,280,290
EndDataSection
Also nicht das die Data Werte stimmen würden, ich meine jetzt nur vom Prinzip.

Den mover werde ich ebenfalls in die Structure aufnehmen und testen.

Zum Thema Sinusschleifen......Ich weiss nichtmal was das ist.
Die andere Idee mit dem Speichern der Koordinaten aus deinem Programm werde ich später mal aufgreifen.
Benutzeravatar
Laurin
Beiträge: 1639
Registriert: 23.09.2004 18:04
Wohnort: /dev/eth0

Beitrag von Laurin »

Sinuskurven ^^
Hast du garantiert schon mal gesehen ;)

Bild
y = sin(x)

Kann man natürlich um 90° drehen.
x = sin(y)

Variieren kann man die Kurve so:
x = m*sin(y)+n

m - wie stark die Bögen ausgeprägt sind bzw. wie stark er nach links und rechts ausschlägt
n - wie weit die Kuve nach links oder rechts verschoben ist.
Zuletzt geändert von Laurin am 07.12.2007 20:17, insgesamt 1-mal geändert.
Now these points of data make a beautiful line.
And we're out of beta. We're releasing on time.
Antworten