BPS #5: Seifenblasenmaschine - Auswertung

Übersicht BlitzMax, BlitzMax NG 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:
BlitzMax: [AUSKLAPPEN]
SuperStrict
Const gfx_w:Int = 800
Const gfx_h:Int = 600
Graphics(gfx_w, gfx_h)
SetBlend(AlphaBlend)
Local FrameTimer:TTimer = TTimer.Create(60), ms:Int

AutoMidHandle(True)
SetMaskColor(255, 0, 255)

Local Bubbels:TImage = LoadAnimImage("Bubbels5x64.png", 64, 64, 0, 5)
Local Machine:TImage = LoadAnimImage("Machine4x128.png", 128, 128, 0, 4)

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

'*** Die Seifenblase:
Local B_x:Int = -1, B_y:Int = -1
Local B_Frame:Int, B_Time:Int

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)
FrameTimer.Wait()
Until KeyHit(KEY_ESCAPE)

End


Mit Types:
BlitzMax: [AUSKLAPPEN]
SuperStrict
Const gfx_w:Int = 800
Const gfx_h:Int = 600
Graphics(gfx_w, gfx_h)
SetBlend(AlphaBlend)
Local FrameTimer:TTimer = TTimer.Create(60)
Global ms:Int, mh1:Int, mx:Int, my:Int

AutoMidHandle(True)
SetMaskColor(255, 0, 255)

Global Bubbels:TImage = LoadAnimImage("Bubbels5x64.png", 64, 64, 0, 5)
Global Machine:TImage = LoadAnimImage("Machine4x128.png", 128, 128, 0, 4)

'*** Eine Maschine erstellen:
TMaschine.Create(gfx_w / 2, gfx_h - 64)

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

'* Aktualisierung aller Objekte:
TMaschine.Update()
TSeifenblase.Update()

If mh1 Then
'* Bei einem Mausklick weitere Maschinen erstellen
TMaschine.Create(mx, gfx_h - 64)
EndIf

Flip(0)
FrameTimer.Wait()
Until KeyHit(KEY_ESCAPE)

End

Type TMaschine
Field x:Int, y:Int
Field frame:Int, time:Int
'* In BlitzBasic hat jeder Type Automatisch eine Liste,
'* in BlitzMax kümmern wir uns selbst darum.
Global liste:TList = New TList

Method New()
'* Sogennantes Überladen der New-Methode.
'* d.h. New erstellt jetzt nicht nur ein neues TMaschine-Objekt
'* sondern trägt es auch gleich in die Liste ein.
TMaschine.liste.AddLast(Self)
End Method

Function Create(_X:Int, _Y:Int)
'** Eine neue Maschine erstellen, und die Koordinaten zuweisen.
Local M:TMaschine = New TMaschine
M.x = _X
M.y = _Y
End Function

Function Update()
' * Alle Maschinen nacheinander abarbeiten:
For Local M:TMaschine = EachIn TMaschine.liste

'* 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.
TSeifenblase.Create(M.x, M.y - 64, Rand(1, 3))
EndIf
EndIf

DrawImage(Machine, M.x, M.y, M.frame)
Next
End Function

End Type

Type TSeifenblase
Field x:Float, y:Float
Field x_speed:Float, y_speed:Float
Field frame:Int, time:Int

Global liste:TList = New TList

Method New()
'* Selbiges wie bei der TMaschine New Methode
TSeifenblase.liste.AddLast(Self)
End Method

Function Create(_X:Int, _Y:Int, count:Int)
For Local i:Int = 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()
'* Alle Objekte in der Liste durchgehen:
For Local B:TSeifenblase = EachIn TSeifenblase.liste
'* 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
TSeifenblase.liste.Remove(B)
'* Prüfung ob B noch existiert entfällt - auch wenn das Objekt aus
'* der Liste ausgetragen wurde, ist es local noch vorhanden.
'* Am Ende der Funktion wird der GC (Garbage Collector) merken, dass
'* auf das Objekt nicht mehr zugegriffen werden kann, und es demnächst
'* aus dem Speicher werfen - darum wird in BlitzMax kein "Delete" verwendet.
EndIf
EndIf

'* 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_speed
B.y:+B.y_speed
'* x:+1 == x = x + 1
EndIf

DrawImage(Bubbels, B.x, B.y, B.frame)
Next
End Function

End Type
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:13, insgesamt einmal bearbeitet

BlitzMoritz

BeitragSo, Apr 03, 2011 18:45
Antworten mit Zitat
Benutzer-Profile anzeigen
BlitzMax: [AUSKLAPPEN]

'Viel Lernspass beim BPS#5 wuenscht BlitzMoritz:
'Erstelle mit Mausklick beliebig viele Seifenblasenmaschinen!

SuperStrict 'jede benutzte Variable muss vorher genau definiert werden
Graphics 1000,600
SetBlend ALPHABLEND 'weil beim Zerplatzen stufenlose Transparenzwerte vorkommen
SetMaskColor 255,0,255 'weil die Bilddateien diese Maskenfarbe besitzen
Local Timer:TTimer = CreateTimer(60) 'weil's zum guten Ton gehoert und den Prozessor schont

'Wir laden die zur Verfuegung gestellten Bilder:

Global MachineImage:TImage = LoadAnimImage("Machine4x128.png", 128, 128, 0, 4)
MidHandleImage(MachineImage)

Global BubbleImage:TImage = LoadAnimImage("Bubbels5x64.png", 64, 64, 0, 5)
MidHandleImage(BubbleImage) '(Anmerkung: Im vorliegenden Code wird nur der vierte und fuenfte Frame genutzt!)
'Fuer die spaetere Kollisionspruefung merken wir uns den Radius der Seifenblasen:
Global BubbleRadius:Int = 0.5*ImageWidth(BubbleImage)

'So, alle Vorbereitungen sind getroffen, jetzt geht es richtig los:

'Um beliebig viele Seifenblasenmaschinen hinzufuegen und verwalten zu koennen, erstellen wir eine Liste
Global MachineList:TList = CreateList()
'aus Objekten der wie folgt definierten Klasse TMachine ...

Type TMachine

'mit folgenden internen Variablen:

Field x:Int, y:Int 'die Position der Maschine
Field Time:Int 'den (Start-)Zeitpunkt fuer bestimme Aktionen
Field FrameDuration:Int 'die Dauer, die fuer einen der vier Zustaende des periodischen Ablaufs reserviert wird
Field Frame:Byte 'quasi die Nummer eines Zustandes, gleichzeitig der Frame des AnimImage
Field BubbleCreated:Byte 'eine Hilfsgroesse, die speichert, ob in der letzten (Gruen-)Phase bereits die Seifenblase erstellt wurde

Function add()

'der Konstruktor erstellt ein neues Objekt der Klasse TMachine:
Local NewMachine:TMachine = New TMachine

'bereitet es gezielt vor:
NewMachine.x = MouseX()
NewMachine.y = GraphicsHeight() - ImageHeight(MachineImage)/2
NewMachine.Time = MilliSecs()
NewMachine.FrameDuration:Int = Rand(250,1000) 'ein kompletter Durchgang dauert also zwischen einer und vier Sekunden

'und fuegt es der globen Liste aller Seifenblasenmaschinen hinzu:
ListAddLast(MachineList, NewMachine)

End Function

'In der folgenden klasseninternen Prozedur wird nicht nur das Maschinenbild gezeichnet,
'sondern auch der periodische Ablauf und das Bilden neuer Seifenblasen organisiert:
Method draw()

DrawImage MachineImage, x, y, Frame

If MilliSecs() - Time > FrameDuration Then 'nach Ablauf des festgelegten Zeitrahmens

Frame = ( Frame + 1 ) Mod 4 'wird weitergezaehlt zum naechsten Zustand,
Time = MilliSecs() 'wiederum der Zeitpunkt aktualisiert
If Frame = 3 Then 'und falls wir uns in der vierten ("Gruen-")Phase befinden
If BubbleCreated = False Then 'und darin noch keine neue Blase erschaffen haben:
BubbleCreated = True
TBubble.add(x, y-38, FrameDuration) 'eine neue Blase erschaffen (und sie der Seifenblasen-Liste hinzufuegen)
End If
Else
BubbleCreated = False
End If
End If

End Method

End Type

'Das war's schon mit der Maschinenklasse.
'Aufwendiger wird die Klasse der Seifenblasen "TBubble",
'deren Objekte wir wiederum in einer Liste sammeln:
Global BubbleList:TList = CreateList()

Type TBubble

'mit folgenden internen Variablen:

Field x_Start:Float, y_Start:Float, x:Float, y:Float 'Diverse Positionsvariablen der Seifenblase

Field Zoom:Float 'der Zoom bzw. die feste Groesse der Blase, festgelegt beim "Aufblasen"
Field xScale:Float, yScale:Float 'die horizontale und vertikale Verzerrung, bedingt durch das Blubbern
'(Lasst uns die Animationsmoeglichkeiten von BlitzMax nutzen!)
Field RGB:Int[] 'verschiedene Farben machen immer Spass...

Field Time:Int 'der (Start-)Zeitpunkt fuer bestimme Aktionen
Field WayX:Int, WayY:Int 'die Richtung und (indirekt) die Geschwindigkeit, mit der die Blase fortfliegen wird
Field Phase:Byte 'einer der drei Zustaende, in denen sich die Blase befindet
Field Duration:Float 'z.T. die jeweilige Dauer oder die Geschwindigkeit, die fuer einen Zustand reserviert wird

Function add(x:Int, y:Int, Duration:Int)

'der Konstruktor erstellt ein neues Objekt der Klasse TBubble:
Local NewBubble:TBubble = New TBubble

'bereitet es gezielt vor, z.B. die uebergebenen (Start-)Positionen:
NewBubble.x_Start = x
NewBubble.y_Start = y
NewBubble.x = x
NewBubble.y = y

'die Dauer der 1.Phase des "Aufblasens":
NewBubble.Duration = 2 * Duration '(abhaengig von der Langsamkeit der Maschine, die die Seifenblase erstellt hat)

'die feste Groesse bzw. der Zoomfaktor soll abhaengig sein von der Dauer des Aufblasens:
NewBubble.Zoom = NewBubble.Duration / 1200.0

'die zufaellige Richtung und Geschwindigkeitkeit der Flug-Bewegungen:
NewBubble.WayX = Rand(-100,+100)
NewBubble.WayY = 150 + Rand(0, 100)

'die zufaellige Farbtoenung:
NewBubble.RGB = [Rand(32,255), Rand(32,255), Rand(32,255)]

'der Startzeitpunkt fuer die erste Animationsphase:
NewBubble.Time = MilliSecs()

'zum Schluss wird das Objekt der globen Liste aller Seifenblasen hinzugefuegt:
ListAddLast(BubbleList, NewBubble)

End Function


'In der folgenden klasseninternen Prozedur wird nicht nur das Seifenblasenbild gezeichnet,
'sondern auch der Ablauf von drei verschiedenen Phasen der Seifenblase organisiert:
Method draw:Byte() '(gibt "True" zurueck, wenn die Seifenblase fertig geplatzt ist)

SetColor RGB[0], RGB[1], RGB[2] 'die individuelle Farbe festlegen

Local Value:Float = (MilliSecs() - Time) / Duration 'der Fortschrittswert der Animationen

If Phase = 0 Then 'der Moment des "Aufblasens" in der Maschine

'da die Maschine die Blase nach Oben hin herausblaest, soll sie zuerst auch so verzerrt werden:
xScale = Value * 0.75 * Zoom
yScale = Value * 1.25 * Zoom
y = y_Start - Value * 32 * Zoom
SetScale xScale, yScale
DrawImage BubbleImage, x, y, 3

If Value >= 1 Then 'die erste Phase ist vorbei, die Blase fertig aufgeblasen
y_Start = y 'ein "Update" der Positionsvariablen,
Duration = Zoom * 1000.0 'der Animationsdauer (bzw. -Geschwindigkeit)
Phase = 1 'und ab in die naechste Phase!
Time = MilliSecs() 'neuer Start-Zeitpunkt
End If

ElseIf Phase = 1 Then 'der Moment des Fliegens

If Value <= 1 Then
'durch das Verzerren beim Aufblasen soll die Blase zunaechst noch weiter hin- und herwabern. Dafuer sorgt
'die Periodik des Kosinus. Das Argument 1440 bedeutet vier Mal, und durch die +180 enden wir bei Null.
'Der zusaetzliche Faktor *(1-Value) sorgt dafuer, dass diese Verzerrung mit der Zeit weniger wird.
'Darum wird auch klar, warum diese Verzerrung nur vorgenommen wird, solange der Value-Wert <= 1 ist.
xScale = Zoom * ( 1 - 0.25 * Cos( Value * (1440 + 180) ) * (1-Value) )
yScale = Zoom * ( 1 + 0.25 * Cos( Value * (1440 + 180) ) * (1-Value) )
End If
SetScale xScale, yScale

'die Blase soll sich anfangs, durch das Abloesen von der Maschine, schnell fortbewegen und sich
'dann verlangsamen. Daher nehmen wir statt dem statisch-linearen Value-Wert lieber seine Wurzel:
x = x_Start + Sqr(Value) * WayX
y = y_Start - Sqr(Value) * WayY

DrawImage BubbleImage, x, y, 3

'Da die Blase nun frei in der Luft ist, muss ab jetzt geprueft werden, ob sie irgendwo anstoesst ...
If collision() = True Then 'falls ja ...
Phase = 2 'dann geht's bereits jetzt in die letzte, dritte Phase der Seifenblase,
Duration = Zoom * 200.0 'die natuerlich, abhaengig von ihrer Groesse, sehr kurz dauern soll!
Time = MilliSecs()
End If

Else 'Phase = 2 'der Moment des Zerplatzens

'Schnelles Groesserwerden,
SetScale Zoom * 2 * Value, Zoom * 2 * Value
'verbunden mit transparentem Aufloesen:
SetAlpha 0.75 * (1-Value)
DrawImage BubbleImage, x, y, 4
SetAlpha 1

'falls das Zerplatzen fertig ist, wird mit
If Value >= 1 Then Return True
''gemeldet'', dass die Seifenblase "tot" ist und aus der Liste genommen werden kann/muss!

End If

End Method

'In der folgenden klasseninternen Prozedur wird geprueft, ob die Seifenblase irgendwo "anstoesst" und zerplatzen soll.
'Anmerkung: Es waere guenstiger, den Kollisionstest zweier Blasen in eine externe Function auszulagern, welche
'nur diejenigen Blasen-Paare prueft, die noch nicht geprueft wurden. Die hiesige Method wird fuer jede Blase durchlaufen,
'testet also jede Paarung doppelt. Der Verständlich- und Uebersichtlichkeit halber belassen wir es jetzt aber so, wie es ist:
Method collision:Byte() '(gibt "True" zurueck, falls ja)

'Kollision mit dem Bildschirmrand?
If x - xScale * BubbleRadius < 0 Then Return True 'Links?
If x + xScale * BubbleRadius > GraphicsWidth() Then Return True 'Rechts?
If y - yScale * BubbleRadius < 0 Then Return True 'Oben?

'Kollision mit anderen Seifenblasen? Also alle vorhandenen testen (wie gesagt: eigentlich zu viele!):
For Local Bubble:TBubble = EachIn BubbleList

If Bubble.x <> x Or Bubble.y <> y Then 'die eigene Blase muss natuerlich ausgeschlossen werden!

'Im Folgenden reicht es nicht, sich auf Kreise zu beschraenken. Da die Seifenblasen bereits in ihrer
'Phase 1 aufeinandertreffen koennen, in der sie noch verzerrt "umherwabern", muss man idealer
'Weise ueberpruefen, ob sich die zwei Blasen-Ellipsen ueberschneiden:

'Als erstes messen wir den Abstand der beiden Blasenzentren:
Local CenterDistance:Float = Sqr( (Bubble.x - x)*(Bubble.x - x) + (Bubble.y - y)*(Bubble.y - y) )
'und den Winkel, den die beiden Mittelpunkte zueinander einnehmen:
Local Angle:Float = ATan2(Bubble.y - y, Bubble.x - x)

'Dann bestimmen wir den variablen Ellipsenradius, den die beiden Blasenellipsen beim gemessenen Winkel einnehmen:
Local Border_Distance1:Float = Sqr( (Bubble.xScale * BubbleRadius * Cos(Angle))^2 + (Bubble.yScale * BubbleRadius * Sin(Angle))^2 )
Local Border_Distance2:Float = Sqr( (xScale * BubbleRadius * Cos(Angle))^2 + (yScale * BubbleRadius * Sin(Angle))^2 )

'(Anmerkungen: Bei den vorangegangenen drei Abstandsberechnungen haetten wir genauso gut die Wurzel
'weglassen, also ihre Quadrate nehmen und vergleichen koennen. Das haette Rechenzeit gespart, aber
'der besseren Vorstellung halber belassen wir es jetzt bei den echten Abstaenden bzw. Ellipsenradien)

'Zum Schluss testen wir, ob die Summe dieser Ellipsenradien kleiner als der Abstand der Mittelpunkte ist:
If Border_Distance1 + Border_Distance2 >= CenterDistance Then 'dann ist's passiert !
'Nicht vergessen, auch die andere Blase in die Zerplatzen-Phase 2 zu schicken:
Bubble.Phase = 2
Bubble.Duration = Bubble.Zoom * 200.0
Bubble.Time = MilliSecs()
Return True
End If

End If
Next

End Method

End Type

'Zum Schluss folgt die eigentliche Hauptschleife:

While Not KeyDown(KEY_ESCAPE) And Not AppTerminate()
Cls

'Alle Seifenblasen malen und verwalten:
For Local Bubble:TBubble = EachIn BubbleList
If Bubble.draw() = True Then 'die Seifenblase ist fertig zerplatzt!
ListRemove(BubbleList, Bubble) 'Seifenblase aus der Liste entfernen!
Bubble = Null 'Objekt entfernen, damit der Speicher nicht unnoetig voll wird!
End If
Next

'Vorangegangene Werte rueckgaengig machen
SetColor 255,255,255
SetScale 1,1

'Alle Maschinen verwenden:
For Local Machine:TMachine = EachIn MachineList
Machine.draw()
Next

'Und die simple Benutzereingabe per Mausklick ergaenzen:
SetAlpha 0.5
DrawImage MachineImage, MouseX(), GraphicsHeight() - ImageHeight(MachineImage)/2
SetAlpha 1
SetColor 0,0,0
DrawText "Mausklick!", MouseX()-36, GraphicsHeight() - 16
If MouseHit(1) Then TMachine.add() 'Mit Mausklick eine neue Maschine hinzufuegen

Flip
WaitTimer(Timer)
Wend

skey-z

BeitragSo, Apr 03, 2011 19:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Eine kleine Einführung

Arrow Generatoren
Der Benutzer kann auswählen, wieviele Generatoren insgesamt erstellt werden
Jeder Generator hat einen eigenen Countdown, der beim Erstellen übergeben werden kann, im Beispiel habe ich dafür 500-2000 Millisekunden eingestellt.

Arrow Blasen
Sobald ein Generator genügend Blasenwasser gesammelt hat(Anzeige wird grün) wird automatisch eine Blase in einer Zufallsfarbe erzeugt.
Die Blase vergrößert sich, solange bis ihre Maximale größe errreicht ist, danach hat sie genug auftrieb, um nach oben zu steigen.
Berührt eine Blase eine andere oder den Bildschirmrand, zerplatzt diese und wird ausgeblendet.

BlitzMax: [AUSKLAPPEN]

Rem
Project: Bubbles 2
Version: BPS#5
Author: skey-z
EndRem


'Voreinstellungen
SuperStrict
SeedRnd MilliSecs()
AutoMidHandle True

'Grafikeinstellungen
Global gWidth:Int = 800
Global gHeight:Int = 600
Local lTimer:TTimer = CreateTimer(60)

Graphics 800, 600

'Bilder laden
SetMaskColor 255, 0, 255
Local imgGen:TImage = LoadAnimImage("maschine.png", 128, 128, 0, 4)
Local imgBub:TImage = LoadAnimImage("blase.png", 64, 64, 0, 5)

'Generatoren erstellen
Local maxGens:Int = 6
For Local gens:Int = -(maxGens-1)/2 To (maxGens-1)/2
Local genPosX:Int = (gWidth/2) - (gens*128)
Local genPosY:Int = (gHeight-ImageHeight(imgGen)/2)
TGenerator.Create(genPosX, genPosY, Rand(500, 2000))
Next


'Hauptschleife
While Not (KeyHit(KEY_ESCAPE) Or AppTerminate())

WaitTimer lTimer

'Update
TGenerator.Update()
TBlase.Update(imgBub)

'draw
SetBlend(ALPHABLEND)
TGenerator.Draw(imgGen)
tBlase.Draw(imgBub)

SetColor(255, 255, 255)
SetAlpha(1)
SetScale(1,1)
SetBlend(ALPHABLEND)
DrawText("Generatoren: " + CountList(TGenerator._genList), 5, 5)
DrawText("Blasen: " + CountList(TBlase._bubList), 5, 20)

Flip
Cls
Wend

TGenerator.DeleteAll()

End

Rem
Hier wird nun der Type für die Maschine erstellt.
Jede Maschine soll einen separaten Timer haben.
EndRem

Type TGenerator

'Listeneintrag
Global _genList:TList = CreateList()
Field _genLink:TLink

'Position
Field _genX:Int
Field _genY:Int

'Timer
Field _genStart:Int
Field _genUpdate:Int

'Status(ohne, rot, gelb, grün)
Field _genState:Byte

'Generator erstellen
Function Create:TGenerator(x:Int, y:Int, update:Int)
Local gen:TGenerator = New TGenerator
gen._genX = x
gen._genY = y
gen._genStart = MilliSecs()
gen._genUpdate = update
Return gen
End Function

'Generatoren aktualisieren
Function Update:TGenerator()
For Local gen:TGenerator = EachIn TGenerator._genList
If (MilliSecs()>(gen._genStart+gen._genUpdate)) Then
gen._genState = (gen._genState + 1) Mod 4
gen._genStart = MilliSecs()

'Bei grün wird die Blase erstellt
If gen._genState = 3 Then TBlase.Create(gen._genX, gen._genY-64, Rand(5,10))
EndIf
Next
End Function

'Generatoren darstellen
Function Draw:TGenerator(img:TImage)
For Local gen:TGenerator = EachIn TGenerator._genList
DrawImage img, gen._genX, gen._genY, gen._genState
Next
End Function

'Alle Generatoren löschen
Function DeleteAll:TGenerator()
For Local gen:TGenerator = EachIn TGenerator._genList
gen.Remove()
Next
End Function

'Generator automatisch in die Liste eintragen
Method New()
_genLink = _genList.AddLast(Self)
End Method

'Generator automatisch aus der liste Löschen
Method Remove()
_genLink.Remove()
End Method
End Type


Rem
Der Type für die Seifenblasen.
Seifenblasen sollen in einem Winkel von -60 bis +60 Grad aufsteigen.
Jede Seifenblase haet eine Lebenszeit, im ersten drittel ist sie noch relativ instabil und kann platzen.
Hat die Seifenblase sich stabilisiert, kann si nur noch durch ihr ableben oder die Berührung mit dem
Rand zerplatzen
EndRem

Type TBlase

'Listeneintrag
Global _bubList:TList = CreateList()
Field _bubLink:TLink

'Position
Field _bubX:Float
Field _bubY:Float
Field _bubAngle:Int

'Farbe
Field _bubColR:Byte
Field _bubColG:Byte
Field _bubColB:Byte
Field _bubAlpha:Float

'Status und Groeße
Field _bubScale:Float
Field _bubState:Byte
Field _bubStable:Byte
Field _bubChange:Byte

'Timer
Field _bubStart:Int
Field _bubUpdate:Int
Field _bubLifeStart:Int
Field _bubLifeEnd:Int

'Blase erstellen
Function Create:TBlase(x:Int, y:Int, lifetime:Int)
Local bub:TBlase = New TBlase
bub._bubX = x
bub._bubY = y
bub._bubAngle = Rand(-60,60)

bub._bubColR = Rand(255)
bub._bubColG = Rand(255)
bub._bubColB = Rand(255)
bub._bubAlpha = 1

bub._bubScale = 1.0/64
bub._bubState = 0
bub._bubStable = False

bub._bubStart = MilliSecs()
bub._bubUpdate = 250
bub._bubLifeStart = MilliSecs()
bub._bubLifeEnd = lifetime*1000

Return bub
End Function

'Blase aktualisieren
Function Update:TBlase(img:TImage)
For Local bub:TBlase = EachIn TBlase._bubList


If (bub._bubState < 4) Then

'Blase generieren/vergrößern
If (bub._bubScale < 1)
bub._bubScale :+ 1.0/64
Else
bub._bubScale = 1

'Blase bewegen
bub._bubX = bub._bubX + Sin(bub._bubAngle)*1
bub._bubY = bub._bubY - Cos(bub._bubAngle)*1
EndIf

If (MilliSecs() > (bub._bubStart+bub._bubUpdate)) Then

If (bub._bubScale >= 1) Then

'Runde Blase
If (bub._bubStable) Then
bub._bubState = 3

'Blasse verkleinern/vergrößern
Else
bub._bubChange = (1 - bub._bubChange)
bub._bubState = 1 + bub._bubChange
EndIf

bub._bubStart = MilliSecs()
EndIf
EndIf

'Sobald eine gewisse Zeit abgelaufen ist, bleibt die Blase stabil
If (MilliSecs() > (bub._bubLifeStart + bub._bubLifeEnd))
bub._bubStable = True
EndIf

'Kollision mit dem Rand
If (bub._bubX < 32) Or (bub._bubX > gWidth-32) Or (bub._bubY < 32) Then
bub._bubState = 4
EndIf

'Prüfe auf Kollision mit anderer Blase
For Local another:TBlase = EachIn TBlase._bubList
If Not (bub = another) Then
If ImagesCollide(img, bub._bubX, bub._bubY, bub._bubState, img, another._bubX, another._bubY, another._bubState) Then
If (another._bubState < 4) And (bub._bubState < 4)
bub._bubState = 4
another._bubState = 4
EndIf
EndIf
EndIf
Next
Else
'Sobald die Blase zerborsten ist...
If (MilliSecs() > (bub._bubStart+100))
bub._bubY :+ 5 ' nach unten verschieben
bub._bubAlpha :- 0.1 ' ausblenden
bub._bubScale :- 1.0/16 ' verkleinern
bub._bubStart = MilliSecs()
EndIf
EndIf

'Blase löschen wenn sie nicht mehr zu sehen ist
If (bub._bubAlpha <= 0) Then bub.Remove

Next
End Function

'Blase darstellen
Function Draw:TBlase(img:TImage)
For Local bub:TBlase = EachIn TBlase._bubList

SetColor(bub._bubColR, bub._bubColG, bub._bubColB)
SetScale(bub._bubScale, bub._bubScale)
SetAlpha(bub._bubAlpha)
SetBlend(LIGHTBLEND)

DrawImage(img, bub._bubX, bub._bubY, bub._bubState)

Next
End Function

'Blase automatisch in die Liste eintragen
Method New()
_bubLink = _bubList.AddLast(Self)
End Method

'Blase automatisch aus der Liste austragen
Method Remove()
_bubLink.Remove()
End Method
End Type
Awards:
Coffee's Monatswettbewerb Feb. 08: 1. Platz
BAC#57: 2. Platz
Twitter

Xeres

Moderator

BeitragMo, Apr 04, 2011 14:48
Antworten mit Zitat
Benutzer-Profile anzeigen
Sehr schöne Ergebnisse. Smile
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)

skey-z

BeitragMo, Apr 04, 2011 18:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich muss aber auch mal zugeben, dass mir das von Moritz besser gefällt

besonders die schnelle steigung am Anfang und das schnelle zum langsammen "wabbeln", sowie die unterschiedlichen Größen(darauf hätte man auch selber kommen können verdammt Wink )
Awards:
Coffee's Monatswettbewerb Feb. 08: 1. Platz
BAC#57: 2. Platz
Twitter

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group