- 2008-08-05 (Tue) 01:00
- ActionScript , Flash/Flex
今回はバネです。ていうかFlexBuilderの試用期間があと10日に迫ってまいりました。あと10日で連載終了などできるわけもなく・・・・・・買うしかないか・・・。それともフリーのFlashDeveloper使うかな?いや、ここは大人しく購入しておくのがいいだろう。
だって買ったら頑張って使わなきゃ元取れないし!
だから頑張れるし!!
摩擦で速度を抹殺せよ!!
夜は恥ずかしいダジャレがためらうことなく口から出てきます。
まあそれはいいとして、前回作成したコードに修正を加えます。 あのままだと、ボールは最終的に転がりつづけたままなかなか止まりません。 壁に反射したときに速度は少し減少しているので、そのうち止まりますが、現実世界には摩擦というものがあります。 摩擦とは、いついかなるときも、速度を0に近づけているものです。
ということでonEnterFrame関数の中で、常に速度に摩擦を適用すればよさそうです。 ここで大事なのは「速度を0に近づける」ということ。 重力のように一定値を引くのではありません。
例えば速度3→1になるのは速度が2減少しています。 では速度が1のときは?同じように2減少させると-1になってしまいます。 これでは反対側に飛んでいくだけなので、摩擦で物体が停止しようとしているときの動作ではありません。
正解は1以下の数値をかけるのです。これで速度は一定して弱まり続けて最終的に0に限りなく近づきます。 フィールド変数として摩擦を表す定数を宣言しましょう。
//摩擦による速度の低下
public var friction:Number = 0.98;
次に、この定数をonEnterFrame関数の最後でX, Y方向の速度にそれぞれ乗じます。
//摩擦の考慮
vx *= friction;
vy *= friction;
これでどうなりますか? 今までよりずっと本物らしくなったでしょう。 摩擦をよりリアルに再現しようとすると、もっと複雑な計算が必要なのですが、手軽さと結果のバランスを考えるとこれくらいが最適な方法だと考えられます。
いよいよバネ!
いや~長かった。 それではバネの動きを実装しましょう。
まず、バネの端っこはもちろんこのボールに繋げるわけですが、もう片方の端も固定しなければなりません。 そこでバネのもう一つの端を画面の真ん中に設定します。 フィールド変数で以下のように宣言しましょう。
//バネの中心点
public var springX:Number = stage.stageWidth / 2;
public var springY:Number = stage.stageHeight / 2;
次に、ボールの真ん中と、バネの中心点が繋がっているように線を描写する関数を作っておきます。
private function drawSpring():void{
//画面の中心に円の描画
graphics.clear();
graphics.beginFill(0);
graphics.drawCircle(springX, springY, 5);
graphics.endFill();
//ボールと画面の中心を線でつなぐ
graphics.lineStyle(2, 0);
graphics.moveTo(ball.x, ball.y);
graphics.lineTo(springX, springY);
}
そしてバネの力をボールの運動に反映させます。 この場合はどのように考えたらいいのでしょうか。
まず、バネは常にボールをある力で引っ張ります。常に引っ張るということはボールの速度に常に影響を与え続けるということです。 ということは重力と同じようにonEnterFrame関数内で、速度に対して何らかの処理をすればいいということですね。 速度に何をしたらいいのでしょうか。ポイントは以下の2つです。
- バネの中心点に向かった力を加える
- バネの中心点から離れれば離れるほど、与える力は強くなる
これらを考慮したコードは以下のようになります。
//バネによる速度の変化
vx += (springX - ball.x) * 0.07;
vy += (springY - ball.y) * 0.07;
(springX, springY)というバネの中心点の座標から、ボールの中心点の座標を引いています。 そしてそれに一定数を掛け合わせ、速度に加えています。
バネの中心点の座標と、ボールの中心点の座標の差が負の値になってもこのコードはうまく動作します。 その理由は皆さん考えてください。 上記のコードを、先ほどの摩擦の計算の前に入れましょう。このバネの力にも摩擦は考慮されるべきだからです。
そして、onEnterFrame関数の一番最後でバネの描写の関数であるdrawSpringを呼び出します。
//バネの描画
drawSpring();
ボールのドラッグ中にもバネは描画して欲しいので、onDragEnterFrame関数の最後にも入れておきましょう。
完成!!
さぁ、これでリアルな動きをするようになりました。 ボールをドラッグしてバネを伸ばし、ボタンを離してみてください。もしくは思いっきり投げつけてみましょう。
最後にここまでで出来たソースコードを掲載します。 次回のネタは今考えているところです。お楽しみに!
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class Animation2 extends Sprite{
//ボール
public var ball:Sprite;
//ボールの半径
public var ballR:Number = 50;
//ボールの横方向の移動量
public var vx:Number = 0;
//ボールの縦方向の移動量
public var vy:Number = 0;
//重力によるy方向の加速度
public var ay:Number = 2;
//バネの中心点
public var springX:Number = stage.stageWidth / 2;
public var springY:Number = stage.stageHeight / 2;
//摩擦による速度の低下
public var friction:Number = 0.98;
//ドラッグ中のマウスのX,Y座標
public var tempX:Number;
public var tempY:Number;
public function Animation2(){
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;
//ボールをマウスでドラッグできるようにする
ball.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
ball.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
//ボールを画面に追加
addChild(ball);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onMouseDown(event:MouseEvent):void{
//ボールの運動を停止させる
vx = 0;
vy = 0;
//ドラッグ中はボールの移動処理をしない
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
//ドラッグ中にマウスの座標を保存する処理を登録
addEventListener(Event.ENTER_FRAME, onDragEnterFrame);
ball.startDrag();
}
private function onMouseUp(event:MouseEvent):void {
//ボールの移動処理を再開
addEventListener(Event.ENTER_FRAME, onEnterFrame);
//マウスの座標を保存する処理を除去
removeEventListener(Event.ENTER_FRAME, onDragEnterFrame);
//ボールを放り投げるX速度とY速度を設定
vx = mouseX - tempX;
vy = mouseY - tempY;
ball.stopDrag();
}
private function onDragEnterFrame(event:Event):void{
tempX = mouseX;
tempY = mouseY;
//バネの描画
drawSpring();
}
private function onEnterFrame(event:Event):void{
//速度に従ってボールの移動
ball.x += vx;
ball.y += vy;
//画面のはみ出しチェック
checkWall();
//重力による加速
vy += ay;
//バネによる速度の変化
vx += (springX - ball.x) * 0.07;
vy += (springY - ball.y) * 0.07;
//摩擦の考慮
vx *= friction;
vy *= friction;
//バネの描画
drawSpring();
}
private function checkWall():void {
//横向きのチェック
if(ball.x < ballR){
ball.x = ballR;
vx *= -0.9;
}else if(stage.stageWidth - ballR < ball.x){
ball.x = stage.stageWidth - ballR;
vx *= -0.9;
}
//縦向きのチェック
if(ball.y < ballR){
ball.y = ballR;
vy *= -0.9;
}else if(stage.stageHeight - ballR < ball.y){
ball.y = stage.stageHeight - ballR;
vy *= -0.9;
}
}
private function drawSpring():void{
//画面の中心に円の描画
graphics.clear();
graphics.beginFill(0);
graphics.drawCircle(springX, springY, 5);
graphics.endFill();
//ボールと画面の中心を線でつなぐ
graphics.lineStyle(2, 0);
graphics.moveTo(ball.x, ball.y);
graphics.lineTo(springX, springY);
}
}
}
関連するエントリー Flex入門者がアニメーションを基礎から説明してみる #6
トラックバック:No Trackbacks
- トラックバック URL
- http://blog.garden-place.jp/action.php?action=plugin&name=TrackBack&tb_id=186
- Listed below are links to weblogs that reference
- Flex入門者がアニメーションを基礎から説明してみる #6 from Web 酒 肴