Box2D試作:間接Drag
範囲内にあるものをジョイントしてドラッグするテスト
/**
* 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/ey0V
*/
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="0x000000")]
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;
//効果範囲
static public const EFFECT_RANGE:Number = VIEW_W/8;
//==Var==
//Box2D
public var m_Box2D_World:b2World;
//マウスで動かせる球
public var m_MouseBallBody:b2Body;
public var m_MouseJoint:b2MouseJoint;
//エフェクト用Graphics
public var m_EffectGraphics:Graphics;
//マウス用フラグ
public var m_MouseDown_Now:Boolean = false;
public var m_MouseDown_Old:Boolean = false;
//==Function==
//Init
public function GameMain(){
//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);
}
//Effect
{
var eff_sprite:Sprite = new Sprite();
m_EffectGraphics = eff_sprite.graphics;
addChild(eff_sprite);
}
//Mouse
{
CreateCollision_MouseSphere(
10
);
}
//周囲
{
//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
);
}
//ブロック
{
for(var x:int = 1; x < 8; x++){
for(var y:int = 1; y < 8; y++){
CreateCollision_Box(
VIEW_W*x/8,//X
VIEW_H*y/8,//Y
VIEW_W/16,//W
VIEW_W/16//H
);
}
}
}
//Update
{
addEventListener(Event.ENTER_FRAME, Update);
}
//Mouse
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:Event):void{m_MouseDown_Now = true;});
stage.addEventListener(MouseEvent.MOUSE_UP, function(e:Event):void{m_MouseDown_Now = false;});
}
}
//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();
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
}else{
shapeDef.density = 0.01;//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 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();
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(VIEW_W/2), IMAGE_to_PHYS(VIEW_H/2));
}
//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 = 300.0 * body.GetMass();
mjd.timeStep = 1.0/30.0;
m_MouseJoint = m_Box2D_World.CreateJoint(mjd) as b2MouseJoint;
}
m_MouseBallBody = body;
}
//Update
public function Update(e:Event=null):void{
//今回進める時間
var DeltaTime:Number = 1.0/30.0;
//物理まわりの更新
Update_Phys(DeltaTime);
//リンクまわりの更新
Update_Link();
}
//物理まわりの更新
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.95;//本当はDeltaTime依存の値にした方が良い
b.GetLinearVelocity().x *= Ratio;
b.GetLinearVelocity().y *= Ratio;
b.SetAngularVelocity(b.GetAngularVelocity() * Ratio);
}
}
}
//リンクわりの更新
public function Update_Link():void{
var j:b2Joint;
var BallX:Number = PHYS_to_IMAGE(m_MouseBallBody.GetPosition().x);
var BallY:Number = PHYS_to_IMAGE(m_MouseBallBody.GetPosition().y);
if(m_MouseDown_Now){
//まだリンクしていなければリンク処理
if(m_MouseDown_Old != m_MouseDown_Now){
for(var b:b2Body = m_Box2D_World.m_bodyList; b; b = b.m_next){
if(b == m_MouseBallBody){continue;}//自分自身はリンクしない
if(b.IsStatic()){continue;}//固定されているものはリンクしない
var GapX:Number = PHYS_to_IMAGE(b.GetPosition().x - m_MouseBallBody.GetPosition().x);
var GapY:Number = PHYS_to_IMAGE(b.GetPosition().y - m_MouseBallBody.GetPosition().y);
var Len:Number = Math.sqrt(GapX*GapX + GapY*GapY);
if(Len <= EFFECT_RANGE){
var jointDef:b2DistanceJointDef = new b2DistanceJointDef();
jointDef.Initialize(b, m_MouseBallBody, b.GetWorldCenter() , m_MouseBallBody.GetWorldCenter());
m_Box2D_World.CreateJoint(jointDef);
}
}
}
//リンクの可視化
{
m_EffectGraphics.clear();
m_EffectGraphics.lineStyle(3, 0x00FFFF, 1.0);
for(j = m_Box2D_World.GetJointList(); j; j = j.m_next){
if(j == m_MouseJoint){continue;}//マウスとの接続は可視化しない
m_EffectGraphics.moveTo(PHYS_to_IMAGE(j.GetAnchor1().x), PHYS_to_IMAGE(j.GetAnchor1().y));
m_EffectGraphics.lineTo(PHYS_to_IMAGE(j.GetAnchor2().x), PHYS_to_IMAGE(j.GetAnchor2().y));
}
}
}else{
//以前にリンクしていたなら切断
if(m_MouseDown_Old != m_MouseDown_Now){
for(j = m_Box2D_World.GetJointList(); j; ){
if(j == m_MouseJoint){j = j.m_next; continue;}
var jj:b2Joint = j.m_next;
m_Box2D_World.DestroyJoint(j);
j = jj;
}
}
//効果範囲の可視化
{
m_EffectGraphics.clear();
m_EffectGraphics.lineStyle(3, 0x00FFFF, 1.0);
m_EffectGraphics.drawCircle(BallX,BallY, EFFECT_RANGE);
}
}
m_MouseDown_Old = m_MouseDown_Now;
}
}
}