kleiner spaceshooter

Übersicht BlitzBasic Beginners-Corner

Gehe zu Seite 1, 2  Weiter

Neue Antwort erstellen

 

pinochino

Betreff: kleiner spaceshooter

BeitragSa, Jun 18, 2011 16:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habe mich mal an nem ganz simplen "Spaceshooter" versucht.

"1 Spielerschiff auf der Linken seite 6 Gegnerschiffe auf der rechten seite, die man abschiesst"

Die Gegnerschiffe bewegen sich noch nicht, aber das ist nicht mein Problem.

Mein Problem sind die Schüsse ich kann diese auf Leertaste "abfeuern" immer einen nach dem anderen.

wenn jetzt ein Schuss auf ein Gegnerschiff trifft werden Gegnerschiff und Schuss gelöscht.
Wenn aber 2 Schüsse unterwegs sind und der erste auftrifft gibts eine Fehlermeldung, das das Image nicht Existiert

Code: [AUSKLAPPEN]
If ImagesCollide(schussgfx,t\x,t\y,0,gegnergfx,g\x,g\y,0)Then


Hab ne weile nach dem Problem gesucht und denke es wird daran liegen das der schuss gelöscht wird aber ja noch ein zweiter unterwegs ist den das Programm dann nicht mehr erkennt.
Nur eine Lösung hab ich bisher nicht gefunden.

Gesamter Code:
Code: [AUSKLAPPEN]
Const xmax=800, ymax= 600

Graphics xmax,ymax,16,2
SetBuffer BackBuffer()
ftimer=CreateTimer(60)

Global spielergfx, gegnergfx, schussgfx







images_load()



Type gegner

   Field x#
   Field y#
   Field tot

End Type

Type schuss

   Field x#
   Field y#
   Field speed#
   Field tot
   
End Type

Local spieler_x# = 30
Local spieler_y# = ymax/2




Repeat
WaitTimer(ftimer)



DrawImage spielergfx, spieler_x,spieler_y

If KeyDown(200) Then
   spieler_y=spieler_y-3
EndIf

If KeyDown(208) Then
   spieler_y=spieler_y+3
EndIf

If KeyHit(57) Then
   neu_schuss(spieler_x,spieler_y,+7,1)
   DrawImage schussgfx, spieler_x,spieler_y
EndIf

If spieler_y = ymax Then spieler_y = spieler_y-3
If spieler_y = 0 Then spieler_y = spieler_y+3


For t.schuss = Each schuss

   DrawImage schussgfx,t\x,t\y
   
   t\x=t\x+t\speed
   
   If t\x=0 Then t\tot=1
   If t\tot=1 Then Delete t.schuss
   
Next

Local gegnercounter=0
   For g.gegner = Each gegner
      gegnercounter=gegnercounter+1
   
      DrawImage gegnergfx,g\x,g\y
      
         For t.schuss = Each schuss
            
   
            If ImagesCollide(schussgfx,t\x,t\y,0,gegnergfx,g\x,g\y,0)Then
            t\tot=1
            g\tot=1
            
            
               If g\tot=1 Then
                  Delete g.gegner
               
               EndIf
                  
            EndIf
            
            
         Next
         
      Next
      
      
      If gegnercounter<=5 Then
      
         neu_gegner()
      EndIf    
            







Flip
Cls
Until KeyHit(1)
End


Function images_load()

spielergfx = LoadImage("gfx\raumschiff.png")
MidHandle spielergfx

gegnergfx = LoadImage("gfx\gegnerschiff.png")
MidHandle gegnergfx
RotateImage gegnergfx,-90

schussgfx = LoadImage("gfx\schuss.png")
MidHandle schussgfx
RotateImage schussgfx, 90

End Function


Function neu_schuss(x#,y#,speed#,schaden#)

t.schuss = New schuss

   t\x=x
   t\y=y
   t\speed=speed
   
End Function

Function neu_gegner()

   g.gegner = New gegner
   
      g\x= 700
      g\y=Rnd(50,550)
      
      
      
End Function


Midimaster

BeitragSa, Jun 18, 2011 16:53
Antworten mit Zitat
Benutzer-Profile anzeigen
ich denke, die Ursache liegt ganz wo anders...

In der Gegner-Routine darfst Du den Gegner nicht töten, solange noch die Schuss-FOR-EACH-Schleife läuft. Sonst kann es dir passieren, dass zwar noch weitere Schüsse unterwegs sind, aber der Gegner mit dem sie gerade verglichen werden schon nicht mehr existiert.
 

bjh

BeitragSa, Jun 18, 2011 16:55
Antworten mit Zitat
Benutzer-Profile anzeigen
hallo pinochino,

ich benutze immer imagesoverlap. würde ich dir auch empfehlen. Wink

ich würde auch den schuss und den gegner schon beim aufprall löschen. dann sparst du dir variablen.

ich benutze nie so viele funktionen. Wink


ich hoffe, jemand anderer kann dir besser helfen

Midimaster

BeitragSa, Jun 18, 2011 16:56
Antworten mit Zitat
Benutzer-Profile anzeigen
BlitzBasic: [AUSKLAPPEN]
   For g.gegner = Each gegner
gegnercounter=gegnercounter+1
DrawImage gegnergfx,g\x,g\y
For t.schuss = Each schuss
If ImagesCollide(schussgfx,t\x,t\y,0,gegnergfx,g\x,g\y,0)Then
Delete t
g\tot=1
EndIf
Next

If g\tot=1 Then
Delete g
EndIf

Next
 

bjh

BeitragSa, Jun 18, 2011 17:16
Antworten mit Zitat
Benutzer-Profile anzeigen
ich würde es immer noch ohne tot-variablen machen Wink
 

pinochino

BeitragSa, Jun 18, 2011 17:23
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich danke euch beiden.


Den Gegner ausserhalb der t.schuss-Schleife löschen war die Antowrt!



EDIT:

Stimmt die tot variable könnte ich weglassen und den gegner einfach löschen.
Meine erste Überlegung bevor ich angefangen haben den Code zu schreiben war aber eine Gegner-Lebensberechnung mit einzubauen und dafür bräuchte ich diese Variable ... glaube ich. Mr. Green

Midimaster

BeitragSa, Jun 18, 2011 17:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Du kannst auf die Variable Gegner\Tot nicht verzichten. Den Schuss kannst du immer gleich löschen. Da der Gegner aber auf der äußeren FOR/EACH-Schleife läuft, darf er in der inneren Schleife eben NICHT sofort gelöscht werden!
 

pinochino

BeitragSa, Jun 18, 2011 17:42
Antworten mit Zitat
Benutzer-Profile anzeigen
Zitat:
Da der Gegner aber auf der äußeren FOR/EACH-Schleife läuft, darf er in der inneren Schleife eben NICHT sofort gelöscht werden!


Hab ich verstanden & Funktioniert.

Zitat:
Du kannst auf die Variable Gegner\Tot nicht verzichten.


Hab ich ausprobiert und ohne g\tot gehts nicht! Very Happy


mfg
pinO

skey-z

BeitragSa, Jun 18, 2011 17:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Doch Midimaster du kannst darauf verzichten, indem du vor der Kollision prüfts, ob der aktuelle Gegner <> NULL ist.
Awards:
Coffee's Monatswettbewerb Feb. 08: 1. Platz
BAC#57: 2. Platz
Twitter
 

pinochino

BeitragSa, Jun 18, 2011 19:35
Antworten mit Zitat
Benutzer-Profile anzeigen
Noch eine Frage.

Ich möchte wenn Gegner mit Spieler kollidiert das Spielgeschehen anhalten, einen Text ausgeben und dann das Programm beim drücken einer beliebigen Taste beenden.

Aber alle meine Versuche schlugen fehl.

Code: [AUSKLAPPEN]
         
If ImagesCollide(spielergfx,spieler_x,spieler_y,0,gegnergfx,g\x,g\y,0) Then
            
               
         Text xmax/2,ymax/2, "GAME OVER! - DEIN SCHIFF WURDE ZERSTOERT!"
         Text xmax/2,ymax/2+20, "PROGRAMM WIRD AUF TASTENDRUCK GESCHLOSSEN!" 
         waitkey
                        END
                
EndIf


habs auch mit Delay und timern versucht aber hat bei mir alles nicht hingehauen.
(Timer weiß ich nur das man die FPS begrenzen kann oda so Very Happy )

gruß
pinO

Midimaster

BeitragSa, Jun 18, 2011 19:49
Antworten mit Zitat
Benutzer-Profile anzeigen
also, wenn du es ganz professionell machen willst, dann hält die Hauptschleife gar nicht an, sondern alle Spielteilnehmer halten an. Ins Spielgeschehen wird nun ein Rechteck eingeblendet auf dem der Text steht. Nach einer Weile oder Spielereingabe wird dann das Rechteck nicht mehr mitgezeichnet, und die Spielfiguren erhalten wieder ihre Bewegungsmöglichkeiten zurück.

Nachzulesen in meinem Timer-Tutorial https://www.blitzforum.de/foru...hp?t=34436

Dich interessiert dabei am meisten das Kapitel III: Ein Textfeld wird für 3 Sekunden eingeblendet

Wichtig ist aber auch das Kapitel I
 

pinochino

BeitragSa, Jun 18, 2011 19:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Deine Tutorials sind wirklich Spitze Wink

Ich hab dieses scheinbar irgendwie übersehen, werde es sofort durcharbeiten Sind einige interessante Themen dabei Very Happy

Zitat:
Lektion I: Wohin führt dieses Tutorial?

Immer wieder scheitern neue Blitz-User an dem Problem mitten im laufenden Spiel eine der Spielfiguren eine länger dauernde Aktion durchführen zu lassen. Folgende Aktionen fallen wir dabei ein:

A.
Eine Explosion beendet das Leben des Gegners. Nun soll die Explosion in 10 Frames an der Stelle, wo der Treffer war ablaufen. Der Rest des Spieles soll aber weiterlaufen.

B.
Der Spieler springt über ein Hindernis. Dabei soll der höchste Punkt nicht auf ein Mal erreicht werden, sondern es soll eine Art Flug zu sehen sein.

C.
Der User soll eine Text-Eingabe machen können, während das Spiel im Hintergrund weiterläuft.

D.
Alle 30 Sekunden soll ein neuer Gegner geboren werden.

E.
Eine Stoppuhr wird in der Bildschirmecke angezeigt.

F.
Die Spielfiguren sollen unabhängig von der Rechnerleistung auf jedem Computer gleich schnell laufen.

Auf all diese Probleme ist das Arbeiten mit Timern die Lösung.


Ich geh jetzt brav Lesen und dann mein Problem lösen Very Happy
 

pinochino

BeitragSa, Jun 18, 2011 22:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Joa ... nee Dachte es Verstanden zu haben, dann aber doch versagt. Embarassed


Code: [AUSKLAPPEN]
      If ImagesCollide(spielergfx,spieler_x,spieler_y,0,gegnergfx,g\x,g\y,0) Then
      
         TextTimer=MilliSecs()+5*1000
       EndIf
         
            If TextTimer>MilliSecs() Then
               Text 100,200,"GAME OVER - SPIEL WIRD BEENDET"
                  If TextTimer<MilliSecs() Then 
                     GameEndTimer=MilliSecs() +1000
                        If GameEndTimer<MilliSecs() Then End
                  EndIf
                        
            EndIf


Hab Viele Verschiedene Varianten aus Probiert. Jetziger Code siehe oben!
Hilfe Bitte Smile
mfg
pinO


EDIT: Oops DoppelPost Verzeihung

Midimaster

BeitragSa, Jun 18, 2011 22:53
Antworten mit Zitat
Benutzer-Profile anzeigen
na, das sieht doch schon ganz vielversprechend aus. Leider hast Du zu wenig Code gesendet. Man müßte auch noch sehen wo die Hauptschleife ist....

Die Timer müssen auch immer darauf gecheckt werden, ob sie schon mal benutzt worden sind. Sonst wird ja der betreffende Code-Abschnitt ständig neu aufgerufen. Die TIMER sollen aber ja immer nur 1x gesetzt werden Du testest, ob Sie schon gesetzt sind, indem man sie auf "=0" testet:

BlitzBasic: [AUSKLAPPEN]
(If TextTimer=0) And (ImagesCollide(spielergfx,spieler_x,spieler_y,0,gegnergfx,g\x,g\y,0)) Then
TextTimer=MilliSecs()+5*1000
EndIf

If TextTimer>MilliSecs() Then
Text 100,200,"GAME OVER - SPIEL WIRD BEENDET"
EndIf

If (GameEndTimer=0) And (TextTimer>0) And (TextTimer<MilliSecs() Then
GameEndTimer=MilliSecs() +1000
EndIf

If (GameEndTimer>0) And (GameEndTimer<MilliSecs() Then
End
EndIf
 

pinochino

BeitragSa, Jun 18, 2011 23:34
Antworten mit Zitat
Benutzer-Profile anzeigen
Warum sie jetzt alles eingeklammert haben Versteh ich nicht! Smile

Nochmal mein Gedankengang :
Code: [AUSKLAPPEN]
      If TextTimer=0 And ImagesCollide(spielergfx,spieler_x,spieler_y,0,gegnergfx,g\x,g\y,0) Then
      
         TextTimer=MilliSecs()+5*1000
      EndIf


Erst wird abgefragt ob der TextTimer=0 ist UND ob spielergfx mit gegnergfx Kollidiert

Wenn das so ist wird TextTimer auf 5sec gestellt.

Code: [AUSKLAPPEN]
            If TextTimer>MilliSecs() Then
               Text 100,200,"GAME OVER - SPIEL WIRD BEENDET"
            EndIf


Solange TextTimer größer ist als MilliSecs (MilliSecs holt ja jetzt langsam auf)

wird GAME - OVER .... Angezeigt

Code: [AUSKLAPPEN]
            If GameEndTimer=0 And TextTimer>0 And TextTimer<MilliSecs() Then
               GameEndTimer=MilliSecs() +1000
            EndIf


Jetzt wird erst abgefragt ob GameEndTimer=0 ist (Unbenutzt) UND ob TextTimer größer als 0(Benutzt)UND ob TextTimer kleiner als Millisecs ist ( Millisecs hat überholt) Dann wird der GameEndTimer auf 1sec gesetzt.

Code: [AUSKLAPPEN]
            If GameEndTimer>0 And GameEndTimer<MilliSecs() Then
               End
            EndIf


Wenn GameEndTimer größer ist als 0 (Benutzt) UND GameEndTimer kleiner ist als MilliSecs ( MilliSecs hat wieder Aufgeholt) Dann Programm Beenden!

Korrigiere mich Bitte wenn ich das Falsch angehe! Very Happy

mfg
pinO

Midimaster

BeitragSa, Jun 18, 2011 23:45
Antworten mit Zitat
Benutzer-Profile anzeigen
die Klammern sind nur da, weil es übersichtlicher ausschaut.

Du hast alles korrekt nachvollzogen. Ich hoffe mal, du wolltest es auch so?

Aber die Grundidee hast du ja jetzt drauf: Immer fragen, ob der Timer schon gesetzt wurden, bzw. ob er noch nicht gesetzt wurde.
Es ginge natürlich auch mit FLAGS:

BlitzBasic: [AUSKLAPPEN]
If GameEndFlag=0	
If (ImagesCollide(spielergfx,spieler_x,spieler_y,0,gegnergfx,g\x,g\y,0)) Then
GameEndTimer=MilliSecs()+5*1000
GameEndFlag=1
EndIf

ElseIf GameEndFlag=1
If GameEndTimer>MilliSecs() Then
Text 100,200,"GAME OVER - SPIEL WIRD BEENDET"
Else
GameEndTimer=MilliSecs() +1000
GameEndFlag=2
EndIf

ElseIf GameEndFlag=2
If GameEndTimer>MilliSecs() Then

Else
End
EndIf
EndIf
 

pinochino

BeitragSo, Jun 19, 2011 0:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Zitat:
Du hast alles korrekt nachvollzogen. Ich hoffe mal, du wolltest es auch so?


Ich wollte es so nachvollziehen? Oder ich wollte das es so abläuft wie es jetzt aufgebaut ist? Mr. Green

Ich habe es so nachvollzogen wie es mir Logisch erschien. Hehe.

Und so wie es jetzt im Spiel abläuft ist es auch korrekt. Smile

Vielen Dank für Ihre unermüdliche Hilfe und den Verweis auf Ihr Tutorial zu Timern, welches ich vollkommen übersehen habe im FAQ-Forum.

Ich werde das Spiel Schritt für Schritt erweitern, ich denke das ist eine gute Methode sich ein gewisses Grundwissen anzueignen. Somit werden sich mir schon bald weitere Rätsel auftuen welche es zu Lösen gilt und über Ihren Rat würde ich mich immer freuen. Very Happy

so long
pinO


EDIT:
Noch eine "kleine" Frage: Wie kann ich bei Kollision das ganze Spielgeschehen anhalten das die schiffe stillstehen etc? kann ich das mit nem Goto befehl machen das ich die main schleife bis auf GameOverText immer überspringe bis end ? Very Happy

Midimaster

BeitragSo, Jun 19, 2011 1:08
Antworten mit Zitat
Benutzer-Profile anzeigen
Das ist eine nicht ganz leichte Angelegenheit und es gibt mehrere Möglichkeiten dafür....

A
Zunächst könntest Du tatsächlich die Stellen, wo Bewegungen addiert werden, überspringen. GOTO sehen die anderen nicht gerne...ist aber möglich.

B
Jedes Spielelement könnte aber auch einen eigenen TIMER haben, der festlegt alle wieviel msec es sich bewegen soll. Setzt Du diese Timer kurzfristig mal auf Millisecs()+5*1000, bleibt alles für 5sec stehen.

C
Oder du machst es wieder über Flags. Also jedes Spielelement hat einen TIMER, der festlegt, wie schnell oder oft es agiert und ein FLAG, das festlegt, ob es sich überhaupt bewegt. Dies Möglichkeit finde ich am schönsten. Hier musst Du keine Ablaufzeit festlegen, sondern kannst z.b. auch solange anhalten, bis der User eine Taste drückt. Bei genügend unterschiedlichen FLAGs kann man dann auch Gruppen oder alles anhalten:


BlitzBasic: [AUSKLAPPEN]
Repeat
If AllBewegungsFlag=1
If AllGegnerFlag=1
For G.Gegner=Each Gegner
If G.Timer<MilliSecs()
;was auch immer
EndIf
Next
EndIf

If AllNaturFlag = 1
For W.Wolken =Each Wolken
If W.Timer<MilliSecs()
;was auch immer
EndIf
Next
....
EndIf

If SpielerFlag = 1
;.......
EndIf

EndIf

; hier alle Mal-Routinen
Cls
For G.Gegner=Each Gegner
....
Next
For W.Wollken=Each Wolken
....
Next

Flip
Until KeyHit(1)
 

pinochino

BeitragSo, Jun 19, 2011 22:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Es ist zum verzweifeln . ... Crying or Very sad Crying or Very sad

Ich wollte den Spaceshooter nochmal komplett ohne Hilfe nachbauen ... denkste...

Ich bin am ?gegnercounter? gescheitert glaub ich nach ewigen Suchen im Code verglich ich den Code nochmal mit der Vorlage und alles scheint richtig zu sein aber der gegner wird scheinbar nict gelöscht wenn er eine bestimte x koordinate erreicht und nach dem löschen wird auch kein neuer erstellt....

Nochmal drüber gucken bitte Embarassed Embarassed

Code: [AUSKLAPPEN]
Const xmax=800, ymax=600
Graphics xmax,ymax,16,2
SetBuffer BackBuffer()

Global fps=CreateTimer(60)

Global playerx# = 30
Global playery# = ymax/2
Global playerspeed# = 5
Global player_last_schuss
Global player_level = 1

Global playergfx=LoadImage("gfx\raumschiff.png")
MidHandle playergfx

Global schussgfx=LoadImage("gfx\schuss.png")
MidHandle schussgfx
RotateImage schussgfx, 90

Global gegnergfx=LoadImage("gfx\gegnerschiff.png")
MidHandle gegnergfx
RotateImage gegnergfx, -90

Type schuss

   Field x#
   Field y#
   Field speed#
   Field tot
   
End Type

Type gegner

   Field x#
   Field y#
   Field speed#
   Field tot
   
End Type


Repeat
WaitTimer(fps)
      

      DrawImage playergfx, playerx,playery
   
   
      If KeyDown(200) Then
         playery=playery-playerspeed
      EndIf
      
      If KeyDown(208) Then
         playery=playery+playerspeed
      EndIf
      
      If playery>600 Then playery=playery-playerspeed
      If playery<0 Then playery=playery+playerspeed
      
      If KeyDown(57)And player_last_schuss<MilliSecs() Then 
            
            create_schuss(playerx,playery,10)
            player_last_schuss=MilliSecs()+1000
         
      EndIf
      
         For s.schuss = Each schuss
            DrawImage schussgfx,s\x,s\y
         
            s\x=s\x+10
         
            If s\x>800 Then s\tot =1
         
            If s\tot = 1 Then Delete s.schuss
      
         Next
      
          Local gegnercounter
            For g.gegner = Each gegner
            gegnercounter=gegnercounter+1
               
               DrawImage gegnergfx,g\x,g\y
               
               If g\x=100 Then g\tot=1
               
               
                  g\x=g\x-g\speed
                  
                     
                     
                        For s.schuss = Each schuss
                           
                           If ImagesCollide(gegnergfx,g\x,g\y,0,schussgfx,s\x,s\y,0) Then
                           
                              s\tot=1
                              g\tot=1
                              
                           
                           EndIf
                        Next
                        
                        
                        
                        
                     If g\tot=1 Then
                        Delete g.gegner
                     EndIf
                     
                     

                     
            Next
                     
         
            
             
            
            If gegnercounter<player_level Then 
            
               create_gegner()
                  
            EndIf   
            
            
            

            
            
            
            
               
      
            
             
      
Flip 0
Cls
Until KeyHit(1)
End


Function create_schuss(x#,y#,speed#)

   s.schuss = New schuss
   
      s\x = x
      s\y = y
      s\speed= speed
      
End Function

Function create_gegner()

   g.gegner = New gegner
   
      g\x= 600
      g\y= Rand(10,590)
      g\speed= 3
   


End Function 

Midimaster

BeitragSo, Jun 19, 2011 22:34
Antworten mit Zitat
Benutzer-Profile anzeigen
von mir gibt es auch ein "fehler suchen"-tutorial, indem strategien erklärt werden, wie man fehler schon im vorfeld verhindert....und wie man sie findet, wenn es doch einmal passiert ist...

https://www.blitzforum.de/foru...hp?t=33510


[EDIT]
Mit DEBUGLOG kannst Du Variablen-Werte während des Spiel im DEBUG-Fenster ausgeben. Da siehst Du oft schon, warum etwas nicht stattfindet.

Ändere folgende Code-Stelle:

BlitzBasic: [AUSKLAPPEN]
DebugLog GegnerCounter + " " + PlayerLevel           
If gegnercounter<player_level Then
create_gegner()
EndIf


...und überprüfe, ob du dieses Reslutat erwartet hättest... Dann überlege wo Du als nächstes einen DEBUGLOG einfügen kannst...


ich werde mich gleich wieder melden....

Gehe zu Seite 1, 2  Weiter

Neue Antwort erstellen


Übersicht BlitzBasic Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group