<?xml version="1.0" encoding="UTF-8"?>

<feed xml:lang="ja" xmlns="http://www.w3.org/2005/Atom">
    <title>Web　酒　肴</title>
    <subtitle>Flex, ActionScript, CMS, Ruby on Rails, Java, NetBeansなどの技術情報その他</subtitle>
    <id>http://blog.garden-place.jp/oborobeer/:2</id>

    <link rel="alternate" type="text/html" href="http://blog.garden-place.jp/oborobeer/" />
    <link rel="self" type="application/atom+xml" href="http://blog.garden-place.jp/oborobeer/" />
    <generator uri="http://nucleuscms.org/">Nucleus CMS v3.31SP1</generator>
    <updated>2009-05-13T09:57:56Z</updated>

    <entry>
 <title type="html"><![CDATA[[ActionScript]２直線の交点を求める]]></title>
 <link rel="alternate" type="text/html" href="http://blog.garden-place.jp/oborobeer/item_261.html" />
 <author>
  <name>obanetty</name>
 </author>
 <updated>2009-05-13T09:57:56Z</updated>
 <published>2009-05-13T18:57:56+09:00</published>
 <content type="html"><![CDATA[<p>先日作ったライブラリを利用すると以下のようなことができます。</p>

<p>画面内でマウスをクリック＆ドラッグしてください。
線分同士の交点を表示します。</p>

<div style="text-align:center;width:465px;"><iframe title="直線や線分の交点を計算する - wonderfl build flash online" src="http://wonderfl.kayac.com/blogparts/f9751de2db14811654827f951714c5a2d6926b67" width="465" height="490" style="border:1px black solid;"></iframe><a href="http://wonderfl.kayac.com/code/f9751de2db14811654827f951714c5a2d6926b67" title="直線や線分の交点を計算する - wonderfl build flash online">直線や線分の交点を計算する - wonderfl build flash online</a></div>

<p>そんなに大したことはしてませんが、あえてLineクラスの特徴をあげるとするならば線分、半直線、直線に対応していることか。
多くの場合は線分同士の交点を求めればいいのであまり使わないけど。</p>

<p>Lineクラスは以下のように使用します。</p>

<pre><code>//Lineインスタンスを２つ作成
var line1:Line = new Line(new Point(x1, y1), new Point(x2, y2), Line.TYPE_SEGMENT); //Line.TYPE_SEGMENTは線分
var line2:Line = new Line(new Point(x3, y3), new Point(x4, y4), Line.TYPE_HALF); //Line.TYPE_HALFは半直線

//交点の座標を取得
var p:Point = line1.getIntersectionPoint(line2);
</code></pre>

<p>交点がない場合は <em>null</em> が返ります。</p>

<p>Lineクラス内では交点を求める以外にもいくつかのチェックなどしていますが、実際に交点を求めるところのアルゴリズムだけを抜き出すと以下のようになります。</p>

<pre><code>// a1,a2を通る直線とb1,b2を通る直線をあらわすベクトル作成（a1, a2, b1, b2は全てPointオブジェクト）
Point a = a2 - a1;
Point b = b2 - b1;

//crossは２つのベクトルの外積を計算するメソッド
return a1 + a * cross(b, b1-a1) / cross(b, a);
</code></pre>

<p>参考にしたのはここ。
<a href="http://www.deqnotes.net/acmicpc/2d_geometry/lines" title="平面幾何におけるベクトル演算 » 直線と線分">平面幾何におけるベクトル演算 » 直線と線分</a></p>

<p>Lineクラスのソースコードは以下。</p>

<p><em>Line.as</em></p>

<pre><code>package
{
    import flash.geom.Point;

    public class Line
    {
        /* ２点を通る直線（終端はない） */
        public static const TYPE_STRAIGHT:String = "straight";
        /* p1からp2の方向に延びる半直線 */
        public static const TYPE_HALF:String = "half";
        /* p1, p2間の線分 */
        public static const TYPE_SEGMENT:String = "segment";

        public var p1:Point;
        public var p2:Point;
        public var type:String;

        public function Line(p1:Point, p2:Point, type:String=TYPE_STRAIGHT)
        {
            this.p1 = p1;
            this.p2 = p2;
            this.type = type;
        }

        /**
         * 2つのLineインスタンスの交点を表わすPointインスタンスを取得する
         * 交点がない場合はnullを返す
         * @param line
         * @return 
         * 
         */
        public function getIntersectionPoint(line:Line):Point{
            var vector1:Point = this.getVector();
            var vector2:Point = line.getVector();

            if(cross(vector1, vector2) == 0.0){
                //2直線が並行の場合はnullを返す
                return null;
            }

            // 交点を this.p1 + s * vector1 としたとき
            var s:Number = cross(vector2, line.p1.subtract(this.p1)) / cross(vector2, vector1);
            // 交点を line.p1 + t * vector2 としたとき
            var t:Number = cross(vector1, this.p1.subtract(line.p1)) / cross(vector1, vector2);

            if(this.validateIntersect(s) &amp;&amp; line.validateIntersect(t)){
                vector1.x *= s;
                vector1.y *= s;
                return this.p1.add(vector1);
            }else{
                return null;
            }
        }

        public function getVector():Point{
            return p2.subtract(p1);
        }

        /**
         * 交点までのベクトルを p1 + n * (p2 - p1) であらわしたとき、
         * nが適切な値の範囲内かどうかを判定する。
         * 
         * 直線の場合：nはどの値でもよい
         * 半直線の場合：nは0以上である必要がある
         * 線分の場合：nは0以上1以下である必要がある
         * @param n
         * @return 
         * 
         */
        private function validateIntersect(n:Number):Boolean{
            if(this.type === TYPE_HALF){
                return (0 &lt;= n);
            }else if(this.type === TYPE_SEGMENT){
                return ((0 &lt;= n) &amp;&amp; (n &lt;= 1));
            }else{
                return true;
            }
        }

        /**
         * 2つの2次元ベクトルの外積を返す
         * @param vector1 2次ベクトルを表わすPointインスタンス
         * @param vector2 2次ベクトルを表わすPointインスタンス
         * @return 
         * 
         */
        private function cross(vector1:Point, vector2:Point):Number{
            return (vector1.x * vector2.y - vector1.y * vector2.x);
        }

        public function toString():String{
            var str:String = "";
            if(type === TYPE_STRAIGHT){
                str += "---&gt; ";
            }
            str += "(" + p1.x + ", " + p1.y + ") ---&gt; (" + p2.x + ", " + p2.y + ")";
            if(type === TYPE_STRAIGHT || type === TYPE_HALF){
                str += " ---&gt;";
            }

            return str;
        }
    }
}
</code></pre>
]]></content>
 <id>http://blog.garden-place.jp/oborobeer/:2:261</id>
</entry><entry>
 <title type="html"><![CDATA[[Flex]カスタムエフェクトの作成 #7 - 2直線の交点を求める]]></title>
 <link rel="alternate" type="text/html" href="http://blog.garden-place.jp/oborobeer/item_258.html" />
 <author>
  <name>obanetty</name>
 </author>
 <updated>2009-05-10T12:10:36Z</updated>
 <published>2009-05-10T21:10:36+09:00</published>
 <content type="html"><![CDATA[<p>久しぶりにこれに取り掛かれる。
5/30の<a href="http://www.fxug.net/modules/bwiki/index.php?Flex3%CA%D9%B6%AF%B2%F1%C2%E870%B2%F3%A1%F7%B5%FE%C5%D4%BB%B2%B2%C3%BC%F5%C9%D5" title="B-Wiki - Flex3勉強会第70回＠京都参加受付 - Flex User Group">Flex3勉強会第70回＠京都</a>までに完成させなくてはいけないので、のんびりしてられないわけだけど、ここにきてまたバンド組んだり知り合いのＨＰ頼まれたり、会社で大がかりな組織変更があってその対応とか、しばらく大変そう・・・。</p>

<p>このエフェクトをきれいにライブラリ化するために、どうしても２つの線分の交点を求める処理が必要になってくる。
どうせならこれも汎用的に使えるようにしようと思って、以下のようなLineクラスを作ることにした。</p>

<p><em>Line</em>クラス概要</p>

<ul>
<li><em>Line</em>クラスのインスタンスは一つの直線・半直線・線分を表わす</li>
<li>（半）直線または線分上にある２つの座標<em>(x1, y1)</em> と <em>(x2, y2)</em>によって初期化される</li>
<li>初期化時のパラメータにより、直線・半直線・線分のいずれかを指定することができる</li>
<li>別のLineクラスのインスタンスを引数に取り、お互いが交差している座標を返す<em>getIntersectionPoint</em>メソッドを持つ</li>
</ul>

<p>これを作成するにあたり、線分の交点を計算するアルゴリズムをいろいろ調べた結果、今回はここを参考にするのが一番目的にあっていそう。</p>

<p><a href="http://www.deqnotes.net/acmicpc/2d_geometry/lines" title="平面幾何におけるベクトル演算 » 直線と線分">平面幾何におけるベクトル演算 » 直線と線分</a></p>

<p>あと、今更ながら知って驚いたこと。</p>

<p><strong>ActionScript3ではコンストラクタを複数定義できないっぽい</strong></p>

<p>ちょっと残念。</p>
]]></content>
 <id>http://blog.garden-place.jp/oborobeer/:2:258</id>
</entry><entry>
 <title type="html"><![CDATA[[ActionScript][アニメーション]Flex勉強会@京都開催しました]]></title>
 <link rel="alternate" type="text/html" href="http://blog.garden-place.jp/oborobeer/item_231.html" />
 <author>
  <name>obanetty</name>
 </author>
 <updated>2009-02-15T03:04:38Z</updated>
 <published>2009-02-15T12:04:38+09:00</published>
 <content type="html"><![CDATA[<p>先日（2/7）、京都でFlex勉強会を開催しました。２０人以上の方が参加してくださり、おかげさまでその後の懇親会も含めて大変盛況でした。
会場を提供してくれた上、様々なご協力をいただいたソフトディバイスさん、本当にありがとうございました。</p>

<p>僕もActionScriptでのアニメーション入門を少し発表したので、その時の資料に少し手を加えたものを掲載しておきます。
<a href="http://wonderfl.kayac.com/" title="wonderfl build flash online">wonderfl</a>というサービスを使い、ソースコードとサンプルを画面上で見れるようにできました。
便利ですね。</p>

<iframe src="http://show.zoho.com/embed?USER=obanetty_gmail&DOC=Flex%E3%81%AB%E3%82%88%E3%82%8B%E3%82%A2%E3%83%8B%E3%83%A1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%2F%E3%82%AD%E3%83%8D%E3%83%9E%E3%83%86%E3%82%A3%E3%82%AF%E3%82%B9%E5%85%A5%E9%96%80&IFRAME=yes&hide_menu=false&loop=true&showrel=true" height="378" width="460" name="ActionScriptによるアニメーション 入門編" scrolling="no" frameBorder="0" style="border:1px solid #aabbcc"></iframe>
]]></content>
 <id>http://blog.garden-place.jp/oborobeer/:2:231</id>
</entry><entry>
 <title type="html"><![CDATA[Flex入門者がアニメーションを基礎から説明してみる #7（最終回）]]></title>
 <link rel="alternate" type="text/html" href="http://blog.garden-place.jp/oborobeer/item_187.html" />
 <author>
  <name>obanetty</name>
 </author>
 <updated>2008-08-10T14:04:55Z</updated>
 <published>2008-08-10T23:04:55+09:00</published>
 <content type="html"><![CDATA[<p>突然ですがこの「Flex入門者がアニメーションを基礎から説明してみる」の連載は今回で終了とします。
なぜかというと学習している書籍の内容的に１、２回のエントリーで書ききれるものが尽きてしまったからです。
本当はここから以下のようなものに話は及びます。</p>

<ul>
<li><p>キネマティクス</p>

<p>人体の腕や足のように、関節を持った部品どうしが関連を持って運動する</p></li>
<li><p>3Dの基本</p>

<p>奥行きのある空間を平面上に表します。RPGゲームの3Dダンジョンのようなことができます。</p></li>
<li><p>3Dの応用</p>

<p>物体を立体的に表現し、そこに照明を当てて影などをつけます。
まだ読んでないので正確には理解してませんが。</p></li>
</ul>

<p>これらのことをブログに書こうと思ったら、一つの話題を理解しやすく書くのに５回程度のエントリーを必要としそうです。
そしてそれは書籍をそのまま転載することとあまり差がなくなってしまいそうな気がするので、僕の望むところではありません。</p>

<h2>まとめとして</h2>

<p>最終回は新しいことを解説しません。
今まで解説してきたことの中でメインとなっていた、物体を現実と同じように運動させる方法についてのまとめを書きます。</p>

<p>僕がボールを使用して解説した運動は以下のものです。</p>

<ol>
<li><p>等速直線運動</p>

<p>一番基本的な運動です。力を加えたらそっちの方に飛んで行く、もしくは転がっていく。</p></li>
<li><p>反射</p>

<p>主に壁に跳ね返ったときに使用しました。
反射する障害物に角度があるとき、すなわち外壁ではなく斜めになっている壁などに反射させるには少し高度な応用が必要です。僕は解説していませんが、書籍には１章割いて解説があります。</p></li>
<li><p>落下運動</p>

<p>これは等加速度運動の一例でした。宇宙空間のロケットの噴射にも応用できます。</p></li>
<li><p>摩擦</p>

<p>ボールが転がり続けたり、跳ね返り続けないための処置です。
現実世界は常に摩擦があるので、これを行わないと自然な動きになりません。</p></li>
<li><p>バネ</p>

<p>これは重力の応用です。
重力は常に同じ力が下に加わっていますが、バネはバネの始点に向かって、離れているほど強い加速度が加わります。</p></li>
</ol>

<h2>一つずつ解説</h2>

<p>さて、あなたがここでの例のようにボールなどをリアルに運動させようとしたとき、まず行うべきは「等速直線運動」の処理を実装することです。
具体的に言うと、以下の２つを用意するのです。</p>

<h3>等速直線運動の実装</h3>

<ol>
<li><p>X方向の速度とY方向の速度をフィールドで宣言する</p>

<p>このようにします。
最初は固定で適当な値を入れてもいいでしょう。</p>

<pre><code>private var vx:Number; //X方向の速度
private var vy:Number; //Y方向の速度
</code></pre></li>
<li><p>単位時間ごとに速度を位置に加算する</p>

<p>Flexの場合はENTER_FRAMEイベントにリスナ関数をセットして、フレーム毎に実行される関数内で速度を物体の位置に加算します。
ballというオブジェクトが表示されているのであれば以下のようにします。</p>

<pre><code>private function onEnterFrame(event:Event):void{
    ball.x += vx;
    ball.y += vy;
}
</code></pre></li>
</ol>

<p>これだけでボールは同じ方向に向かって進み続けるでしょう。
これ自体はとっても簡単ですが、このとっても簡単なことはいつも変わらないし、あとの仕事はさらにシンプルなのです。</p>

<h3>壁の反射、重力、バネ、摩擦などの実装</h3>

<p>色々なサンプルを掲載してきましたが、やっていることにはある共通点があります。
それは<strong>いじるのは速度だけ</strong>ということです。
壁の外にはみ出たときなど、特殊な例でない限り、物体のX座標やY座標はいじりません。
常に速度を適切な場所で少し変更するだけで、これらは実現できるのです。
一つずつ解説していきましょう。</p>

<ul>
<li><p>壁の反射</p>

<p>物体が移動することにより、壁との衝突を検知した時点で速度を反転させるだけです。
つまり、横の壁に衝突したら<em><code>vx *= -1;</code></em>します。縦の壁に衝突したら<em><code>vy *= -1;</code></em>です。
たったこれだけ。</p></li>
<li><p>重力</p>

<p>単位時間ごとつまりENTER_FRAMEのリスナ関数内で速度に重力の影響を加算します。
上のonEnterFrame関数に以下の一行を加えるような感じです。</p>

<pre><code>private function onEnterFrame(event:Event):void{
    ball.x += vx;
    ball.y += vy;

    vy += gravity; //gravityは重力の作用を表す数値（0.1などを代入しておく）
}
</code></pre></li>
<li><p>摩擦</p>

<p>摩擦とは常に速度を0に近づけるので、速度に一定の値を単位時間ごとにかけるだけです。
上のサンプルだと以下の２行を加えます。</p>

<pre><code>private function onEnterFrame(event:Event):void{
    ball.x += vx;
    ball.y += vy;

    vy += gravity; //gravityは重力の作用を表す数値（0.1などを代入しておく）

    vx *= friction; //frictionは摩擦を表す数値（0.95などを代入しておく）
    vy *= firction;
}
</code></pre></li>
</ul>

<p>バネの解説は前回やったため割愛します。
どうでしょうか？とてもシンプルではないですか？
実際に完成させるにはもう少し色々な処理を考える必要がありますが、基本的にはこれでいけます。</p>

<p>そしてこれらは、必要なものだけを取捨選択して書き加えればよいのです。
例えばビリヤード台を上から見た図なら、等速直線運動と反射、摩擦を実装する。しかし重力はいらないから実装しない、とか。
バネと重力はいるけど、摩擦は実装せずにずっとビヨンビヨン動かしておこう、とか。
自分の作りたい世界に合わせて、必要なものだけを書き加えるという実にシンプルな作り方ができるのです。</p>

<p>さらに、ここで解説していない処理を加えるとしても、多くの場合は既存のコードに修正はほとんどいりません。
その処理に必要な操作を、「速度」に対して行うだけでいいのです。そういえばボールをドラッグで掴んで投げた処理もそうでした。
とっても複雑な処理も、実は一つずつの処理を順番に実行している場合がほとんどなのです。</p>

<p>どうですか？簡単でしょう？
多くの人がアニメーションの簡単さ、楽しさに気付いてくれることを期待しています。
もちろん、もっともっと複雑なことがやりたい人は、簡単なことばかりでは済まないないでしょう。
その場合でも、この本さえあれば、きっと糸口は見つかります。</p>

<iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=obanetty-22&o=9&p=8&l=as1&asins=4862460496&fc1=000000&IS2=1&lt1=_blank&lc1=5C5C5C&bc1=000000&bg1=FFFFFF&f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>

<p>また宣伝かよ、とか思ったそこのあなた。だから初めからそうだと言ってるじゃないですか。</p>

<p>では皆さん、楽しいアニメーション作成を。</p>
]]></content>
 <id>http://blog.garden-place.jp/oborobeer/:2:187</id>
</entry><entry>
 <title type="html"><![CDATA[Flex入門者がアニメーションを基礎から説明してみる #6]]></title>
 <link rel="alternate" type="text/html" href="http://blog.garden-place.jp/oborobeer/item_186.html" />
 <author>
  <name>obanetty</name>
 </author>
 <updated>2008-08-04T16:00:08Z</updated>
 <published>2008-08-05T01:00:08+09:00</published>
 <content type="html"><![CDATA[<p>今回はバネです。ていうかFlexBuilderの試用期間があと10日に迫ってまいりました。あと10日で連載終了などできるわけもなく・・・・・・買うしかないか・・・。それともフリーのFlashDeveloper使うかな？いや、ここは大人しく購入しておくのがいいだろう。</p>

<p>だって買ったら頑張って使わなきゃ元取れないし！</p>

<p><b>だから頑張れるし！！</b></p>

<h2>摩擦で速度を抹殺せよ！！</h2>

<p>夜は恥ずかしいダジャレがためらうことなく口から出てきます。</p>

<p>まあそれはいいとして、前回作成したコードに修正を加えます。
あのままだと、ボールは最終的に転がりつづけたままなかなか止まりません。
壁に反射したときに速度は少し減少しているので、そのうち止まりますが、現実世界には摩擦というものがあります。
摩擦とは、いついかなるときも、速度を0に近づけているものです。</p>

<p>ということで<em>onEnterFrame</em>関数の中で、常に速度に摩擦を適用すればよさそうです。
ここで大事なのは「速度を0に近づける」ということ。
重力のように一定値を引くのではありません。</p>

<p>例えば速度3→1になるのは速度が2減少しています。
では速度が1のときは？同じように2減少させると-1になってしまいます。
これでは反対側に飛んでいくだけなので、摩擦で物体が停止しようとしているときの動作ではありません。</p>

<p>正解は1以下の数値をかけるのです。これで速度は一定して弱まり続けて最終的に0に限りなく近づきます。
フィールド変数として摩擦を表す定数を宣言しましょう。</p>

<pre><code>//摩擦による速度の低下
public var friction:Number = 0.98;
</code></pre>

<p>次に、この定数を<em>onEnterFrame</em>関数の最後でX, Y方向の速度にそれぞれ乗じます。</p>

<pre><code>//摩擦の考慮
vx *= friction;
vy *= friction;
</code></pre>

<p>これでどうなりますか？
今までよりずっと本物らしくなったでしょう。
摩擦をよりリアルに再現しようとすると、もっと複雑な計算が必要なのですが、手軽さと結果のバランスを考えるとこれくらいが最適な方法だと考えられます。</p>

<h2>いよいよバネ！</h2>

<p>いや～長かった。
それではバネの動きを実装しましょう。</p>

<p>まず、バネの端っこはもちろんこのボールに繋げるわけですが、もう片方の端も固定しなければなりません。
そこでバネのもう一つの端を画面の真ん中に設定します。
フィールド変数で以下のように宣言しましょう。</p>

<pre><code>//バネの中心点
public var springX:Number = stage.stageWidth / 2;
public var springY:Number = stage.stageHeight / 2;
</code></pre>

<p>次に、ボールの真ん中と、バネの中心点が繋がっているように線を描写する関数を作っておきます。</p>

<pre><code>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);
}
</code></pre>

<p>そしてバネの力をボールの運動に反映させます。
この場合はどのように考えたらいいのでしょうか。</p>

<p>まず、バネは常にボールをある力で引っ張ります。常に引っ張るということはボールの速度に常に影響を与え続けるということです。
ということは重力と同じように<em>onEnterFrame</em>関数内で、速度に対して何らかの処理をすればいいということですね。
速度に何をしたらいいのでしょうか。ポイントは以下の２つです。</p>

<ul>
<li>バネの中心点に向かった力を加える</li>
<li>バネの中心点から離れれば離れるほど、与える力は強くなる</li>
</ul>

<p>これらを考慮したコードは以下のようになります。</p>

<pre><code>//バネによる速度の変化
vx += (springX - ball.x) * 0.07;
vy += (springY - ball.y) * 0.07;
</code></pre>

<p>(springX, springY)というバネの中心点の座標から、ボールの中心点の座標を引いています。
そしてそれに一定数を掛け合わせ、速度に加えています。</p>

<p>バネの中心点の座標と、ボールの中心点の座標の差が負の値になってもこのコードはうまく動作します。
その理由は皆さん考えてください。
上記のコードを、先ほどの摩擦の計算の前に入れましょう。このバネの力にも摩擦は考慮されるべきだからです。</p>

<p>そして、<em>onEnterFrame</em>関数の一番最後でバネの描写の関数である<em>drawSpring</em>を呼び出します。</p>

<pre><code>//バネの描画
drawSpring();
</code></pre>

<p>ボールのドラッグ中にもバネは描画して欲しいので、<em>onDragEnterFrame</em>関数の最後にも入れておきましょう。</p>

<h2>完成！！</h2>

<p>さぁ、これでリアルな動きをするようになりました。
ボールをドラッグしてバネを伸ばし、ボタンを離してみてください。もしくは思いっきり投げつけてみましょう。</p>

<p><embed src="/media/2/20080805-Animation2.swf" quality="high" type="application/x-shockwave-flash" width="400" height="400"align="middle"  pluginspage="http://www.adobe.com/go/getflashplayer_jp" /></p>

<p>最後にここまでで出来たソースコードを掲載します。
次回のネタは今考えているところです。お楽しみに！</p>

<pre><code>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 &lt; ballR){
                ball.x = ballR;
                vx *= -0.9;
            }else if(stage.stageWidth - ballR &lt; ball.x){
                ball.x = stage.stageWidth - ballR;
                vx *= -0.9;
            }

            //縦向きのチェック
            if(ball.y &lt; ballR){
                ball.y = ballR;
                vy *= -0.9;
            }else if(stage.stageHeight - ballR &lt; 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);
        }
    }
}
</code></pre>
]]></content>
 <id>http://blog.garden-place.jp/oborobeer/:2:186</id>
</entry><entry>
 <title type="html"><![CDATA[Flex入門者がアニメーションを基礎から説明してみる #5]]></title>
 <link rel="alternate" type="text/html" href="http://blog.garden-place.jp/oborobeer/item_184.html" />
 <author>
  <name>obanetty</name>
 </author>
 <updated>2008-08-02T15:41:55Z</updated>
 <published>2008-08-03T00:41:55+09:00</published>
 <content type="html"><![CDATA[<p>さて、今回はバネの運動を紹介しようと思いましたが、やめました。
その事前準備の説明で今回の記事は十分な長さになりそうだからです。</p>

<p>今回紹介するのは今までの復習のようなものです。
基本となるのははボールの落下、反射です。そこに少しだけ機能を加えてボールのドラッグと、ボールを放り投げる処理を入れて今回は終わります。
そこに次回、鮮やかな修正を加えてバネの動きを実現します。</p>

<h2>復習　「ボールの落下、反射」</h2>

<p>ではまず、新しいActionScriptプロジェクトを作成しましょう。
いつも通り、Flex Builder 3を前提として話していますので、他の環境の方は読み替えてください。
単にActionScriptのクラスファイルを１つ作成するだけです。
プロジェクト名、クラス名は何でもいいです。僕はAnimation2というプロジェクトを作成しました。</p>

<p>そこに以下のように入力しましょう。</p>

<pre><code>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 &lt; ballR){
                ball.x = ballR;
                vx *= -0.9;
            }else if(stage.stageWidth - ballR &lt; ball.x){
                ball.x = stage.stageWidth - ballR;
                vx *= -0.9;
            }

            //縦向きのチェック
            if(ball.y &lt; ballR){
                ball.y = ballR;
                vy *= -0.9;
            }else if(stage.stageHeight - ballR &lt; ball.y){
                ball.y = stage.stageHeight - ballR;
                vy *= -0.9;
            }
        }
    }
}
</code></pre>

<p>最初から読み進めてきた方なら、なんなく理解できるでしょう。
今までと少し違うのはボールが枠からはみ出したかどうかのチェックをcheckWallという一つの関数に切り出したくらいです。
あと、重力の加速度を2に設定して、少し前よりも重力を強くしています。</p>

<p>落下はonEnterFrameの最後の<em>vy += ay;</em>がポイントでした。反射はcheckWall関数で枠からはみ出していたときに、速度に-0.9をかけて、反転しつつ少し絶対値を小さくしています。</p>
<h2>ドラッグドロップ処理追加</h2>

<p>ボールをドラッグできるように、init関数の中に以下の処理を追加しましょう。</p>

<pre><code>//ボールをマウスでドラッグできるようにする
ball.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
ball.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
</code></pre>

<p>マウスのボタンをクリックしたときに<em>onMouseDown</em>関数、ボタンを離したときに<em>onMouseUp</em>関数が実行されるようにしました。
それぞれの関数は以下のように実装します。</p>

<pre><code>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();
}
</code></pre>

<p>onMouseDown関数でドラッグ開始の処理を実装します。
まず、いったんボールのドラッグを始めるとボールの速度は0に設定しています。
ボタンを離してボールを解放したときに、今までのボールの速度を保持せず、またそこから新たに落下処理を始めるためです。</p>

<p>また、フレーム毎の移動処理も停止させるため、以下の一行でイベント処理を削除します。
これにより<em>onEnterFrame</em>関数は実行されなくなります。</p>

<pre><code>//ドラッグ中はボールの移動処理をしない
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
</code></pre>

<p>最後に、ドラッグ開始します。</p>

<pre><code>ball.startDrag();
</code></pre>

<p>この一行だけでボールのドラッグ移動が可能になるなんて便利すぎです。</p>

<p>そして<em>onMouseUp</em>関数でドラッグ終了。
終了時にはフレーム毎の移動処理が再開されるように<em>onEnterFrame</em>関数を再登録します。</p>

<pre><code>//ボールの移動処理を再開
addEventListener(Event.ENTER_FRAME, onEnterFrame);
</code></pre>

<p>そしてドラッグ終了もこの一行。便利便利万歳。（←わかる人は友達）</p>

<pre><code>ball.stopDrag();
</code></pre>

<p>これでボールをドラッグして移動させることができるようになりました。</p>

<h2>放り投げちゃえ！</h2>

<p>次はボールを放り投げる処理を追加します。
ドラッグで移動した後に、マウスのボタンを離しながらポーンと好きな方向に投げれるようにしましょう。
投げる勢いも実際のマウスの動きから取得するようにしましょう。</p>

<p>どういう考え方でこれを実装すればいいか解説します。
実際のボタンを離した瞬間のマウスの動きを取ることはできません。
ですので、ボタンを離す直前の動きを使用します。
ということはドラッグ中のマウスの移動方向、速度を取得する必要があるということですね。</p>

<p>実はこれは全然難しくありません。
ドラッグ中は常にマウスの位置だけを記録していればいいのです。
そしてマウスのボタンを離した瞬間の<em>onMouseUp</em>関数の中でもマウスの位置を取得できます。
この２点を比較すれば、直前のマウスの移動方向と距離、すなわち速度が取得できます。
スピードをつけて投げれば投げるほど、この２点間の距離は離れているはずですから。</p>

<p>では、ドラッグ中に常にマウスの位置を記録しておくために、フィールド変数を追加しましょう。</p>

<pre><code>//ドラッグ中のマウスのX,Y座標
public var tempX:Number;
public var tempY:Number;
</code></pre>

<p>そしてドラッグ中は常にこの変数に座標を上書き保存し続ける関数を追加します。</p>

<pre><code>private function onDragEnterFrame(event:Event):void{
    tempX = mouseX;
    tempY = mouseY;
}
</code></pre>

<p>ドラッグ中は常にこの関数が実行されるように<em>onMouseDown</em>関数を以下のように変更します。
ドラッグが終了するとこの関数が実行されないように<em>onMouseUp</em>関数内で除去します。</p>

<pre><code>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();
}
</code></pre>

<p>マウスのボタンを離したときに、直前のマウスの座標と現在のマウスの座標から、ボールを放り投げるべき速度と方向を取得しなくてはなりません。
これは２点間の位置関係を算出するだけで簡単に実装できます。</p>

<p><em>onMouseUp</em>関数に以下の記述を加えましょう。
X方向にマウスが動いた距離がそのままボールのX方向の速度に、Y方向にマウスが動いた距離がそのままボールのY方向の速度になります。</p>

<pre><code>//ボールを放り投げるX速度とY速度を設定
vx = mouseX - tempX;
vy = mouseY - tempY;
</code></pre>

<h2>完成！！</h2>

<p>さあ、マウスのドラッグでボールを掴んで放り投げてみましょう。</p>

<p><embed src="/media/2/20080803-Animation2_2.swf" quality="high" type="application/x-shockwave-flash" width="400" height="400"align="middle"  pluginspage="http://www.adobe.com/go/getflashplayer_jp" /></p>

<p>うまくいきましたか？
ではここまでのソースコードを載せて今回は終了します。
次回は、ここにバネの動きを追加します。</p>

<pre><code>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 &lt; ballR){
                ball.x = ballR;
                vx *= -0.9;
            }else if(stage.stageWidth - ballR &lt; ball.x){
                ball.x = stage.stageWidth - ballR;
                vx *= -0.9;
            }

            //縦向きのチェック
            if(ball.y &lt; ballR){
                ball.y = ballR;
                vy *= -0.9;
            }else if(stage.stageHeight - ballR &lt; ball.y){
                ball.y = stage.stageHeight - ballR;
                vy *= -0.9;
            }
        }
    }
}
</code></pre>
]]></content>
 <id>http://blog.garden-place.jp/oborobeer/:2:184</id>
</entry><entry>
 <title type="html"><![CDATA[Flex入門者がアニメーションを基礎から説明してみる #4]]></title>
 <link rel="alternate" type="text/html" href="http://blog.garden-place.jp/oborobeer/item_183.html" />
 <author>
  <name>obanetty</name>
 </author>
 <updated>2008-07-27T15:08:53Z</updated>
 <published>2008-07-28T00:08:53+09:00</published>
 <content type="html"><![CDATA[<p>さて、今回は重力の働きを再現してみます。
前回はビリヤード台を上から見たようなイメージのものだったけど、それでは重力を観察できないため、横から見たイメージでいきます。
水槽の中でバウンドしているボールという感じになるでしょう。</p>

<h2>前回の修正</h2>

<p>前回のコードのままでは、ボールが枠の外にでてしまう可能性があります。
それを防ぐために修正を入れましょう。</p>

<p>onEnterFrame関数のはみ出しチェック内を以下のように修正します。</p>

<pre><code>        //画面領域からはみ出した場合は、移動量の正負反転
        //横方向のはみ出しチェック
        if(ball.x - ballR &lt; 0){
            //左方向にはみ出した
            vx *= -1;
            ball.x = ballR;
        }else if(stage.stageWidth &lt; ball.x + ballR){
            //右方向にはみ出した
            vx *= -1;
            ball.x = stage.stageWidth - ballR;
        }
        //縦方向のはみ出しチェック
        if(ball.y - ballR &lt; 0){
            //上方向にはみ出した
            vy *= -1;
            ball.y = ballR;
        }else if(stage.stageHeight &lt; ball.y + ballR){
            //下方向にはみ出した
            vy *= -1;
            ball.y = stage.stageHeight - ballR;
        }
</code></pre>

<p>はみ出したボールの位置を壁にピッタリつくところにセットしています。
座標がはみ出したままだと、何かの拍子に壁に入り込んでしまうことがあるためです。
では、今回の課題に入っていきましょう。</p>

<h2>等加速度運動</h2>

<p>今回の一番の肝がこれです。等加速度運動。漢字は似てるけど最初にやった等速直線運動とは別のものです。
ちなみに等速直線運動を少し思い出してみましょう。</p>

<p>物体が直線上をずっと同じ速度で運動する</p>

<p>でしたね。
地球上では摩擦があるので実際にはあまり目にすることがないのですが、ビリヤードの球とか氷の上のカーリングは摩擦が小さいので等速直線運動に近い状態です。
また、止まっている物体も速度０で等速直線運動をしていると考えられます。</p>

<p>つまりポイントは</p>

<p><b>周りから余計な力が働いていない</b></p>

<p>ということなのです。この条件を満たす物体は全て等速直線運動をしていると言っていいでしょう。
ちなみに自信は９９％くらいなので、間違ってたら指摘しなさい。</p>

<p>で、等加速度運動の説明です。
等加速度運動という字を見て分かる通り</p>

<p><b>加速度がずっと等しいのです。</b></p>

<p>加速度って何か、速度に影響を与える力です。つまり何らかの力だと考えたらいいです。
そして、周りから加わる力が常に一定方向に同じ力だけ働いているのです。</p>

<p>例を考えてみましょう。
宇宙空間に漂うロケットを想像してください。
さっきまでエンジンを入れていたのですが、今は切っています。
するとどうなりますか？
先ほどまでの推進力の惰性で、ずっと同じスピードでスーッと動いているでしょう。</p>

<p><b>はい、これが等速直線運動。</b></p>

<p>何も力が加わってませんよね。
そして、ここでエンジンを入れました。
エンジンの出力パワーは同じまま、ゴーッとしばらくエンジンを点けたらどうなりますか？
ロケットのスピードはもちろん速くなります。
どういう風に早くなるか、重い物体はスピードに乗るまでにしばらく時間がかかります。
だから初めはゆっくり、だんだん速く、グィイイイイーーーーンってスピードが上がっていくはずです。</p>

<p><b>はい、これが等加速度運動。</b></p>

<p>速度を上げるために常に同じ力で押しているので、速度はある一定のペースで増加、もしくは減少しつづけます。
プログラム的に言えば、ある一定時間ごとに速度自体を+1していると思えばいいでしょう。
そして速度は位置情報、つまり(x, y)に加算されるので、加算する値が毎回少しずつ変化するのです。
同じペースでね。</p>

<p><b>だから、等加速度運動</b></p>

<p>速度に影響を与えるものが加速度で、それが同じ大きさってこと。</p>

<h2>重力</h2>

<p>では、重力はどうやって表現するのか？</p>

<p><b>簡単です</b></p>

<p>等加速度運動です。
地球はその重力によって、常に地球上の物体を下に引っ張っています。
しかも、常に同じ力で（厳密には高度によって替わりますが、ほぼ一緒なので無視します）。</p>

<p><b>これって等加速度運動です。</b></p>

<p>つまり地球上にいるとき、僕たちは常に真下に向かってロケットエンジンを噴射し続けているのです。
だから、足で踏ん張って立たないといけないのですね。</p>
<h2>能書きはいいからプログラム</h2>

<p>なぜ・・・なぜこんなにも能書きが長くなったのか。
それは訳があります。
それは・・・</p>

<p><b>プログラムの修正があまりにも少なすぎるから！！！</b></p>

<p>はっきり言って、初めてこれを実装したときは衝撃でした。
皆さんも同じ衝撃を感じてくれたら嬉しい限りです。
では、前回のプログラムに修正を加えましょう。
コメントを除けば、わずか２行の修正です。</p>

<p>ではいきます。
最終的なコードは最後に載せます。</p>

<p>まず、最初の変数宣言のところに重力を表す加速度を宣言します。</p>

<pre><code>//重力によるy方向の加速度
public var ay:Number = 1;
</code></pre>

<p>下に引っ張るので、y方向にプラスの影響を与えるので正の数となります。
1というのは、まあ適当ですね。</p>

<p>そしてonEnterFrame関数の最後に以下の記述を加えます。</p>

<pre><code>//重力による速度の変化
vy += ay;
</code></pre>

<p>yの速度に一定数としてayを毎回加えているのですね。</p>

<p><b>たったこれだけdeath</b></p>

<p>では実行してください。
なんとなく重力が働いているみたいでしょう？</p>

<p>・・・。</p>

<p>でも少し不自然ですね。
その原因は跳ね返ったボールが毎回同じ高さまで跳ね返ってくるので、いつまでたってもボールが止まらないからです。
通常、壁などでボールが反射するときは摩擦で速度が一部失われます。</p>

<p>では、上記の現象をコードに落とし込んでみましょう。
壁に跳ね返る場所・・・例えばここですね。</p>

<pre><code>//左方向にはみ出した
vx *= -1;
</code></pre>

<p>上下左右にはみ出した場合で合計４箇所あります。
ここで速度を反転しているのですが、-1をかけているのが問題のようです。
摩擦で力が失われることなく、反対側に同じ速度で飛んでいってしまいます。</p>

<p>方向としては反対側に飛ばしたいので、マイナスはマイナスなのですが、少し速度を小さくするために-0.9をかけるようにしてみましょう。</p>

<pre><code>//左方向にはみ出した
vx *= -0.9;
</code></pre>

<p>ちゃんと４箇所書き換えてください。これでどうでしょう。</p>

<h2>完成</h2>

<p>ボールは見事に日常生活で見られる、あの動きをしているように見えます。
空気抵抗は考えていないため、横方向の移動はいつまでたっても終わらないのが、やや不自然です。
この実装はもうみなさんにお任せしてみましょう。</p>

<p><embed src="/media/2/20080728-Animation1_2.swf" quality="high" type="application/x-shockwave-flash" width="400" height="400"align="middle"  pluginspage="http://www.adobe.com/go/getflashplayer_jp" /></p>

<p>ちなみにayの値を1以外の色んな値に変化させてみると面白いです。
この世界での重力が変わるわけです。
月のような重力の少ない世界にしてみるのか、重力装置で１００倍の重力を再現した部屋、みたいにしてみるのか。
全てはあなたの思うままです。</p>

<p>では、ここまでのコードを掲載して今回は終わります。</p>

<pre><code>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 &lt; 0){
                //左方向にはみ出した
                vx *= -0.9;
                ball.x = ballR;
            }else if(stage.stageWidth &lt; ball.x + ballR){
                //右方向にはみ出した
                vx *= -0.9;
                ball.x = stage.stageWidth - ballR;
            }
            //縦方向のはみ出しチェック
            if(ball.y - ballR &lt; 0){
                //上方向にはみ出した
                vy *= -0.9;
                ball.y = ballR;
            }else if(stage.stageHeight &lt; ball.y + ballR){
                //縦方向にはみ出した
                vy *= -0.9;
                ball.y = stage.stageHeight - ballR;
            }

            //重力による速度の変化
            vy += ay;
        }
    }
}
</code></pre>

<p>次回はバネの働きでもやってみましょうかねぇ。</p>
]]></content>
 <id>http://blog.garden-place.jp/oborobeer/:2:183</id>
</entry><entry>
 <title type="html"><![CDATA[Flex入門者がアニメーションを基礎から説明してみる #3]]></title>
 <link rel="alternate" type="text/html" href="http://blog.garden-place.jp/oborobeer/item_180.html" />
 <author>
  <name>obanetty</name>
 </author>
 <updated>2008-07-21T16:21:07Z</updated>
 <published>2008-07-22T01:21:07+09:00</published>
 <content type="html"><![CDATA[<p>放置と思いきや、連続の更新ですよ。ある意味ツンデレみたいなもんですわ。
今回のテーマは「物体移動の角度と反射」です。
前回は縦方向と横方向の移動量だけを定義したけど、今回はそれに角度と速度をからめて考えます。</p>

<p>縦方向と横方向の移動量を決定したら角度と速度が確定します。
また、角度と速度を決定したら縦方向と横方向の移動量が確定します。
相互に変換できるので、その時々で便利な方を使うようにしましょう。</p>

<p>おっと、その前にタイトルを少し変えました。ActionScript→Flexに変更です。
それに合わせて過去の記事も変更させてもらいました。Flex主体で説明しているからね。</p>

<h2>Flexにおける角度</h2>

<p>Flexでの角度の考え方は、一般的な数学での考え方と同じです。
すなわち右に水平な方向が0度。そこから上に向かって角度が上がっていき垂直になったところが90度。
左方向に水平になって180度。下が270度で元の位置まで戻って360度です。
めんどくさいので図は用意しませんでした。</p>

<p>そして、一般的な数学と同じように角度から辺の長さを求めるのにsin, cos関数を使用します。
逆を求めるときは一般にatan関数を使用します。
詳しい説明はしません。
sin(角度）で実行するとその角度にふさわしいx方向の移動量が得られます。同じくcos(角度）でy方向の移動量が得られます。
これらの結果を現在の座標に加算することで、指定した角度の方向に距離１分だけ移動することになります。</p>

<p>Flexの事情ですが、角度をパラメータとして扱う場合、一般的な角度として扱う場合と、ラジアンという単位で扱う場合の2通りあります。
気温で言うと摂氏と華氏の違いのようなものです。
同じ角度を表すのでも違う数値になります。</p>

<p>そしてこれは関数毎に違うので、実行する関数によって普通の角度やラジアンを使い分けなくてはいけません。
ラジアンと角度は以下の計算で相互に変化できるので、少しめんどくさいけど問題はありません。
（Math.PIは円周率）</p>

<ul>
<li><p>角度→ラジアン</p>

<p>(ラジアン) = （角度） x Math.PI / 180</p></li>
<li><p>ラジアン→角度</p>

<p>（角度） = （ラジアン） x 180 / Math.PI</p></li>
</ul>

<h2>速度</h2>

<p>指定した角度にどれくらいの移動量で移動するか、それが速度です。
sin, cos関数で得られた(x, y)にそれぞれ速度vをかけた値を(vx, vy)とすると、現在の座標に(vx, vy)を加算したとき、
物体の移動量はvとなります。
証明はしません。そうなるのだと思ってください。
どうしても知りたい方は高校の数学か物理の範囲で検索すれば出てくるかと思います。</p>

<h2>　反射</h2>

<p>次は反射です。
今回は壁に反射するケースだけを考えるので非常に簡単です。
左右の壁を超えた時はx方向の速度の正負を反転してあげるだけ。同じく上下の壁を超えた時はy方向の速度の正負を反転。
なぜそうなるのかは、考えましょう。</p>
<h2>サンプル</h2>

<p>では実際のサンプルです。
今回も新しくプロジェクトを作成してもいいですが、前回のサンプルにちょっとした修正をいれるだけなので、前回との比較をしてみると面白いと思います。
以下のコードを入れてください。
クラス名は自分の環境に合わせてください。</p>

<pre><code>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 &lt; 0 || stage.stageWidth &lt; ball.x + ballR){
                //横方向にはみ出した
                vx *= -1;
            }
            //縦方向のはみ出しチェック
            if(ball.y - ballR &lt; 0 || stage.stageHeight &lt; ball.y + ballR){
                //縦方向にはみ出した
                vy *= -1;
            }
        }
    }
}
</code></pre>

<p>前回と変わった部分を中心に説明します。</p>

<pre><code>//ボール
public var ball:Sprite;
//ボールの半径
public var ballR:Number = 50;
//ボールの移動速度
public var v:Number = 20;
//ボールの横方向の移動量
public var vx:Number;
//ボールの縦方向の移動量
public var vy:Number;
</code></pre>

<p>まず、ボールの半径を色んな場所で使用するので変数化しました。</p>

<p>次に、今回は全体的な速度を20としました。x方向、y方向のそれぞれの移動量は角度から算出します。
それをしているのが以下の部分です。</p>

<pre><code>//ボールの移動角度設定
var radian:Number = Math.random() * 360;
radian = radian * 180 / Math.PI;

//角度の要素からx方向、y方向の移動量を取得
vx = Math.cos(radian) * v;
vy = Math.sin(radian) * v;
</code></pre>

<p>まず、ランダムにボールの移動角度を設定しています。
0度以上360度未満の角度を取得し、それをラジアンに変換しています。
分かりやすく書こうとしてこうなったのですが、以下のように書けば一行ですみます。</p>

<pre><code>var radian:Number = Math.random() * 2 * Math.PI;
</code></pre>

<p>そしてsin, cos関数でx, yの移動量を算出し、速度vをかけています。
上の方で説明した通りです。</p>

<p>最後に画面領域からはみ出た時の処理です。
ボールの座標はボールの中心点なので、ボールの半径を加減算することでボールの端が画面の外にでているかを判定しています。
半径は50なので、50を加減算してもいいのですが、今後ボールの半径を変更したとしてもここを変更しないで済むようにこうしておきます。</p>

<p>はみ出たときは、上で説明した通り、xかyの進行方向の正負のフラグを反転してやるだけです。
縦方向と横方向同時にはみ出すことを考慮して、条件式はそれぞれ書いてやる必要があります。</p>

<pre><code>//画面領域からはみ出した場合は、移動量の正負反転
//横方向のはみ出しチェック
if(ball.x - ballR &lt; 0 || stage.stageWidth &lt; ball.x + ballR){
    //横方向にはみ出した
    vx *= -1;
}
//縦方向のはみ出しチェック
if(ball.y - ballR &lt; 0 || stage.stageHeight &lt; ball.y + ballR){
    //縦方向にはみ出した
    vy *= -1;
}
</code></pre>

<h2>完成</h2>

<p>できました。
画面をクリックしたら動きます。
なお、細かい調整部分は省略しているので、たまにボールが画面の外に出て動きがおかしくなる可能性があります。
今回は説明を簡略化するために、あえてこのままにします。
あと、なぜか家のFirefoxに限って境界の位置が微妙にずれる・・・。</p>

<p><embed src="/media/2/20080727-Animation1.swf" quality="high" type="application/x-shockwave-flash" width="400" height="400"align="middle"  pluginspage="http://www.adobe.com/go/getflashplayer_jp" /></p>

<p>これでビリヤードとかエアホッケーっぽくなりました。
延々動き続けるのは、摩擦を考慮に入れていないからです。
最後に摩擦を考慮するコードを入れてみましょう。</p>

<p>onEnterFrame関数の最初に以下の2文を入れます。</p>

<pre><code>vx *= 0.98;
vy *= 0.98;
</code></pre>

<p>つまり速度が徐々に目減りして0に近づくようにしているのですね。
どうですか？徐々に遅くなって止まったでしょ？</p>

<p>今回はここまでです。
次回は・・・どうしようかなぁ・・・？<br />
もう一つの主役、重力の話でもしましょう。
これは多分、週末になる予感。</p>
]]></content>
 <id>http://blog.garden-place.jp/oborobeer/:2:180</id>
</entry>
</feed>
