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

forked from: Box2D試作:光源(視界)処理

An attempt at drawing shadows using the BitmapData hack from http://wonderfl.net/c/fDdO
/**
 * Copyright yonatan ( http://wonderfl.net/user/yonatan )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/5Ecc
 */

// forked from o_healer's Box2D試作:光源(視界)処理
package {
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.system.*;
    import flash.text.*;
    //Box2D
    import Box2D.Dynamics.*;
    import Box2D.Collision.*;
    import Box2D.Collision.Shapes.*;
    import Box2D.Common.*;
    import Box2D.Common.Math.*;
    import Box2D.Dynamics.Joints.*;
    [SWF(width="465", height="465", frameRate="30", backgroundColor="0xFFFFFF")]
    public class GameMain extends Sprite {
        //==Const==
        //画面サイズ
        static public const VIEW_W:int = 465;
        static public const VIEW_H:int = 465;
        //重力
        static public const GRAVITY:Number = 0.0;
        //Box2Dと実際の表示の比率(Box2Dに大きすぎる値を入れると上手く動かなかったりする)
        static public const PHYS_SCALE:Number = 10;
        static public function PHYS_to_IMAGE(in_Val:Number):Number{return in_Val * PHYS_SCALE;}
        static public function IMAGE_to_PHYS(in_Val:Number):Number{return in_Val / PHYS_SCALE;}
        //Box2Dの画面外の余白
        static public const BOX2D_RANGE_OFFSET:int = 100;
        //==Var==
        //Layer
        public var m_Layer_ShadowCast:Sprite = new Sprite();
        //Box2D
        public var m_Box2D_World:b2World;
        //光源の球
        public var m_LightBody:b2Body;
        //マウスで動かせる球
        public var m_MouseBallBody:b2Body;
        public var m_MouseJoint:b2MouseJoint;
        //境界線を描くためのGraphics
        public var m_LightShape:Shape = new Shape();
        public var m_LightGraphics:Graphics = m_LightShape.graphics;
        //光源の表示用Bitmap
        public var m_BitmapData_Light:BitmapData = new BitmapData(VIEW_W, VIEW_H, true, 0x00000000);
        //==Function==
        //Init
        public function GameMain(){
            //Layer
            //addChild(m_Layer_ShadowCast);
            //Box2D
            //考慮する領域
            var worldAABB:b2AABB = new b2AABB();
            worldAABB.lowerBound.Set(IMAGE_to_PHYS(-BOX2D_RANGE_OFFSET), IMAGE_to_PHYS(-BOX2D_RANGE_OFFSET));
            worldAABB.upperBound.Set(IMAGE_to_PHYS(VIEW_W+BOX2D_RANGE_OFFSET), IMAGE_to_PHYS(VIEW_H+BOX2D_RANGE_OFFSET));
            //重力ベクトル
            var gravity:b2Vec2 = new b2Vec2(0.0, GRAVITY);
            //Sleep
            var useSleep:Boolean = true;
            //物理world
            m_Box2D_World = new b2World(worldAABB, gravity, useSleep);
            //周囲
            //D
            CreateCollision_Box(
                VIEW_W/2,//X
                VIEW_H - 5,//Y
                VIEW_W,//W
                10,//H
                0,//Rot
                true//IsFix
            );
            //U
            CreateCollision_Box(
                VIEW_W/2,//X
                5,//Y
                VIEW_W,//W
                10,//H
                0,//Rot
                true//IsFix
            );
            //L
            CreateCollision_Box(
                5,//X
                VIEW_H/2,//Y
                10,//W
                VIEW_H,//H
                0,//Rot
                true//IsFix
            );
            //R
            CreateCollision_Box(
                VIEW_W - 5,//X
                VIEW_H/2,//Y
                10,//W
                VIEW_H,//H
                0,//Rot
                true//IsFix
            );
            //段差
            CreateCollision_Box(
                VIEW_W*1/4,//X
                VIEW_H*3/4,//Y
                VIEW_W/4,//W
                20//H
            );
            CreateCollision_Box(
                VIEW_W*3/4,//X
                VIEW_H*3/4,//Y
                VIEW_W/4,//W
                20//H
            );
            CreateCollision_Box(
                VIEW_W*3/4,//X
                VIEW_H*1/4,//Y
                VIEW_W/4,//W
                20//H
            );
            //Light
            CreateCollision_LightSphere(
                VIEW_W/2, VIEW_H/2, 6
            );
            //Mouse
            CreateCollision_MouseSphere(
                10
            );
            //m_BitmapData_Light
            addChild(canvas); //canvasBmd instead of m_BitmapData_Light
            //addChild(m_LightShape);
            //Update
            addEventListener(Event.ENTER_FRAME, Update);
        }
        //Create : Collision : Box
        public function CreateCollision_Box(in_X:int, in_Y:int, in_W:int, in_H:int, in_Rot:Number = 0, in_FixFlag:Boolean = false):void{
            //Image
            var sprite:Sprite;
            sprite = new Sprite();
            sprite.graphics.beginFill(0xDDDDDD);
            sprite.graphics.drawRect(-in_W/2, -in_H/2, in_W, in_H);
            sprite.graphics.endFill();
            m_Layer_ShadowCast.addChild(sprite);
            //Shape Def
            var shapeDef:b2PolygonDef;
            shapeDef = new b2PolygonDef();
            shapeDef.SetAsBox(IMAGE_to_PHYS(in_W/2), IMAGE_to_PHYS(in_H/2));
            if(in_FixFlag){
                shapeDef.density = 0;//Fix
                shapeDef.restitution = 1.5;
            }else{
                shapeDef.density = 1;//tekitou
            }
            //Body Def
            var bodyDef:b2BodyDef;
            bodyDef = new b2BodyDef();
            bodyDef.position.Set(IMAGE_to_PHYS(in_X), IMAGE_to_PHYS(in_Y));
            bodyDef.angle = in_Rot;
            //Body
            var body:b2Body;
            body = m_Box2D_World.CreateBody(bodyDef);
            body.CreateShape(shapeDef);
            body.SetMassFromShapes();
            body.m_userData = sprite;
        }
        //Create : Collision : Sphere for Light
        public function CreateCollision_LightSphere(in_X:int, in_Y:int, in_R:int, in_FixFlag:Boolean = false):void{
            //Image (light source) - moved to Update_Light
            // var sprite:Sprite;
            // sprite = new Sprite();
            // sprite.graphics.beginFill(0xFFFF88);
            // sprite.graphics.drawCircle(0,0, in_R);
            // sprite.graphics.endFill();
            // sprite.filters = [new GlowFilter(0xBBBB00)];
            // addChild(sprite);
            //Shape Def
            var shapeDef:b2CircleDef;
            shapeDef = new b2CircleDef();
            shapeDef.radius = IMAGE_to_PHYS(in_R);
            shapeDef.restitution = 1.3;
            if(in_FixFlag){
                shapeDef.density = 0;//Fix
            }else{
                shapeDef.density = 1;//tekitou
            }
            //Body Def
            var bodyDef:b2BodyDef;
            bodyDef = new b2BodyDef();
            bodyDef.position.Set(IMAGE_to_PHYS(in_X), IMAGE_to_PHYS(in_Y));
            //Body
            var body:b2Body;
            body = m_Box2D_World.CreateBody(bodyDef);
            body.CreateShape(shapeDef);
            body.SetMassFromShapes();
            // body.m_userData = sprite;
            m_LightBody = body;
        }
        //Create : Collision : Sphere for Mouse
        public function CreateCollision_MouseSphere(in_R:int):void{
            //Image
            var sprite:Sprite;
            sprite = new Sprite();
            sprite.graphics.beginFill(0xDDDDDD);
            sprite.graphics.drawCircle(0,0, in_R);
            sprite.graphics.endFill();
            m_Layer_ShadowCast.addChild(sprite);
            //Shape Def
            var shapeDef:b2CircleDef;
            shapeDef = new b2CircleDef();
            shapeDef.radius = IMAGE_to_PHYS(in_R);
            shapeDef.density = 1;//tekitou
            //Body Def
            var bodyDef:b2BodyDef;
            bodyDef = new b2BodyDef();
            bodyDef.position.Set(IMAGE_to_PHYS(30), IMAGE_to_PHYS(30));
            //Body
            var body:b2Body;
            body = m_Box2D_World.CreateBody(bodyDef);
            body.CreateShape(shapeDef);
            body.SetMassFromShapes();
            body.m_userData = sprite;
            //Joint
            var mjd:b2MouseJointDef = new b2MouseJointDef();
            mjd.body1 = m_Box2D_World.GetGroundBody();
            mjd.body2 = body;
            //mjd.target.Set(IMAGE_to_PHYS(mouseX), IMAGE_to_PHYS(mouseY));
            mjd.target.Set(bodyDef.position.x, bodyDef.position.y);
            mjd.maxForce = 1000.0 * body.GetMass();
            mjd.timeStep = 1.0/30.0;
            m_MouseJoint = m_Box2D_World.CreateJoint(mjd) as b2MouseJoint;
        }
        //Update
        public function Update(e:Event=null):void{
            //今回進める時間
            var DeltaTime:Number = 1.0/30.0;
            //物理まわりの更新
            Update_Phys(DeltaTime);
            //光源(視界)処理
            Update_Light();
        }
        //物理まわりの更新
        public function Update_Phys(in_DeltaTime:Number):void{
            //マウスのところに移動
            m_MouseJoint.SetTarget(new b2Vec2(IMAGE_to_PHYS(mouseX), IMAGE_to_PHYS(mouseY)));
            //物理エンジンをDeltaTimeだけ進める
            m_Box2D_World.Step(in_DeltaTime, 10);
            //
            for (var b:b2Body = m_Box2D_World.m_bodyList; b; b = b.m_next) {
                //画像との同期
                if(b.m_userData != null){
                    var sprite:Sprite = b.m_userData as Sprite;
                    sprite.x = PHYS_to_IMAGE(b.GetPosition().x);
                    sprite.y = PHYS_to_IMAGE(b.GetPosition().y);
                    //b.m_userData.m_VX = PHYS_to_IMAGE(b.m_linearVelocity.x);
                    //b.m_userData.m_VY = PHYS_to_IMAGE(b.m_linearVelocity.y);
                    sprite.rotation = b.GetAngle() * 180/Math.PI;
                }
                //擬似摩擦
                const Ratio:Number = 0.9;//本当はDeltaTime依存の値にした方が良い
                b.GetLinearVelocity().x *= Ratio;
                b.GetLinearVelocity().y *= Ratio;
                b.SetAngularVelocity(b.GetAngularVelocity() * Ratio);
            }
        }
        //光源(視界)処理
        private const CT_FORCE_DARK:ColorTransform = new ColorTransform(0,0,0,1, 0,0,0,-0);
        private const GS:Number = 50; // gradient size
        public function Update_Light():void{
            //初期化
            m_LightGraphics.clear();
            m_LightGraphics.lineStyle();//(1,0x00FFFF,1.0);
            // light source coords
            var SrcX:Number = PHYS_to_IMAGE(m_LightBody.GetPosition().x);
            var SrcY:Number = PHYS_to_IMAGE(m_LightBody.GetPosition().y);
            //=実際の光の範囲の描画=
            //まずはリセット
            m_BitmapData_Light.fillRect(m_BitmapData_Light.rect, 0xff010203);
            //境界線をDraw
            mtx.createGradientBox(GS, GS, 0, SrcX-GS/2, SrcY-GS/2);
            m_LightGraphics.beginGradientFill(
                "radial",[16777215,16514912,16762441,16499790,5877756],[1,1,0.92,0.43,0],[10,20,48,146,253],
                mtx, "pad","rgb",0);
            m_LightGraphics.drawRect(int(SrcX-GS/2),int(SrcY-GS/2),GS,GS); // floats don't work well with blendmode == "add"
            m_BitmapData_Light.draw(m_LightShape, null, new ColorTransform(16/255, 9/255, 4/255), "add");//, null, CT_FORCE_DARK);
            //物体もDraw
            m_BitmapData_Light.draw(m_Layer_ShadowCast, null, CT_FORCE_DARK);
            canvas.bitmapData = process(m_BitmapData_Light, 0.5 - SrcX/SIZE, 0.5 - SrcY/SIZE);
            //m_BitmapData_Light.floodFill(SrcX, SrcY, 0x80FFFFFF);
        }

        private static const SIZE:int = 465;
        private var canvasBmd:BitmapData = new BitmapData(SIZE, SIZE, true, 0);
        private var canvas:Bitmap = new Bitmap(canvasBmd);
        private var dst:BitmapData = new BitmapData(SIZE, SIZE, true, 0);
        private var mtx:Matrix = new Matrix;
        private var blur:BlurFilter = new BlurFilter;
        private function process(src:BitmapData, cx:Number, cy:Number):BitmapData {
            var dst:BitmapData = this.dst;
            var cnt:int = 6;
            mtx.identity();
            mtx.translate(-SIZE * 1/512, -SIZE * 1/512);
            mtx.translate(cx*SIZE/256, cy*SIZE/256);
            mtx.scale(257/256, 257/256);
            var tmp:BitmapData;
            src.lock(); dst.lock();
            while(cnt--) {
                mtx.concat(mtx);
                dst.copyPixels(src, src.rect, src.rect.topLeft);
                dst.draw(src, mtx, null, "add");
                dst.applyFilter(dst, dst.rect, dst.rect.topLeft, blur);
                tmp = src;
                src = dst;
                dst = tmp;
            }
            src.unlock(); dst.unlock();
            return src;
        }
    }
}