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;
}
}
}