- 2008-07-22 (Tue) 01:21
- ActionScript , Flash/Flex
放置と思いきや、連続の更新ですよ。ある意味ツンデレみたいなもんですわ。 今回のテーマは「物体移動の角度と反射」です。 前回は縦方向と横方向の移動量だけを定義したけど、今回はそれに角度と速度をからめて考えます。
縦方向と横方向の移動量を決定したら角度と速度が確定します。 また、角度と速度を決定したら縦方向と横方向の移動量が確定します。 相互に変換できるので、その時々で便利な方を使うようにしましょう。
おっと、その前にタイトルを少し変えました。ActionScript→Flexに変更です。 それに合わせて過去の記事も変更させてもらいました。Flex主体で説明しているからね。
Flexにおける角度
Flexでの角度の考え方は、一般的な数学での考え方と同じです。 すなわち右に水平な方向が0度。そこから上に向かって角度が上がっていき垂直になったところが90度。 左方向に水平になって180度。下が270度で元の位置まで戻って360度です。 めんどくさいので図は用意しませんでした。
そして、一般的な数学と同じように角度から辺の長さを求めるのにsin, cos関数を使用します。 逆を求めるときは一般にatan関数を使用します。 詳しい説明はしません。 sin(角度)で実行するとその角度にふさわしいx方向の移動量が得られます。同じくcos(角度)でy方向の移動量が得られます。 これらの結果を現在の座標に加算することで、指定した角度の方向に距離1分だけ移動することになります。
Flexの事情ですが、角度をパラメータとして扱う場合、一般的な角度として扱う場合と、ラジアンという単位で扱う場合の2通りあります。 気温で言うと摂氏と華氏の違いのようなものです。 同じ角度を表すのでも違う数値になります。
そしてこれは関数毎に違うので、実行する関数によって普通の角度やラジアンを使い分けなくてはいけません。 ラジアンと角度は以下の計算で相互に変化できるので、少しめんどくさいけど問題はありません。 (Math.PIは円周率)
角度→ラジアン
(ラジアン) = (角度) x Math.PI / 180
ラジアン→角度
(角度) = (ラジアン) x 180 / Math.PI
速度
指定した角度にどれくらいの移動量で移動するか、それが速度です。 sin, cos関数で得られた(x, y)にそれぞれ速度vをかけた値を(vx, vy)とすると、現在の座標に(vx, vy)を加算したとき、 物体の移動量はvとなります。 証明はしません。そうなるのだと思ってください。 どうしても知りたい方は高校の数学か物理の範囲で検索すれば出てくるかと思います。
反射
次は反射です。 今回は壁に反射するケースだけを考えるので非常に簡単です。 左右の壁を超えた時はx方向の速度の正負を反転してあげるだけ。同じく上下の壁を超えた時はy方向の速度の正負を反転。 なぜそうなるのかは、考えましょう。
サンプル
では実際のサンプルです。 今回も新しくプロジェクトを作成してもいいですが、前回のサンプルにちょっとした修正をいれるだけなので、前回との比較をしてみると面白いと思います。 以下のコードを入れてください。 クラス名は自分の環境に合わせてください。
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;
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 || stage.stageWidth < ball.x + ballR){
//横方向にはみ出した
vx *= -1;
}
//縦方向のはみ出しチェック
if(ball.y - ballR < 0 || stage.stageHeight < ball.y + ballR){
//縦方向にはみ出した
vy *= -1;
}
}
}
}
前回と変わった部分を中心に説明します。
//ボール
public var ball:Sprite;
//ボールの半径
public var ballR:Number = 50;
//ボールの移動速度
public var v:Number = 20;
//ボールの横方向の移動量
public var vx:Number;
//ボールの縦方向の移動量
public var vy:Number;
まず、ボールの半径を色んな場所で使用するので変数化しました。
次に、今回は全体的な速度を20としました。x方向、y方向のそれぞれの移動量は角度から算出します。 それをしているのが以下の部分です。
//ボールの移動角度設定
var radian:Number = Math.random() * 360;
radian = radian * 180 / Math.PI;
//角度の要素からx方向、y方向の移動量を取得
vx = Math.cos(radian) * v;
vy = Math.sin(radian) * v;
まず、ランダムにボールの移動角度を設定しています。 0度以上360度未満の角度を取得し、それをラジアンに変換しています。 分かりやすく書こうとしてこうなったのですが、以下のように書けば一行ですみます。
var radian:Number = Math.random() * 2 * Math.PI;
そしてsin, cos関数でx, yの移動量を算出し、速度vをかけています。 上の方で説明した通りです。
最後に画面領域からはみ出た時の処理です。 ボールの座標はボールの中心点なので、ボールの半径を加減算することでボールの端が画面の外にでているかを判定しています。 半径は50なので、50を加減算してもいいのですが、今後ボールの半径を変更したとしてもここを変更しないで済むようにこうしておきます。
はみ出たときは、上で説明した通り、xかyの進行方向の正負のフラグを反転してやるだけです。 縦方向と横方向同時にはみ出すことを考慮して、条件式はそれぞれ書いてやる必要があります。
//画面領域からはみ出した場合は、移動量の正負反転
//横方向のはみ出しチェック
if(ball.x - ballR < 0 || stage.stageWidth < ball.x + ballR){
//横方向にはみ出した
vx *= -1;
}
//縦方向のはみ出しチェック
if(ball.y - ballR < 0 || stage.stageHeight < ball.y + ballR){
//縦方向にはみ出した
vy *= -1;
}
完成
できました。 画面をクリックしたら動きます。 なお、細かい調整部分は省略しているので、たまにボールが画面の外に出て動きがおかしくなる可能性があります。 今回は説明を簡略化するために、あえてこのままにします。 あと、なぜか家のFirefoxに限って境界の位置が微妙にずれる・・・。
これでビリヤードとかエアホッケーっぽくなりました。 延々動き続けるのは、摩擦を考慮に入れていないからです。 最後に摩擦を考慮するコードを入れてみましょう。
onEnterFrame関数の最初に以下の2文を入れます。
vx *= 0.98;
vy *= 0.98;
つまり速度が徐々に目減りして0に近づくようにしているのですね。 どうですか?徐々に遅くなって止まったでしょ?
今回はここまでです。
次回は・・・どうしようかなぁ・・・?
もう一つの主役、重力の話でもしましょう。
これは多分、週末になる予感。
関連するエントリー Flex入門者がアニメーションを基礎から説明してみる #3
トラックバック:No Trackbacks
- トラックバック URL
- http://blog.garden-place.jp/action.php?action=plugin&name=TrackBack&tb_id=180
- Listed below are links to weblogs that reference
- Flex入門者がアニメーションを基礎から説明してみる #3 from Web 酒 肴