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

試作:ショットで壁を撃ち抜くAct

試作:ショットで壁を撃ち抜くAct:2D
 ・DisplacementMapFilterで地形に干渉するアクションゲームの試作
 ・ねじ曲げ方については「DisplacementMapFilterで四分の一円 ( http://wonderfl.net/c/bzmh )」を参考にした

 操作方法(画面を2回ほどクリックしないとキーボード操作できないかもしれません)
 ・十字キー
  ・移動&ジャンプ
 ・SPACE(半角で)
  ・ショット(地形に当たると地形をねじ曲げる)
Get Adobe Flash player
by o_healer 28 Jul 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/lmjM
 */

/*
 試作:ショットで壁を撃ち抜くAct:2D
 ・DisplacementMapFilterで地形に干渉するアクションゲームの試作
 ・ねじ曲げ方については「DisplacementMapFilterで四分の一円 ( http://wonderfl.net/c/bzmh )」を参考にした

 操作方法(画面を2回ほどクリックしないとキーボード操作できないかもしれません)
 ・十字キー
  ・移動&ジャンプ
 ・SPACE(半角で)
  ・ショット(地形に当たると地形をねじ曲げる)
*/

package
{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.text.*;
    import flash.filters.*;
    import flash.ui.*;

    public class GameMain extends Sprite
    {
        //==Const==

        //干渉半径
        static public const DIS_RAD:int = 0x20;

        //プレイヤーの初期位置
        static public const PLAYER_INIT_X:int = 70;
        static public const PLAYER_INIT_Y:int = 70;

        //Utility
        static public const POS_ZERO:Point = new Point(0,0);


        //==Var==

        //背景
        public var m_BitmapData_View:BitmapData;

        //破壊部分(背景を一度これにコピーして、Filterで破壊してから背景に書き戻す)
        public var m_Bitmap_Destroy:Bitmap;

        //コリジョン(背景を太く書き出して、プレイヤーのためのコリジョンとして扱う)
        public var m_BitmapData_Collision:BitmapData;

        //プレイヤー
        public var m_Player:Player;


        //==Function==

        //Static Global Access
        static private var m_Instance:GameMain;
        static public function Instance():GameMain{return m_Instance;}

        //Init
        public function GameMain() 
        {
            m_Instance = this;
            addEventListener(Event.ADDED_TO_STAGE, Init);
        }

        public function Init(e:Event=null):void
        {
            var g:Graphics;

            //Init Once
            {
                removeEventListener(Event.ADDED_TO_STAGE, init);
            }

            //コリジョン
            {
                m_BitmapData_Collision = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0xFFFFFFFF);

                //debug
//                addChild(new Bitmap(m_BitmapData_Collision));
            }

            //背景
            {
                //Create & Regist
                {
                    m_BitmapData_View = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0xFFFFFF);
                    addChild(new Bitmap(m_BitmapData_View));
                }

                //Draw
                {
                    var shape_bg:Shape = new Shape();
                    g = shape_bg.graphics;

                    g.clear();
                    g.lineStyle(3, 0x000000);

                    g.drawRect(50, 50, 200, 100);

                    g.drawRect(150, 250, 200, 100);

                    g.beginFill(0x000000, 1.0);
                    g.drawRect(50, 100, 50, 50);
                    g.drawRect(350, 100, 200, 100);
                    g.drawRect(0, 300, 50, 50);
                    g.drawRect(50, 400, 50, 50);
                    g.drawRect(250, 400, 250, 150);
                    g.endFill();

                    m_BitmapData_View.draw(shape_bg);
                }
            }

            //破壊部分
            {
                //Create & Regist
                {
                    m_Bitmap_Destroy = new Bitmap(new BitmapData(2*DIS_RAD, 2*DIS_RAD, true, 0x00000000));
                }

                //フィルター
                {
                    //オフセットから色を計算
                    const calc_color:Function = function(in_GapX:int, in_GapY:int):uint{
                        if(in_GapX > 0){return 0x008080;}

                        var LenX:Number = DIS_RAD - Math.abs(in_GapX);
                        var LenY:Number = DIS_RAD - Math.abs(in_GapY);
                        LenY *= 1.5;

                        var Distance:Number = Math.sqrt(LenX*LenX + LenY*LenY);

                        var r:uint = 0x00;
                        var g:uint = 0x80 + LenX - Distance;
                        if(Distance > DIS_RAD){g = 0x80 + LenX - DIS_RAD;}
                        var b:uint = 0x80;// + in_GapY;
                        return (r << 16) | (g << 8) | (b << 0);
                    };

                    //オフセット値を格納したBitmap
                    var bmd_sampling:BitmapData = new BitmapData(2*DIS_RAD, 2*DIS_RAD, false, calc_color(0,0));

                    //歪めるための計算
                    for(var y:int = 0; y < 2*DIS_RAD; y++){
                        var GapY:int = DIS_RAD - y;
                        for(var x:int = 0; x < 2*DIS_RAD; x++){
                            var GapX:int = DIS_RAD - x;

                            bmd_sampling.setPixel(x, y, calc_color(GapX, GapY));
                        }
                    }

                    //実際にフィルターとして生成&セット
                    m_Bitmap_Destroy.filters = [
                        new DisplacementMapFilter(
                            bmd_sampling,//Sampling : Bitmap
                            null,//Sampling : Point
                            BitmapDataChannel.GREEN,//X
                            BitmapDataChannel.BLUE,//Y
                            0x100,//ScaleX
                            0x100,//ScaleY
                            DisplacementMapFilterMode.COLOR,//Mode
                            0x000000,//color
                            0//alpha
                        )
                    ];
                }
/*
                //Debug
                {
                    addChild(m_Bitmap_Destroy);

                    //初期化
                    Update_Destroy();

                    //マウスの移動のたびに更新
                    stage.addEventListener(MouseEvent.MOUSE_MOVE, Update_Destroy);
                }
/*/
                Update_Collision();
//*/
            }

            //プレイヤー
            {
                //Create & Regist
                {
                    m_Player = new Player(PLAYER_INIT_X, PLAYER_INIT_Y);
                    addChild(m_Player);
                }
            }
        }
/*
        //破壊部分の更新:デバッグ表示確認用
        static public var copy_rect:Rectangle = new Rectangle(0,0, 2*DIS_RAD,2*DIS_RAD);
        public function Update_Destroy(e:Event=null):void{
            var lx:int = mouseX-DIS_RAD;
            var uy:int = mouseY-DIS_RAD;

            //背景の該当部分をBitmapにコピー
            copy_rect.x = lx;
            copy_rect.y = uy;
            m_Bitmap_Destroy.bitmapData.copyPixels(m_BitmapData_View, copy_rect, POS_ZERO);

            m_Bitmap_Destroy.x = lx;
            m_Bitmap_Destroy.y = uy;

            //さらにコリジョンも更新
            Update_Collision();
        }
//*/
        //コリジョンの更新
        static public var mtx:Matrix = new Matrix();
        public function Update_Collision(e:Event=null):void{
            //背景を描画
            m_BitmapData_Collision.copyPixels(m_BitmapData_View, m_BitmapData_View.rect, POS_ZERO);

            //白い部分を透明にする
            m_BitmapData_Collision.threshold(m_BitmapData_Collision, m_BitmapData_Collision.rect, POS_ZERO, ">", 0xFF/2, 0x00000000, 0x000000FF);

            //さらにプレイヤーの厚みに合わせて相対的にコリジョン側の厚みを増やす(プレイヤーは1ドット分の大きさで済むように)
            const glow_filter_x:GlowFilter = new GlowFilter(0x000000,1.0, 2*Player.RAD,0, 255);
            const glow_filter_y:GlowFilter = new GlowFilter(0x000000,1.0, 0,2*Player.RAD, 255);
            m_BitmapData_Collision.applyFilter(m_BitmapData_Collision, m_BitmapData_Collision.rect, POS_ZERO, glow_filter_x);
            m_BitmapData_Collision.applyFilter(m_BitmapData_Collision, m_BitmapData_Collision.rect, POS_ZERO, glow_filter_y);
        }

        //コリジョンがあるか
        public function IsCollision(in_X:int, in_Y:int):Boolean{
            //範囲外チェック:ぶつかるようにする
            {
                if(in_X < 0){return true;}
                if(in_X >= m_BitmapData_Collision.width){return true;}
                if(in_Y < 0){return true;}
                if(in_Y >= m_BitmapData_Collision.height){return true;}
            }

            //あとは普通にコリジョンを見る
            var color:uint = m_BitmapData_Collision.getPixel32(in_X, in_Y);
            var a:uint = (color >> 24) & 0xFF;
            return a > 0xFF/2;//一定以上不透明だったらコリジョンとみなす
        }
    }
}


import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.*;
import flash.text.*;
import flash.filters.*;
import flash.ui.*;

//プレイヤー
internal class Player extends Sprite{

    //==Cost==

    //#Size
    static public const RAD:int = 8;

    //#Input
    static public var button_enum:int = 0;
    static public const BUTTON_L:int = button_enum++;
    static public const BUTTON_R:int = button_enum++;
    static public const BUTTON_U:int = button_enum++;
    static public const BUTTON_NUM:int = button_enum;

    //#Move
    static public const VEL_X:Number = 100.0;
    static public const VEL_Y:Number = 300.0;
    static public const ACC_Y:Number = 500.0;

    //==Var==

    //#Input
    public var m_Input:Array = new Array(BUTTON_NUM);

    //#Move
    public var m_VY:Number = 0.0;
    public var m_OnGround:Boolean = false;

    //==Function==

    //#Init
    public function Player(in_X:int, in_Y:int){
        //Pos
        {
            this.x = in_X;
            this.y = in_Y;
        }

        //Init Later (for Using "stage" etc.)
        addEventListener(Event.ADDED_TO_STAGE, Init );
    }

    public function Init(e:Event = null):void{
        var i:int;

        //Init Once Only
        {
            removeEventListener(Event.ADDED_TO_STAGE, Init );
        }

        //Create Graphic
        {
            var shape:Shape = new Shape();
            var g:Graphics = shape.graphics;

            g.lineStyle(2, 0xFF0000, 1.0);
            g.beginFill(0xFFFFFF, 1.0);
            g.drawCircle(0,0, RAD);
            g.endFill();

            addChild(shape);
        }
        
        //Input
        {
            //Init
            for(i = 0; i < BUTTON_NUM; i++){
                m_Input[i] = false;
            }

            //Listener
            stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDown);
            stage.addEventListener(KeyboardEvent.KEY_UP, KeyUp);
        }

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

    //#Input
    public function KeyDown(e:KeyboardEvent):void{
        switch(e.keyCode){
        case Keyboard.LEFT:        m_Input[BUTTON_L] = true;        this.scaleX = -1;    break;
        case Keyboard.RIGHT:    m_Input[BUTTON_R] = true;        this.scaleX = 1;    break;
        case Keyboard.UP:        m_Input[BUTTON_U] = true;        break;

        case Keyboard.SPACE:
//            GameMain.Instance().addChild(new Shot(this.x, this.y, 100 * this.scaleX));
            GameMain.Instance().addChild(new Shot(this.x, this.y, 100));//左に発射した時の地形干渉を用意してないので右にだけショット
            break;
        }
    }

    public function KeyUp(e:KeyboardEvent):void{
        switch(e.keyCode){
        case Keyboard.LEFT:        m_Input[BUTTON_L] = false;        break;
        case Keyboard.RIGHT:    m_Input[BUTTON_R] = false;        break;
        case Keyboard.UP:        m_Input[BUTTON_U] = false;        break;
        }
    }

    //#Update
    public function Update(e:Event):void{
        var DeltaTime:Number = 1.0 / 24.0;

        //Move
        {
           //Calc MoveVal
            var MoveX:int;
            var MoveY:int;
            {
                //X
                {
                    MoveX = 0;

                    if(m_Input[BUTTON_L]){MoveX -= VEL_X * DeltaTime;}
                    if(m_Input[BUTTON_R]){MoveX += VEL_X * DeltaTime;}
                }

                //Y
                {
                    //ジャンプ
                    if(m_OnGround && m_Input[BUTTON_U]){
                        m_VY = -VEL_Y;
                    }
                    m_OnGround = false;//毎回着地判定を行うので、着地しなかった時のためにリセット

                    //重力
                    m_VY += ACC_Y * DeltaTime;

                    MoveY = m_VY * DeltaTime;
                }
            }

            //移動アルゴリズム実行

            const BaseOffset:int = 1;//浮く量
            var Offset:int;

            var TrgX:int;
            var TrgY:int;

            var i:int;

            //Move : Up
            {
                TrgX = this.x;
                Offset = (MoveY < 0)? BaseOffset-MoveY: BaseOffset;

                for(i = 0; i < Offset; i++){
                    TrgY = this.y - 1;
                    if(GameMain.Instance().IsCollision(TrgX, TrgY)){
                        //天井にぶつかったので速度は0にする
                        m_VY = 0;
                        break;
                    }
                    this.y = TrgY;
                }
            }

            //Move : Horz
            {
                TrgX = this.x;
                TrgY = this.y;

                for(i = 0; i != MoveX; ){
                    if(i < MoveX){
                        i++;
                        TrgX++;
                    }else{
                        i--;
                        TrgX--;
                    }

                    if(GameMain.Instance().IsCollision(TrgX, TrgY)){break;}

                    this.x = TrgX;
                }
            }

            //Move : Down
            {
                TrgX = this.x;
                Offset = (MoveY > 0)? BaseOffset+MoveY: BaseOffset;

                for(i = 0; i < Offset; i++){
                    TrgY = this.y + 1;
                    if(GameMain.Instance().IsCollision(TrgX, TrgY)){
                        //接地したとみなす
                        m_OnGround = true;//ジャンプできるようにフラグオン
                        m_VY = 0;//速度リセット
                        break;
                    }
                    this.y = TrgY;
                }
            }
        }
    }
}



//ショット
internal class Shot extends Sprite{

    //==Const==

    static public const RAD:int = 4;


    //==Var==

    public var m_PosX:Number;
    public var m_PosY:Number;

    public var m_VX:Number;


    //==Function==

    public function Shot(in_X:int, in_Y:int, in_VX:Number){
        //Param
        {
            this.x = m_PosX = in_X;
            this.y = m_PosY = in_Y;

            m_VX = in_VX;
        }

        //Graphic
        {
            var shape:Shape = new Shape();
            var g:Graphics = shape.graphics;

            g.lineStyle(1, 0x444444, 1.0);
            g.beginFill(0x888888, 1.0);
            g.drawCircle(0,0, RAD);
            g.endFill();

            addChild(shape);
        }

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

    public function Update(e:Event=null):void{
        const DeltaTime:Number = 1/24.0;

        var TrgX:Number = m_PosX + m_VX * DeltaTime;
        var MoveX:int = TrgX - this.x;
        var LastX:int = this.x;
        for(var i:int = 0; i != MoveX; ){
            if(i < MoveX){
                i++;
            }else{
                i--;
            }

            if(GameMain.Instance().IsCollision(this.x + i, this.y)){
                //壁にぶつかった
                //→まわりをねじ曲げて消滅

                //まずは背景をコピー
                var rect:Rectangle = new Rectangle(LastX - GameMain.DIS_RAD, this.y - GameMain.DIS_RAD, 2*GameMain.DIS_RAD, 2*GameMain.DIS_RAD);
                const POS_ZERO:Point = new Point(0,0);
                GameMain.Instance().m_Bitmap_Destroy.bitmapData.copyPixels(GameMain.Instance().m_BitmapData_View, rect, POS_ZERO);

                //フィルターをかけたもので背景を上書き
                var mtx:Matrix = new Matrix();
                mtx.tx = rect.x;
                mtx.ty = rect.y;
                GameMain.Instance().m_BitmapData_View.draw(GameMain.Instance().m_Bitmap_Destroy, mtx);

                //さらに白円で塗りつぶしてみる
                var shape:Shape = new Shape();
                var g:Graphics = shape.graphics;
                g.lineStyle(0, 0x000000, 0.0);
                g.beginFill(0xFFFFFF, 1.0);
                g.drawCircle(LastX+32, this.y, 16);
                g.endFill();
                GameMain.Instance().m_BitmapData_View.draw(shape);

                //背景に基づきコリジョンを再計算
                GameMain.Instance().Update_Collision();

                //Kill
                parent.removeChild(this);
                removeEventListener(Event.ENTER_FRAME, Update);

                return;
            }

            LastX = this.x+i;
        }

        //壁にぶつからなかった
        //→普通に移動

        m_PosX = TrgX;
        this.x = m_PosX;
        
        //範囲外になったら死んでおく
        if(this.x > stage.stageWidth){
            parent.removeChild(this);
            removeEventListener(Event.ENTER_FRAME, Update);
        }
    }
}