In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

試作:ロープ

ロープアクションで使うためのロープの試作。

左右キーで揺らせる。
Get Adobe Flash player
by o_healer 30 Oct 2010
    Embed
/**
 * Copyright o_healer ( http://wonderfl.net/user/o_healer )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/maXQ
 */

/*
 ターザンロープ試作

 概要
 - ロープアクションで使うためのロープの試作

 操作方法
 - 十字キーの左右でロープを揺らせる

 アルゴリズム
 - 関節の数だけ「ポイント」を用意
 - それぞれのポイントに対して「速度&重力」による移動先を計算
 - それぞれのポイントが一定距離になるように位置を修正
 - 修正した位置を元に、速度を逆算

 ゲームに使う場合の問題点
 - 先端の速度が不安定
 -- プレイヤーの制御がしづらいので、意図しない方向に飛んでしまいそう
 -- もう少しベタな振り子運動の方が、ジャンプ方向を決定しやすいはず

 その他
 - 関節の位置がユーザにわかってしまう問題は、表示だけベジエにすることで解決するはず
 - PointではなくVector3Dにした方が計算がしやすかったかもしれない
*/

package {
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.system.*;
    import flash.text.*;
    import flash.media.*;
    import flash.ui.*;
 
    [SWF(width="465", height="465", frameRate="60", backgroundColor="0x000000")]
    public class GameMain extends Sprite {

        //==Const==

        //表示サイズ
        static public const VIEW_W:int = 465;
        static public const VIEW_H:int = 465;

        //ポイント数(先端と終端を含めた関節数)
        static public const POINT_NUM:int = 10;
        //ポイント間の距離
        static public const POINT_DISTANCE:Number = VIEW_H/POINT_NUM * 0.4;

        //入力による移動力
        static public const MOVE_POW:Number = 400.0;
        //重力
        static public const GRAVITY:Number = -250.0;//50.0;
        //ポイントの距離の補正の試行回数
        static public const TRY_COUNT:int = 3;
        //擬似空気抵抗(速度の減衰率)
        static public const DEC_RATIO:Number = 0.99;

        //ラインの太さ
        static public const LINE_W:int = 8;


        //==Var==

        //ロープの各点([0]が根元)
        public var m_Point:Array = new Array(POINT_NUM);

        //ロープのグラフィック
        public var g:Graphics;

        //入力
        public var m_InputL:Boolean = false;
        public var m_InputR:Boolean = false;


        //==Function==

        //Init
        public function GameMain(){
            var i:int;

            //ロープの描画登録
            {
                var shape:Shape = new Shape();
                g = shape.graphics;

                addChild(shape);
            }

            //ポイントの初期化
            {
                for(i = 0; i < POINT_NUM; i++){
                    m_Point[i] = new RopePoint();
                    m_Point[i].m_Pos.x = VIEW_W/2;
                    m_Point[i].m_Pos.y = VIEW_H/4 + i * POINT_DISTANCE;
                }
            }

            //入力監視
            {
                addEventListener(
                    Event.ADDED_TO_STAGE,//stageに触るので、stageに登録されたあとに設定
                    function(e:Event):void{
                        //キー入力を見る
                        stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
                        stage.addEventListener(KeyboardEvent.KEY_UP, OnKeyUp);
                    }
                );
            }

            //Update
            {
                addEventListener(Event.ENTER_FRAME, Update);
            }
        }

        //Input
        private function OnKeyDown(event:KeyboardEvent):void{
            switch(event.keyCode){
            case Keyboard.LEFT:    m_InputL = true; break;
            case Keyboard.RIGHT:m_InputR = true; break;
            }
        }
        private function OnKeyUp(event:KeyboardEvent):void{
            switch(event.keyCode){
            case Keyboard.LEFT:    m_InputL = false; break;
            case Keyboard.RIGHT:m_InputR = false; break;
            }
        }

        //Update
        public function Update(e:Event=null):void{
            var DeltaTime:Number = 1.0 / stage.frameRate;

            //入力による速度補正
            Update_Input(DeltaTime);

            //実際のロープの移動
            Update_Move(DeltaTime);

            //描画
            Redraw();
        }

        //Update : Input
        public function Update_Input(in_DeltaTime:Number):void{
            var InputVal:Number = 0;
            {
                if(m_InputL){InputVal -= 1;}
                if(m_InputR){InputVal += 1;}
            }

            {
/*
                //先端だけだと変なふうに曲がる
                m_Point[POINT_NUM-1].m_Vel.x += InputVal * MOVE_POW * in_DeltaTime;
//*/
/*
                //一つ手前だと先がおいてけぼりな感じ
                m_Point[POINT_NUM-2].m_Vel.x += InputVal * MOVE_POW * in_DeltaTime;
//*/
/*
                //先端の2つだとそこそこそれっぽい
                m_Point[POINT_NUM-1].m_Vel.x += InputVal * MOVE_POW * in_DeltaTime;
                m_Point[POINT_NUM-2].m_Vel.x += InputVal * MOVE_POW * in_DeltaTime;
//*/
//*
                //先端の力が大きくなるように全体にかけるとわりとそれっぽい
                for(var i:int = 0; i < POINT_NUM; i++){
                    var ratio:Number = i/(POINT_NUM-1.0);
                    ratio *= ratio;//固定点付近の力をさらに少なくする
                    m_Point[i].m_Vel.x += InputVal * MOVE_POW * in_DeltaTime * ratio;
                }
//*/
            }
        }

        //Update : Move
        public function Update_Move(in_DeltaTime:Number):void{
            var i:int;

            //まずは慣性(Vel)と重力(Gravity)での移動先を算出
            var NextPos:Array = new Array(POINT_NUM);
            {
                for(i = 0; i < POINT_NUM; i++){
                    //想定移動先
                    if(i == 0){NextPos[i] = new Point(m_Point[i].m_Pos.x, m_Point[i].m_Pos.y); continue}

                    NextPos[i] = new Point(
                        (m_Point[i].m_Pos.x) + (m_Point[i].m_Vel.x * in_DeltaTime),
                        (m_Point[i].m_Pos.y) + (m_Point[i].m_Vel.y * in_DeltaTime) + (-GRAVITY * 0.5*in_DeltaTime*in_DeltaTime)
                    );
                }
            }

            //ポイント間の距離を一定に保とうとする
            {
                for(var c:int = 0; c < TRY_COUNT; c++){
                    //for(i = 1; i < POINT_NUM; ++i)
                    for(i = POINT_NUM-1; i > 0; i--)
                    {
                        var SrcIndex:int = i-1;
                        var DstIndex:int = i;

                        var SrcPos:Point = NextPos[SrcIndex];
                        var DstPos:Point = NextPos[DstIndex];

                        var Center:Point = new Point(
                            (DstPos.x + SrcPos.x)/2,
                            (DstPos.y + SrcPos.y)/2
                        );

                        var Src_Dst:Point = new Point(
                            (DstPos.x - SrcPos.x),
                            (DstPos.y - SrcPos.y)
                        );
                        Src_Dst.normalize(1);

                        SrcPos.x = Center.x - POINT_DISTANCE/2 * Src_Dst.x;
                        SrcPos.y = Center.y - POINT_DISTANCE/2 * Src_Dst.y;
                        DstPos.x = Center.x + POINT_DISTANCE/2 * Src_Dst.x;
                        DstPos.y = Center.y + POINT_DISTANCE/2 * Src_Dst.y;
                    }

                    //[0]は戻す
                    NextPos[0].x = m_Point[0].m_Pos.x;
                    NextPos[0].y = m_Point[0].m_Pos.y;
                }
            }

            //速度の再計算
            {
                for(i = 0; i < POINT_NUM; ++i){
                    //今回の移動量から逆算
                    m_Point[i].m_Vel.x = (NextPos[i].x - m_Point[i].m_Pos.x) / in_DeltaTime;
                    m_Point[i].m_Vel.y = (NextPos[i].y - m_Point[i].m_Pos.y) / in_DeltaTime;

                    //重力による速度補正
                    m_Point[i].m_Vel.y -= GRAVITY * in_DeltaTime;

                    //擬似空気抵抗
                    m_Point[i].m_Vel.x *= DEC_RATIO;
                    m_Point[i].m_Vel.y *= DEC_RATIO;
                }
            }

            //位置の正式採用
            {
                for(i = 0; i < POINT_NUM; ++i){
                    m_Point[i].m_Pos = NextPos[i];
                }
            }
        }

        //Redraw
        public function Redraw():void{
            g.clear();
            g.lineStyle(LINE_W, 0xFFFFFF, 1.0);

            g.moveTo(m_Point[0].m_Pos.x, m_Point[0].m_Pos.y);
            for(var i:int = 1; i < POINT_NUM; i++){
                g.lineTo(m_Point[i].m_Pos.x, m_Point[i].m_Pos.y);
            }
        }
    }
}

import flash.geom.*;

class RopePoint
{
    //==Var==
    public var m_Pos:Point = new Point(0,0);
    public var m_Vel:Point = new Point(0,0);
}