- 2008-08-03 (Sun) 00:41
- ActionScript , Flash/Flex
さて、今回はバネの運動を紹介しようと思いましたが、やめました。 その事前準備の説明で今回の記事は十分な長さになりそうだからです。
今回紹介するのは今までの復習のようなものです。 基本となるのははボールの落下、反射です。そこに少しだけ機能を加えてボールのドラッグと、ボールを放り投げる処理を入れて今回は終わります。 そこに次回、鮮やかな修正を加えてバネの動きを実現します。
復習 「ボールの落下、反射」
ではまず、新しいActionScriptプロジェクトを作成しましょう。 いつも通り、Flex Builder 3を前提として話していますので、他の環境の方は読み替えてください。 単にActionScriptのクラスファイルを1つ作成するだけです。 プロジェクト名、クラス名は何でもいいです。僕はAnimation2というプロジェクトを作成しました。
そこに以下のように入力しましょう。
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 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;
//ボールを画面に追加
addChild(ball);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void{
//速度に従ってボールの移動
ball.x += vx;
ball.y += vy;
//画面のはみ出しチェック
checkWall();
//重力による加速
vy += ay;
}
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;
}
}
}
}
最初から読み進めてきた方なら、なんなく理解できるでしょう。 今までと少し違うのはボールが枠からはみ出したかどうかのチェックをcheckWallという一つの関数に切り出したくらいです。 あと、重力の加速度を2に設定して、少し前よりも重力を強くしています。
落下はonEnterFrameの最後のvy += ay;がポイントでした。反射はcheckWall関数で枠からはみ出していたときに、速度に-0.9をかけて、反転しつつ少し絶対値を小さくしています。
ドラッグドロップ処理追加
ボールをドラッグできるように、init関数の中に以下の処理を追加しましょう。
//ボールをマウスでドラッグできるようにする
ball.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
ball.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
マウスのボタンをクリックしたときにonMouseDown関数、ボタンを離したときにonMouseUp関数が実行されるようにしました。 それぞれの関数は以下のように実装します。
private function onMouseDown(event:MouseEvent):void{
//ボールの運動を停止させる
vx = 0;
vy = 0;
//ドラッグ中はボールの移動処理をしない
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
ball.startDrag();
}
private function onMouseUp(event:MouseEvent):void {
//ボールの移動処理を再開
addEventListener(Event.ENTER_FRAME, onEnterFrame);
ball.stopDrag();
}
onMouseDown関数でドラッグ開始の処理を実装します。 まず、いったんボールのドラッグを始めるとボールの速度は0に設定しています。 ボタンを離してボールを解放したときに、今までのボールの速度を保持せず、またそこから新たに落下処理を始めるためです。
また、フレーム毎の移動処理も停止させるため、以下の一行でイベント処理を削除します。 これによりonEnterFrame関数は実行されなくなります。
//ドラッグ中はボールの移動処理をしない
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
最後に、ドラッグ開始します。
ball.startDrag();
この一行だけでボールのドラッグ移動が可能になるなんて便利すぎです。
そしてonMouseUp関数でドラッグ終了。 終了時にはフレーム毎の移動処理が再開されるようにonEnterFrame関数を再登録します。
//ボールの移動処理を再開
addEventListener(Event.ENTER_FRAME, onEnterFrame);
そしてドラッグ終了もこの一行。便利便利万歳。(←わかる人は友達)
ball.stopDrag();
これでボールをドラッグして移動させることができるようになりました。
放り投げちゃえ!
次はボールを放り投げる処理を追加します。 ドラッグで移動した後に、マウスのボタンを離しながらポーンと好きな方向に投げれるようにしましょう。 投げる勢いも実際のマウスの動きから取得するようにしましょう。
どういう考え方でこれを実装すればいいか解説します。 実際のボタンを離した瞬間のマウスの動きを取ることはできません。 ですので、ボタンを離す直前の動きを使用します。 ということはドラッグ中のマウスの移動方向、速度を取得する必要があるということですね。
実はこれは全然難しくありません。 ドラッグ中は常にマウスの位置だけを記録していればいいのです。 そしてマウスのボタンを離した瞬間のonMouseUp関数の中でもマウスの位置を取得できます。 この2点を比較すれば、直前のマウスの移動方向と距離、すなわち速度が取得できます。 スピードをつけて投げれば投げるほど、この2点間の距離は離れているはずですから。
では、ドラッグ中に常にマウスの位置を記録しておくために、フィールド変数を追加しましょう。
//ドラッグ中のマウスのX,Y座標
public var tempX:Number;
public var tempY:Number;
そしてドラッグ中は常にこの変数に座標を上書き保存し続ける関数を追加します。
private function onDragEnterFrame(event:Event):void{
tempX = mouseX;
tempY = mouseY;
}
ドラッグ中は常にこの関数が実行されるようにonMouseDown関数を以下のように変更します。 ドラッグが終了するとこの関数が実行されないようにonMouseUp関数内で除去します。
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);
ball.stopDrag();
}
マウスのボタンを離したときに、直前のマウスの座標と現在のマウスの座標から、ボールを放り投げるべき速度と方向を取得しなくてはなりません。 これは2点間の位置関係を算出するだけで簡単に実装できます。
onMouseUp関数に以下の記述を加えましょう。 X方向にマウスが動いた距離がそのままボールのX方向の速度に、Y方向にマウスが動いた距離がそのままボールのY方向の速度になります。
//ボールを放り投げるX速度とY速度を設定
vx = mouseX - tempX;
vy = mouseY - tempY;
完成!!
さあ、マウスのドラッグでボールを掴んで放り投げてみましょう。
うまくいきましたか? ではここまでのソースコードを載せて今回は終了します。 次回は、ここにバネの動きを追加します。
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;
//ドラッグ中のマウスの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;
}
private function onEnterFrame(event:Event):void{
//速度に従ってボールの移動
ball.x += vx;
ball.y += vy;
//画面のはみ出しチェック
checkWall();
//重力による加速
vy += ay;
}
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;
}
}
}
}
関連するエントリー Flex入門者がアニメーションを基礎から説明してみる #5
- Newer: Flex入門者がアニメーションを基礎から説明してみる #6
- Older: Flex入門者がアニメーションを基礎から説明してみる #4
トラックバック:No Trackbacks
- トラックバック URL
- http://blog.garden-place.jp/action.php?action=plugin&name=TrackBack&tb_id=184
- Listed below are links to weblogs that reference
- Flex入門者がアニメーションを基礎から説明してみる #5 from Web 酒 肴