- 2008-07-28 (Mon) 00:08
- ActionScript , Flash/Flex
さて、今回は重力の働きを再現してみます。 前回はビリヤード台を上から見たようなイメージのものだったけど、それでは重力を観察できないため、横から見たイメージでいきます。 水槽の中でバウンドしているボールという感じになるでしょう。
前回の修正
前回のコードのままでは、ボールが枠の外にでてしまう可能性があります。 それを防ぐために修正を入れましょう。
onEnterFrame関数のはみ出しチェック内を以下のように修正します。
//画面領域からはみ出した場合は、移動量の正負反転
//横方向のはみ出しチェック
if(ball.x - ballR < 0){
//左方向にはみ出した
vx *= -1;
ball.x = ballR;
}else if(stage.stageWidth < ball.x + ballR){
//右方向にはみ出した
vx *= -1;
ball.x = stage.stageWidth - ballR;
}
//縦方向のはみ出しチェック
if(ball.y - ballR < 0){
//上方向にはみ出した
vy *= -1;
ball.y = ballR;
}else if(stage.stageHeight < ball.y + ballR){
//下方向にはみ出した
vy *= -1;
ball.y = stage.stageHeight - ballR;
}
はみ出したボールの位置を壁にピッタリつくところにセットしています。 座標がはみ出したままだと、何かの拍子に壁に入り込んでしまうことがあるためです。 では、今回の課題に入っていきましょう。
等加速度運動
今回の一番の肝がこれです。等加速度運動。漢字は似てるけど最初にやった等速直線運動とは別のものです。 ちなみに等速直線運動を少し思い出してみましょう。
物体が直線上をずっと同じ速度で運動する
でしたね。 地球上では摩擦があるので実際にはあまり目にすることがないのですが、ビリヤードの球とか氷の上のカーリングは摩擦が小さいので等速直線運動に近い状態です。 また、止まっている物体も速度0で等速直線運動をしていると考えられます。
つまりポイントは
周りから余計な力が働いていない
ということなのです。この条件を満たす物体は全て等速直線運動をしていると言っていいでしょう。 ちなみに自信は99%くらいなので、間違ってたら指摘しなさい。
で、等加速度運動の説明です。 等加速度運動という字を見て分かる通り
加速度がずっと等しいのです。
加速度って何か、速度に影響を与える力です。つまり何らかの力だと考えたらいいです。 そして、周りから加わる力が常に一定方向に同じ力だけ働いているのです。
例を考えてみましょう。 宇宙空間に漂うロケットを想像してください。 さっきまでエンジンを入れていたのですが、今は切っています。 するとどうなりますか? 先ほどまでの推進力の惰性で、ずっと同じスピードでスーッと動いているでしょう。
はい、これが等速直線運動。
何も力が加わってませんよね。 そして、ここでエンジンを入れました。 エンジンの出力パワーは同じまま、ゴーッとしばらくエンジンを点けたらどうなりますか? ロケットのスピードはもちろん速くなります。 どういう風に早くなるか、重い物体はスピードに乗るまでにしばらく時間がかかります。 だから初めはゆっくり、だんだん速く、グィイイイイーーーーンってスピードが上がっていくはずです。
はい、これが等加速度運動。
速度を上げるために常に同じ力で押しているので、速度はある一定のペースで増加、もしくは減少しつづけます。 プログラム的に言えば、ある一定時間ごとに速度自体を+1していると思えばいいでしょう。 そして速度は位置情報、つまり(x, y)に加算されるので、加算する値が毎回少しずつ変化するのです。 同じペースでね。
だから、等加速度運動
速度に影響を与えるものが加速度で、それが同じ大きさってこと。
重力
では、重力はどうやって表現するのか?
簡単です
等加速度運動です。 地球はその重力によって、常に地球上の物体を下に引っ張っています。 しかも、常に同じ力で(厳密には高度によって替わりますが、ほぼ一緒なので無視します)。
これって等加速度運動です。
つまり地球上にいるとき、僕たちは常に真下に向かってロケットエンジンを噴射し続けているのです。 だから、足で踏ん張って立たないといけないのですね。
能書きはいいからプログラム
なぜ・・・なぜこんなにも能書きが長くなったのか。 それは訳があります。 それは・・・
プログラムの修正があまりにも少なすぎるから!!!
はっきり言って、初めてこれを実装したときは衝撃でした。 皆さんも同じ衝撃を感じてくれたら嬉しい限りです。 では、前回のプログラムに修正を加えましょう。 コメントを除けば、わずか2行の修正です。
ではいきます。 最終的なコードは最後に載せます。
まず、最初の変数宣言のところに重力を表す加速度を宣言します。
//重力によるy方向の加速度
public var ay:Number = 1;
下に引っ張るので、y方向にプラスの影響を与えるので正の数となります。 1というのは、まあ適当ですね。
そしてonEnterFrame関数の最後に以下の記述を加えます。
//重力による速度の変化
vy += ay;
yの速度に一定数としてayを毎回加えているのですね。
たったこれだけdeath
では実行してください。 なんとなく重力が働いているみたいでしょう?
・・・。
でも少し不自然ですね。 その原因は跳ね返ったボールが毎回同じ高さまで跳ね返ってくるので、いつまでたってもボールが止まらないからです。 通常、壁などでボールが反射するときは摩擦で速度が一部失われます。
では、上記の現象をコードに落とし込んでみましょう。 壁に跳ね返る場所・・・例えばここですね。
//左方向にはみ出した
vx *= -1;
上下左右にはみ出した場合で合計4箇所あります。 ここで速度を反転しているのですが、-1をかけているのが問題のようです。 摩擦で力が失われることなく、反対側に同じ速度で飛んでいってしまいます。
方向としては反対側に飛ばしたいので、マイナスはマイナスなのですが、少し速度を小さくするために-0.9をかけるようにしてみましょう。
//左方向にはみ出した
vx *= -0.9;
ちゃんと4箇所書き換えてください。これでどうでしょう。
完成
ボールは見事に日常生活で見られる、あの動きをしているように見えます。 空気抵抗は考えていないため、横方向の移動はいつまでたっても終わらないのが、やや不自然です。 この実装はもうみなさんにお任せしてみましょう。
ちなみにayの値を1以外の色んな値に変化させてみると面白いです。 この世界での重力が変わるわけです。 月のような重力の少ない世界にしてみるのか、重力装置で100倍の重力を再現した部屋、みたいにしてみるのか。 全てはあなたの思うままです。
では、ここまでのコードを掲載して今回は終わります。
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class Animation1 extends Sprite
{
//ボール
public var ball:Sprite;
//ボールの半径
public var ballR:Number = 50;
//ボールの移動速度
public var v:Number = 20;
//ボールの横方向の移動量
public var vx:Number;
//ボールの縦方向の移動量
public var vy:Number;
//重力によるy方向の加速度
public var ay:Number = 1;
public function Animation1()
{
init();
}
public function init():void
{
//ボールの作成
ball = new Sprite();
ball.graphics.beginFill(0xff0000); //赤色で塗りつぶし開始
ball.graphics.drawCircle(0, 0, ballR); //座標(0, 0)に半径50の円
ball.graphics.endFill(); //塗りつぶし終了
//ボールの位置指定(画面の真ん中)
ball.x = stage.stageWidth / 2;
ball.y = stage.stageHeight / 2;
//ボールの移動角度設定
var radian:Number = Math.random() * 2 * Math.PI;
//角度の要素からx方向、y方向の移動量を取得
vx = Math.cos(radian) * v;
vy = Math.sin(radian) * v;
//ボールを画面に追加
addChild(ball);
//マウスクリックイベントを追加
stage.addEventListener(MouseEvent.CLICK, onMouseClick);
}
public function onMouseClick(event:MouseEvent):void
{
//フレーム毎のイベントの追加
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
public function onEnterFrame(event:Event):void
{
ball.x += vx;
ball.y += vy;
//画面領域からはみ出した場合は、移動量の正負反転
//横方向のはみ出しチェック
if(ball.x - ballR < 0){
//左方向にはみ出した
vx *= -0.9;
ball.x = ballR;
}else if(stage.stageWidth < ball.x + ballR){
//右方向にはみ出した
vx *= -0.9;
ball.x = stage.stageWidth - ballR;
}
//縦方向のはみ出しチェック
if(ball.y - ballR < 0){
//上方向にはみ出した
vy *= -0.9;
ball.y = ballR;
}else if(stage.stageHeight < ball.y + ballR){
//縦方向にはみ出した
vy *= -0.9;
ball.y = stage.stageHeight - ballR;
}
//重力による速度の変化
vy += ay;
}
}
}
次回はバネの働きでもやってみましょうかねぇ。
関連するエントリー Flex入門者がアニメーションを基礎から説明してみる #4
- Newer: Flex入門者がアニメーションを基礎から説明してみる #5
- Older: Flex入門者がアニメーションを基礎から説明してみる #3
トラックバック:No Trackbacks
- トラックバック URL
- http://blog.garden-place.jp/action.php?action=plugin&name=TrackBack&tb_id=183
- Listed below are links to weblogs that reference
- Flex入門者がアニメーションを基礎から説明してみる #4 from Web 酒 肴