Bewegungslehre
-> Bouncing Ball
Das mit der Physik ist so ne Sache: es reizt mich ungemein damit
rumzuspielen, weils so schöne Formeln gibt, die man so schön
verwenden könnte. Aber bei der praktischen Anwendung stolper ich immer
wieder über dumme Probleme.
So hab ich mal was zusammengebastelt, was irgendwie zu funktionieren
scheint, aber ich weiß, daß es nicht wirklich korrekt ist.
Wer die folgenden Scripte korrigieren möchte, ist herzlich eingeladen.
:-)
Bouncing Ball
Phase 1 - Der Ball fällt, und fällt, und fällt,
und wird erstaunlicherweise immer schneller...
Ohne Physik ists so und so keine Zauberei. "pSpeed" sei eine Property, die die
aktuelle Geschwindigkeit enthält. Sie wird ständig durch einen fixen
Wert erhöht.
on exitFrame
pSpeed = pSpeed + pAcceleration
sprite(me.spriteNum).locV = sprite(me.spriteNum).locV
+ pSpeed
end |
Mit Physik schauts zunächst auch nicht viel schwieriger aus. Im
Physikbuch steht ne Formel, und die tippt man ab. Ach, und eine neue Property
namens "pGravity" erfindet man noch (und setzt den Wert gleich 9.81 oder
so ähnlich).
on exitFrame me
-- Physikbuch: s = s0 +
(v0 * t) + (b * t^2 / 2)
t = 1 -- vereinfachen wir mal den Zeitfaktor
pLocV = pLocV + (pSpeed * t) + (pGravity * t *
t / 2)
pSpeed = pSpeed + (pGravity * t)
sprite(me.spriteNum).locV = pLocV
end |
Phase 2 - Achtung Boden!
"Abprallen ist ja nicht schwer" denkt man sich, fragt ab, ob die Position
des Balls noch über dem Fußboden liegt, und tippt andernfalls
eine kleine if-then-Ausnahme. Und bei dieser Gelegenheit fällt einem
noch ein, daß man sich ja auch mit der Elastizität des Balls
beschäftigen sollte, woraufhin man klarerweise "pElasticity" kreiert,
und mal nen Wert von -0.8 probiert.
on exitFrame me
-- Physikbuch: s = s0 +
(v0 * t) + (b * t^2 / 2)
t = 1 -- vereinfachen wir mal den Zeitfaktor
pLocV = pLocV + (pSpeed * t) + (pGravity * t *
t / 2)
pSpeed = pSpeed + (pGravity * t)
if pLocV >= pGround then
pLocV = pGround
pSpeed = pSpeed * pElastic
end if
sprite(me.spriteNum).locV = pLocV
end |
|
|
Sieht ja hübsch aus, allerdings hört der blöde Ball
nimma auf zu hüpfen, obwohl man ihn doch deutlich bei jedem Aufprall
seiner Energie beraubt...
Ich habe einige Scripts vom BouncingBall im Internet gefunden,
die witzigerweise bei genauerer Betrachtung alle diesen Fehler aufweisen. Manchmal erst,
wenn man ein bischen mit den Werten rumspielt.
Der Grund für den Fehler ist aber glaube ich logisch, wie die
nebenstehnde Skizze verdeutlichen soll:
Zum Zeitpunkt, da die Position des Balls zum Fußboden
gezwungen wird, darf nicht einfach jene Geschwindigkeit in Rechnung gestellt
werden, die der Ball hätte, wenn er ohne Hindernis weitergeflogen
wäre.
Man muß sie neu berechnen! Juchu. ;-) |
|
Die Korrektur.
Wenn man die Formel aus dem Physikbuch ein bischen umdreht, sieht sie
folgendermaßen aus:
(b * t^2 / 2) + (v0 * t) + s0 - s = 0
Sämtliche Faktoren sind zu dem Zeitpunkt, da
der Ball den Boden berührt, bekannt: Die letze Position (s0), die
neue Position (s), die letzte Geschwindigkeit (v0), die Beschleunigung oder
Gravitation (b) - nur das "t", die verstrichene Zeit, ist das große
Fragezeichen.
Die umgedrehte Formel entspricht folgendem mathematischen
System ("quadratische Gleichung"):
(a * x^2) + (b * x) + c = 0
und dafür gibt es erneut eine Formel ("Große Lösungsformel"), um das x ausrechnen zu können:
x = (-b +- sqrt(b^2 - 4ac)) / 2a
Setzt man die richtigen Werte ein (und macht dabei hoffentlich keine
Fehler ;-) dann sieht das fertige Script ca. so aus:
on exitFrame me
t = 1 -- the time - lets make it easy
-- s = s0 + (v0 * t) + (b
* t^2 / 2)
newLocV = pLocV + (pSpeed * t) + (pGravity * t
* t / 2)
newSpeed = pSpeed + (pGravity * t)
if newLocV >= pGround then -- touching the ground
if newLocV > pGround then
--
(a * x^2) + (b * x) + c = 0
--> x = (-b +- sqrt(b^2 - 4ac)) / 2a
-- a ... pGravity/2
-- b ... pSpeed
-- c ... pLocV - pGround
partOfTheFormula = sqrt((pSpeed
* pSpeed) - (4 * (pGravity/2) * (pLocV - pGround)))
newT = (-pSpeed + partOfTheFormula)
/ pGravity
if newT < 0 or newT
> t then newT = (-pSpeed - partOfTheFormula) / pGravity
if newT > 0 then
newSpeed =
pSpeed + (pGravity * newT)
end if
end if
newLocV = pGround
newSpeed = pSpeed * pElastic
end if
pLocV = newLocV
pSpeed = newSpeed
sprite(me.spriteNum).locV = pLocV
end |
Phase 3 - und seitlich werfen, bitte!
Das Hinzufügen der horizontalen Bewegung ist eigentlich nicht schwierig,
weil sie ziemlich unabhängig vom Rest berechnet werden kann. Genaugenommen
müßte man zwar Korrekturen vornehmen, wenn der Ball am Boden
aufprallt, aber dafür war ich glücklicherweise zu faul. ;-)
Ein halbwegs funktionierendes Script ist dem nächsten Beispiel
zu entnehmen. Sieht ja eigentlich eh ganz cool aus, nicht?
|