5.12 Beispiel 10: Erweiterung des Ball-Beispiels

Das abschließende Beispiel zeigt, wie man bei unserem Ball-Beispiel aus dem letzten Unterkapitel auch die Dimensionen des Rechtecks dynamisch über ein Verhalten setzen kann. Es ist ohne weiteres möglich, das Rechteck im laufenden Programm zu verschieben, indem man es auf moveable setzt.

<img src="../grafik/bilder/beispiel10.jpg" width="512" height="384">

Das Rechteck-Objekt definiert dieses Rechteck, dessen einzige Aufgabe es ist, die Koordinaten der Rechteck-Ränder zu ermitteln (getLeft(), getRight(), getTop(), getBottom()). Über die Methode spriteAnmelden() teilt das Rechteck-Verhalten mit, in welchem Spritekanal das Rechteck liegt. Die Methode isReady() stellt fest, ob schon eine Anmeldung erfolgt ist.

-- das Rechteck, das als Begrenzer für die springenden Bälle dient
-- es muss ein Sprite angemeldet werden, damit das Skript funktioniert

property mSprite

on new me
-- Rechtecksprite ist anfangs noch undefiniert
mSprite = VOID
return me
end new

on spriteAnmelden me, spriteNummer
-- meldet das Rechteck-Sprite an
mSprite = sprite(spriteNummer)
end spriteAnmelden

on getLeft me
-- gibt die x-Koordinate der linken Kante des Rechtecks zurück
if me.isReady() then
return mSprite.locH
else
return VOID
end if
end getLeft

on getRight me
-- gibt die x-Koordinate der rechten Kante des Rechtecks zurück
if me.isReady() then
return mSprite.locH + mSprite.width
else
return VOID
end if
end getRight

on getTop me
-- gibt die y-Koordinate der oberen Kante des Rechtecks zurück
if me.isReady() then
return mSprite.locV
else
return VOID
end if
end getTop

on getBottom me
-- gibt die y-Koordinate der unteren Kante des Rechtecks zurück
if me.isReady() then
return mSprite.locV + mSprite.height
else
return VOID
end if
end getBottom

on isReady me
-- prüft, ob das Rechteckobjekt schon initialisiert wurde,
-- d.h. mSprite gesetzt ist
return objectP(mSprite)
end isReady

Das zugehörige Rechteck-Verhalten setzt voraus, dass das Rechteck-Objekt schon initialisiert und der Globalen gRechteckObj zugewiesen wurde, was in unserem Beispiel im prepareMovie-Handler geschieht.

-- Verhalten, dass das begrenzende Rechteck anmeldet;
-- auf ein Sprite ziehen, das als Begrenzer für
-- die Bälle dienen soll

global gRechteckObj

property spriteNum

on beginSprite me
-- dieses Sprite beim Rechteck-Objekt anmelden
gRechteckObj.spriteAnmelden(spriteNum)
end beginSprite

on getBehaviorDescription me
return "Dieses Verhalten auf ein Sprite ziehen, das" &
"als Begrenzer für die hüpfenden Bälle dienen soll."
end getBehaviorDescription

Das Skript zum neuen BallObjekt sieht nun wie folgt aus:

global gRechteckObj

property mSprite, mBewegungsvektor

on new me, spriteNummer, anfangsVektor
-- Sprite-Kanal
mSprite = sprite(spriteNummer)
-- anfänglicher Bewegungsvektor: Werte aus Behavior einlesen
mBewegungsvektor = anfangsVektor
return me
end new

on stepframe me
newLoc = mSprite.loc + mBewegungsvektor
-- aktuelle Kanten des Balls bestimmen
linkeKante = newLoc[1] - mSprite.member.regpoint[1]
rechteKante = newLoc[1] + mSprite.member.width - mSprite.member.regpoint[1]
obereKante = newLoc[2] - mSprite.member.regpoint[2]
UntereKante = newLoc[2] + mSprite.member.height - mSprite.member.regpoint[2]

-- Kollission kann nur geprüft werden, wenn Rechteckobjekt
-- schon initialisiert ist
if gRechteckObj.isReady() then
if (linkeKante < gRechteckObj.getLeft()) then
-- Ball prallt von linker Kante ab
-- x-Koordinate an linker Kante spiegeln
newLoc[1] = newLoc[1] - 2*(linkeKante - gRechteckObj.getLeft())
-- Bewegungsrichtung umkehren
mBewegungsvektor = mBewegungsvektor * point(-1, 1)
else
if (rechteKante > gRechteckObj.getRight()) then
-- Ball prallt von rechter Kante ab
-- x-Koordinate an rechter Kante spiegeln
newLoc[1] = newLoc[1] - 2*(rechteKante - gRechteckObj.getRight())
-- Bewegungsrichtung umkehren
mBewegungsvektor = mBewegungsvektor * point(-1, 1)
end if
end if
if (obereKante < gRechteckObj.getTop()) then
-- Ball prallt von oberer Kante ab
-- y-Koordinate an oberer Kante spiegeln
newLoc[2] = newLoc[2] - 2*(obereKante - gRechteckObj.getTop())
-- Bewegungsrichtung umkehren
mBewegungsvektor = mBewegungsvektor * point(1, -1)
else
if (untereKante > gRechteckObj.getBottom()) then
-- Ball prallt von unterer Kante ab
-- y-Koordinate an unterer Kante spiegeln
newLoc[2] = newLoc[2] - 2*(untereKante - gRechteckObj.getBottom())
-- Bewegungsrichtung umkehren
mBewegungsvektor = mBewegungsvektor * point(1, -1)
end if
end if
end if
-- Sprite aktualisieren
mSprite.loc = newLoc
end stepframe

Ein kleiner Trick wurde bei dem Darsteller angewendet, der den erklärenden Text enthält. Damit die schwarze Schrift immer innerhalb des Rechtecks liegt und lesbar bleibt, wurde einfach ein Ball-Verhalten mit dem Bewegungsvektor (0|0) am Textdarsteller angebracht.

Quellcode des Beispiels

5.11 Kommunikation zwischen Verhalten und Objekten 6 Beispiele