BPS #5: Seifenblasenmaschine - Auswertung

Übersicht BlitzBasic Beginners-Corner

Neue Antwort erstellen

Xeres

Moderator

Betreff: BPS #5: Seifenblasenmaschine - Auswertung

BeitragSo, Apr 03, 2011 16:11
Antworten mit Zitat
Benutzer-Profile anzeigen
Die Zeit ist 'rum - wer konnte was hübsches mit den Seifenblasen anstellen?

Das war die Aufgabe

Postet hier eure Ergebnisse, Codes, Gedanken. Lernt von den anderen, seht euch deren Quelltext an und versucht euren eigenen zu verbessern.

Diskussion
Postet zu euren Codes stets eine kurze Erklärung mit euren Gedanken in denen ihr simpel gesagt die Frage "Wieso habe ich XY auf diese Art gelöst?" beantwortet. Beiträge, die nur den Code enthalten werden wir aus dem Thread entfernen.

Nächste Aufgabe
In drei Tagen, am 6. April wird die Musterlösung nach editiert und die nächste Aufgabe eingestellt.

Viel Spaß & viel Erfolg!

Musterlösung:
Ein Objekt:
BlitzBasic: [AUSKLAPPEN]
Const gfx_w% = 800
Const gfx_h% = 600
Graphics(gfx_w, gfx_h, 32, 2)
SetBuffer(BackBuffer())
Local FrameTimer = CreateTimer(60), ms

AutoMidHandle(True)
Local Bubbels = LoadAnimImage("Bubbels5x64.png",64,64,0,5)
MaskImage(Bubbels,255,0,255)

Local Machine = LoadAnimImage("Machine4x128.png",128,128,0,4)
MaskImage(Machine,255,0,255)

;*** Die Maschine:
Local M_x% = gfx_w/2, M_y% = gfx_h-64
Local M_Frame%, M_Time%

;*** Die Seifenblase:
Local B_x% = -1, B_y% = -1
Local B_Frame%, B_Time%

Repeat
Cls
ms = MilliSecs() ;*** Zeit Zwischenspeichern

;* Die Maschine generiert alle 4 Sekunden eine Blase.
If M_Time < ms Then
M_Time = ms+1000
M_Frame = (M_Frame+1) Mod 4
If M_Frame = 3 Then
;* Die Anfangsbedinungen für die Blase werden gesetzt:
B_x = M_x
B_y = M_y - 64
B_Frame = 0
B_Time = ms + 250
EndIf
EndIf

;* Die Blase existiert 3 1/4 Sekunden:
;* 3 Frames herumwobbeln nach der Entstehung für je 1/4 Sekunde.
;* Die Ausgebildete, stabile Blase für 2 Sekunden.
;* Und das Zerplatzen wird 1/2 Sekunde lang angezeigt.
If B_Time < ms Then
B_Time = ms + 250
B_Frame = (B_Frame+1) Mod 5
If B_Frame = 3 Then ;** Ausgebildete Blase
B_Time = ms + 2000
ElseIf B_Frame = 4 Then ;** Platzen
B_Time = ms + 500
ElseIf B_Frame = 0 Then ;** Nach dem Platzen nicht mehr zeichnen
B_x = -1
B_y = -1
EndIf
EndIf

If B_x <> -1 And B_y <> -1 Then ;** Die Blase wird nur gezeichnet, wenn sie
If B_Frame <> 4 Then ;** Koordinaten innerhalb des Bildschirms hat.
B_x = B_x + Rand(-2,2)
B_y = B_y - 2
EndIf
DrawImage(Bubbels, B_x, B_y, B_Frame)
EndIf

DrawImage(Machine, M_x, M_y, M_Frame)

Flip(0)
WaitTimer(FrameTimer)
Until KeyHit(1)

End


Mit Types:
BlitzBasic: [AUSKLAPPEN]
Const gfx_w% = 800
Const gfx_h% = 600
Graphics(gfx_w, gfx_h, 32, 2)
SetBuffer(BackBuffer())
Local FrameTimer = CreateTimer(60)
Global ms, mh1, mx, my

AutoMidHandle(True)
Global Bubbels = LoadAnimImage("Bubbels5x64.png",64,64,0,5)
MaskImage(Bubbels,255,0,255)

Global Machine = LoadAnimImage("Machine4x128.png",128,128,0,4)
MaskImage(Machine,255,0,255)

Type TMaschine
Field x, y
Field frame, time
End Type

Type TSeifenblase
Field x#, y#
Field x_speed#, y_speed#
Field frame, time
End Type

;*** Eine Maschine erstellen:
Create_Maschine(gfx_w/2, gfx_h-64)


Repeat
Cls
ms = MilliSecs() ;*** Zeit Zwischenspeichern
mh1 = MouseHit(1)
mx = MouseX()
my = MouseY()

;* Aktualisierung aller Objekte zur besseren Übersicht in einer Funktion.
Update_All()

If mh1 Then
;* Bei einem Mausklick weitere Maschinen erstellen
Create_Maschine(mx, gfx_h-64)
EndIf

Flip(0)
WaitTimer(FrameTimer)
Until KeyHit(1)

End

Function Create_Maschine(X, Y)
;** Eine neue Maschine erstellen, und die Koordinaten zuweisen.
Local M.TMaschine = New TMaschine
M\x = X
M\y = Y
End Function

Function Create_Blase(X, Y, count)
Local i
For i=0 To count
;* Neue Seifenblasen erstellen und zufällige Geschwindigkeiten verwenden.
Local B.TSeifenblase = New TSeifenblase
B\x = X
B\y = Y
B\x_speed = Rnd(-2,2)
B\y_speed = -Rnd(0.5,2)
B\frame = 0
B\time = ms + 250
Next
End Function

Function Update_All()
Local M.TMaschine, B.TSeifenblase

;* Alle Maschinen nacheinander abarbeiten:
For M = Each TMaschine

;* Die Maschine generiert alle 4 Sekunden eine Blase.
If M\time < ms Then ;* Die aktuelle ComputerZeit hat den Wert der Variable eingeholt
M\time = ms + 1000 ;* Die Variable bekommt eine Zeit in der Zukunft (aktuelle Zeit + 1 Sekunde) zugewiesen.
M\frame = (M\frame+1) Mod 4 ;* Der Frame wird weitergeschaltet; Mod 4 stellt sicher, das der Frame die Werte 0,1,2,3 enthält.
If M\frame = 3 Then ;* Der Frame, auf dem alle 3 Leuchten an sind, wurde erreicht.
;* Ein paar Blasen werden an den Koordinaten der Maschine erstellt.
Create_Blase(M\x, M\y - 64, Rand(1,3))
EndIf
EndIf

DrawImage(Machine, M\x, M\y, M\frame)
Next

;* Alle Blasen aktuallisieren:
For B = Each TSeifenblase

;* Die Blase existiert 3 1/4 Sekunden:
;* 3 Frames herumwobbeln nach der Entstehung für je 1/4 Sekunde.
;* Die Ausgebildete, stabile Blase für 2 Sekunden.
;* Und das Zerplatzen wird 1/2 Sekunde lang angezeigt.
If B\time < ms Then
B\time = ms + Rand(4,8)*50 ;* 200-400 in 50er Schritten
B\frame = (B\frame+1) Mod 5
If B\frame = 3 Then ;** Ausgebildete Blase
B\time = ms + Rand(2, 3)*1000 ;* 2 oder 3 Sekunden
ElseIf B\frame = 4 Then ;** Platzen
B\time = ms + Rand(300, 600)
ElseIf B\frame = 0 Then ;** Nach dem Platzen Löschen
Delete B
EndIf
EndIf

If B <> Null Then ;*** Prüfung ob B noch existiert... (wegen Delete im letzen Block)
;* Platzen am Bildschirmrand
If B\x =< 32 Or B\x => gfx_w-32 Or B\y =< 32 Then B\frame = 4

If B\frame <> 4 Then ;** Geplatzte Blasen bewegen sich nicht mehr...
B\x = B\x + B\x_speed
B\y = B\y + B\y_speed
EndIf

DrawImage(Bubbels, B\x, B\y, B\frame)
EndIf
Next

End Function
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)
  • Zuletzt bearbeitet von Xeres am Do, Apr 07, 2011 1:12, insgesamt einmal bearbeitet

PhillipB

BeitragSo, Apr 03, 2011 19:03
Antworten mit Zitat
Benutzer-Profile anzeigen
So diesmal habe ich mich auch mal dran gemacht und hier mein Code:
Code: [AUSKLAPPEN]
Graphics 640, 480, 16
SetBuffer BackBuffer()
Machine = LoadAnimImage("Machine.png", 128, 128, 0, 4)           ;Daten laden
Seifenblasen = LoadAnimImage("blasen.png", 64, 64,0, 5)

MaskImage Seifenblasen, 255, 0, 255                               ;Transparent effect
MaskImage Machine, 255, 0, 255


Global M_einstellung = 0                                         
Global S_einstellung# = 0
Global S_da# = 0.1
Global S_speed# = 340
Global S_anim# = 0



Timer=MilliSecs()+1000                                    ;Maschienen Timer
SeifenblasenTimer=MilliSecs()+5400                        ;SeifenblasenTimer
MS=MilliSecs()

While Not KeyHit(1)
   Cls


;Maschienen Ablauf:

   If Timer < MilliSecs() And M_einstellung = 0          ;Status änderung der Maschiene // Frame änderung durch M_einstellung
  M_einstellung = 1
  Timer=MilliSecs()+3000
Else If Timer < MilliSecs() And M_einstellung = 1
 M_einstellung = 2
  Timer=MilliSecs()+1000
Else If Timer < MilliSecs() And M_einstellung = 2
 M_einstellung = 3
  Timer=MilliSecs()+300
Else If Timer < MilliSecs() And M_einstellung = 3
 M_einstellung = 1
  Timer=MilliSecs()+8000
EndIf



;Seifenblase starten:


If M_einstellung = 3 Then                                ;Seifenblase erstellen
S_da = 0
EndIf


If S_da = 0 Then                                        ;Speed geht immer herunter da die Y koordinate ja auch nach unten steigt
S_speed = S_speed - 0.9
DrawImage Seifenblasen, 232, S_Y ,S_einstellung         ;S_einstellung steht für den jeweiligen Frame
EndIf

;Schnelligkeit:
S_Y = S_speed                                           ;S_Y ist für die Y Koordinaten der Seifenblase(Schnelligkeit)
;Weitere Einstellungen:
If S_da = 1 Then                                        ;Speed auf 340 für die Tiefste Koordinate stellen
S_speed = 340
EndIf

;Seifenblase gesamt:
If S_da = 0 And SeifenblasenTimer < MilliSecs() And S_einstellung = 0 Then
  S_einstellung = 1
  SeifenblasenTimer=MilliSecs()+1000
ElseIf SeifenblasenTimer < MilliSecs() And S_einstellung = 1 Then
  S_einstellung = 2
  SeifenblasenTimer=MilliSecs()+1000
ElseIf SeifenblasenTimer < MilliSecs() And S_einstellung = 2 Then
  S_einstellung = 3
  SeifenblasenTimer=MilliSecs()+4000
Else If SeifenblasenTimer < MilliSecs() And S_einstellung = 3 Then
 S_einstellung = 4
  Timer=MilliSecs()+7000
Else If SeifenblasenTimer < MilliSecs() And S_einstellung = 4 Then
 S_einstellung = 0
  Timer=MilliSecs()+8000
S_da = 1
EndIf



DrawImage Machine, 200, 350, M_einstellung                              ;Maschiene wird erstellt // M_einstellung steht für die Frames

   Flip
 
Wend
End


Die erklärung ist in den Kommentaren Wink
Ich fande die Timer variante am einfachsten also mit millisecs!

mfg
PhillipB.

ozzi789

BeitragSo, Apr 03, 2011 19:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Code: [AUSKLAPPEN]
;ozzi789 - BPS #5: Seifenblasenmaschine
;Initialisierung
AppTitle "Seifenblasenmaschine"
gfx_window_x=800
gfx_window_y=600

Graphics gfx_window_x,gfx_window_y,32,2
SetBuffer BackBuffer()

ClsColor (30,40,220)
timer=CreateTimer(60)

;Bilder Laden
gfx_img_machine =LoadAnimImage("Machine4x128.png",128,128,0,4)
gfx_img_bubble  =LoadAnimImage("Bubbels5x64.png",64,64,0,5)
MaskImage(gfx_img_machine,255,0,255)
MaskImage(gfx_img_bubble,255,0,255)

;Type für die Blasen erstellen
Type tbuble
   Field x
   Field y
   Field frame
End Type



While Not KeyHit(1)
   Cls
      If MilliSecs()>timecounter+500   ;Die Positionen der Blasen und den aktuellen Frame berechnen
         timecounter=MilliSecs()
      
         framecounter_img_machine=framecounter_img_machine+1   
         
         For t.tbuble= Each tbuble
         t.tbuble\frame=t.tbuble\frame+1 ;Frame immer erhöhen
         t.tbuble\y=t.tbuble\y-1         ;Immer ein px nach oben
         Next
         
         If framecounter_img_machine Mod 4 = 3 ;Falls Maschine wieder grün zeigt neue Blase erstellen
            t.tbuble = New tbuble
            t\x=(gfx_window_x-64)/2
            t\y=(gfx_window_y-(170))
            t\frame=3
         EndIf
      EndIf
   
      For t.tbuble= Each tbuble   ; Die Blasen zeichnen
      t.tbuble\y=t.tbuble\y-1
      t.tbuble\x=t.tbuble\x+Sin(t.tbuble\y+Rand(-20,20))
         If t.tbuble\y<50
            DrawImage gfx_img_bubble,t.tbuble\x,t.tbuble\y,4
         Else
            DrawImage gfx_img_bubble,t.tbuble\x,t.tbuble\y,t.tbuble\frame Mod 4
         EndIf
         
         If t.tbuble\y<20 ;Wenn sie ganz oben ist kann man sie löschen
         Delete t.tbuble
         EndIf
      Next
      DrawImage gfx_img_machine,(gfx_window_x-128)/2,gfx_window_y-128,framecounter_img_machine Mod 4 ;Die Maschine einzeichnen
    WaitTimer timer
   Flip 0
Wend


Sieht dann etwa so aus
user posted image

mfg
0x2B || ! 0x2B
C# | C++13 | Java 7 | PHP 5

Xeres

Moderator

BeitragMo, Apr 04, 2011 14:40
Antworten mit Zitat
Benutzer-Profile anzeigen
@PhillipB: Schön, dass du mitmachst. Scheint zu funktionieren, aber: Man sieht deine Blase weder herumwackeln noch zerplatzen. Du behandelst deine Variablen etwas komisch:
Code: [AUSKLAPPEN]
S_Y = S_speed
Wenn du Geschwindigkeit und Koordinaten mischst, kann man nur verwirrt werden. Ich würde eher S_Y_StartPosition o.ä. nehmen und S_speed sollte das sein, was es aussagt - die Geschwindigkeit die Hardcoded bei 0.9 liegt.

Werfen wir mal einen Blick auf die Maschinensteuerung:
BlitzBasic: [AUSKLAPPEN]
	If Timer < MilliSecs() And M_einstellung = 0
M_einstellung = 1
Timer=MilliSecs()+3000
Else If Timer < MilliSecs() And M_einstellung = 1
M_einstellung = 2
Timer=MilliSecs()+1000
Else If Timer < MilliSecs() And M_einstellung = 2
M_einstellung = 3
Timer=MilliSecs()+300
Else If Timer < MilliSecs() And M_einstellung = 3
M_einstellung = 1
Timer=MilliSecs()+8000
EndIf

Wenn immer wieder der Gleiche Ausdruck da steht, lässt sich was optimieren. Da die Bedingungen mit AND Verknüpft sind, kann man die Bedingungen auch verschachtelt schreiben:
BlitzBasic: [AUSKLAPPEN]
	If Timer < MilliSecs() Then
If M_einstellung = 0
M_einstellung = 1
Timer=MilliSecs()+3000
ElseIf M_einstellung = 1
M_einstellung = 2
Timer=MilliSecs()+1000
ElseIf M_einstellung = 2
M_einstellung = 3
Timer=MilliSecs()+300
ElseIf M_einstellung = 3
M_einstellung = 1
Timer=MilliSecs()+8000
EndIf
EndIf

Bei einfachen Zahlen, benötigt eine Select Case Konstruktion weniger Platz:
BlitzBasic: [AUSKLAPPEN]
	If Timer < MilliSecs() Then

Select M_einstellung
Case 0
M_einstellung = 1
Timer=MilliSecs()+3000
Case 1
M_einstellung = 2
Timer=MilliSecs()+1000
Case 2
M_einstellung = 3
Timer=MilliSecs()+300
Case 3
M_einstellung = 1
Timer=MilliSecs()+8000
End Select

EndIf
Ähnlich lässt sich auch Block mit der Seifenblase verkürzen.
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)

PhillipB

BeitragMo, Apr 04, 2011 18:16
Antworten mit Zitat
Benutzer-Profile anzeigen
Erstmal vielen dank für Die tipps Wink
Die Seifenblase zerplatzt aber.
Das mit dem herumm schwirren muss ich mir mal näher angucken.

Nova

BeitragSa, Jun 02, 2012 13:42
Antworten mit Zitat
Benutzer-Profile anzeigen
Zuerst wollte ich die Blasen noch etwas hin- und herschwingen lassen, habe das dann aber doch gelassen.

Dass die Seifenblasen leicht verzögert erstellt werden ist übrigens Absicht. Wink

Im Grunde funktioniert mein Programm nach folgendem Schema:
Erst werden 5 Maschinen erstellt. In der Hauptschleife werden dann immer alle Maschinen und alle Seifenblasen durchgegangen.
Für die einzelnen Teile der Bilder habe ich ein (nur schlecht erweiterbares) System auf If-Abfragen genutzt. Das war die einfachste Lösung für mich. Wink

BlitzBasic: [AUSKLAPPEN]
; Bereite alles vor, also die Grafik und die Timer
Graphics 800, 600, 0, 2
SetBuffer BackBuffer()
Local timer = CreateTimer(60)
SeedRnd (MilliSecs ())

; Definiere ein paar wichtige Variablen
Global blasenbilder = LoadAnimImage ("bubbels5x64.png", 64, 64, 0, 5)
Global maschinenbilder = LoadAnimImage ("machine4x128.png", 128, 128, 0, 4)
Global maschinen.Maschine
Global blasen.Blase
Local frame
Local i

; Überprüfung, ob die Bilder geladen werden konnten:
If blasenbilder = 0
RuntimeError "Das Bild bubbels5x64.png konnte nicht geladen werden!"
End
EndIf
If maschinenbilder = 0
RuntimeError "Das Bild machine4x128.png konnte nicht geladen werden!"
End
EndIf


; Maskenfarbe für die Bilder:
MaskImage blasenbilder, 255, 0, 255
MaskImage maschinenbilder, 255, 0, 255


; Wir erstellen 5 Maschinen als Beispiel:
For i = 1 To 5
maschinen.Maschine = New Maschine
Local abstand
maschinen\x = 154* (i -1) +26
maschinen\y = 600-128 ; Höhe des Fensters minus Höhe des Bildes
maschinen\zeit = MilliSecs ()
Next



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



; Und schon gehen wir in die Hauptschleife und starten das Programm
While Not KeyHit(1) ; Programm beenden mit Escape.
Cls
Color 255, 255, 255
Text 1, 1, "Escape zum Beenden des Programms"


; Gehe alle Maschinen durch:
For maschinen.Maschine = Each Maschine

; Je nach dem, wie viel Zeit seit der letzten Blase
; vergangen ist, wird ein anderer Frame gezeichnet:
If MilliSecs () - maschinen\zeit < 3000 Then
frame = 0
ElseIf MilliSecs () - maschinen\zeit < 4000
frame = 1
ElseIf MilliSecs () - maschinen\zeit < 5000
frame = 2
ElseIf MilliSecs () - maschinen\zeit < 6000
frame = 3
ElseIf MilliSecs () - maschinen\zeit >= 6000 ; Erstelle eine neue Blase
frame = 3
If Rand (1, 100) <= 5 Then
frame = 0
maschinen\zeit = MilliSecs ()
blasen.Blase = New Blase
blasen\x = maschinen\x +32
blasen\y = maschinen\y -32
blasen\zeit = MilliSecs ()
EndIf
EndIf

DrawImage maschinenbilder, maschinen\x, maschinen\y, frame
Next


; Gehe alle Blasen durch:
For blasen.Blase = Each Blase

blasen\y = blasen\y - 0.6

; Je nach dem, wie viel Zeit seit der Erstellung
; vergangen ist, wird ein anderer Frame gezeichnet:
If MilliSecs () - blasen\zeit < 500 Then
frame = 0
ElseIf MilliSecs () - blasen\zeit < 800
frame = 1
ElseIf MilliSecs () - blasen\zeit < 1100
frame = 3
ElseIf MilliSecs () - blasen\zeit < 1400
frame = 2
ElseIf MilliSecs () - blasen\zeit < 1800
frame = 3
ElseIf MilliSecs () - blasen\zeit < 2100
frame = 1
ElseIf MilliSecs () - blasen\zeit < 2400
frame = 3
ElseIf MilliSecs () - blasen\zeit < 2700
frame = 2
ElseIf MilliSecs () - blasen\zeit < 3000
frame = 3
ElseIf MilliSecs () - blasen\zeit < 3300
frame = 1
ElseIf MilliSecs () - blasen\zeit < 10000
frame = 3
ElseIf MilliSecs () - blasen\zeit < 10500
frame = 4
ElseIf MilliSecs () - blasen\zeit >= 10500
frame = -1
EndIf

If frame >= 0 Then
DrawImage blasenbilder, blasen\x, blasen\y, frame
Else
Delete blasen.Blase
EndIf
Next

WaitTimer timer
Flip
Wend

End ; Hier wird das Programm dann beendet.


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


; Neben ein paar Funktionen brauchen wir hier auch Types:
Type Maschine
Field x
Field y
Field zeit ; Zeit während der Erstellung der letzten Blase.
; Wie viel Zeit seit der letzten Blase vergangen ist:
; Vergangene Zeit zwischen 0 und 2999: Erster Frame
; zwischen 3000 und 3999: Zweiter Frame
; zwischen 4000 und 4999: Dritter Frame
; zwischen 5000 und 5999: Vierter Frame
; über 6000: Neue Blase, "zeit" wird wieder auf 0 gesetzt.
End Type

Type Blase
Field x# ; Float für Bewegungen unter 1 Pixel pro Frame.
Field y#
Field zeit ; Zeit während der Erstellung der Blase.
End Type
AMD Athlon II 4x3,1GHz, 8GB Ram DDR3, ATI Radeon HD 6870, Win 7 64bit

Neue Antwort erstellen


Übersicht BlitzBasic Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group