Box2Dの練習001 マウスでつかむ(FULL SCREENボタンに対応)
FULL SCREENボタンに対応してみた
* 床オブジェクトが画面サイズに合わせて伸縮・位置変わります
* リサイズハンドラで処理をしています。
* 「CreateShape」で床オブジェクトのサイズを変更していますが、これで良いかは疑問・・・
* Createだと新たにオブジェクトを作っている・・・わけではないのでしょうか??
/**
* Copyright fumix ( http://wonderfl.net/user/fumix )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/qE8e
*/
/**
* FULL SCREENボタンに対応してみた
* 床オブジェクトが画面サイズに合わせて伸縮・位置変わります
* リサイズハンドラで処理をしています。
* 「CreateShape」で床オブジェクトのサイズを変更していますが、これで良いかは疑問・・・
* Createだと新たにオブジェクトを作っている・・・わけではないのでしょうか??
**/
package {
import flash.events.TimerEvent;
import flash.utils.Timer;
import Box2D.Collision.Shapes.b2CircleDef;
import Box2D.Collision.Shapes.b2Shape;
import Box2D.Dynamics.Joints.b2MouseJoint;
import Box2D.Dynamics.Joints.b2MouseJointDef;
import flash.events.MouseEvent;
import Box2D.Dynamics.b2DebugDraw;
import Box2D.Collision.Shapes.b2PolygonDef;
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2BodyDef;
import Box2D.Common.Math.b2Vec2;
import Box2D.Dynamics.b2World;
import Box2D.Collision.b2AABB;
import flash.events.Event;
import flash.display.MovieClip;
/**
* @author fumix
*/
[SWF(width=465, height=465, backgroundColor=0x999999)]
public class main extends MovieClip {
private var _iterations : int;
private var _timeStep : Number;
private var _physScale : Number;
private var _world : b2World;
//マウスジョイント
var _mouseJoint : b2MouseJoint;
/**
* コンストラクタ
*/
public function main() : void {
if (stage) onInit();
else addEventListener(Event.ADDED_TO_STAGE, onInit);
}
/**
* 初期処理
*/
private function onInit(event : Event = null) : void {
removeEventListener(Event.ADDED_TO_STAGE, onInit);
//ステージ設定
stage.align = "TL";
stage.scaleMode = "noScale";
_iterations = 10; //制度
_timeStep = 1.0 / 24.0; //実行速度
_physScale = 30; //表示倍率
//ワールドの定義
var worldAABB : b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-100.0, -100.0);
worldAABB.upperBound.Set(100.0, 100.0);
//重力の定義
var gravity : b2Vec2 = new b2Vec2(0.0, 10.0);
//スリープのONOFF
var doSleep : Boolean = true;
//ワールドのインスタンス作成
_world = new b2World(worldAABB, gravity, doSleep);
//----------------------------------
// 床を作る
//----------------------------------
// 物体の定義を作る
var wallBdDef : b2BodyDef = new b2BodyDef();
var w : int = stage.stageWidth;
var h : int = stage.stageHeight;
wallBdDef.position.Set(w / 2 / _physScale, (h - 20) / _physScale);
wallBdDef.angle = 0; //Math.PI / 24;
// 形の定義を作る
var wallShapeDef : b2PolygonDef = new b2PolygonDef();
wallShapeDef.SetAsBox(w / _physScale, 10 / _physScale);
wallShapeDef.friction = 2; //摩擦力
wallShapeDef.density = 0; //密度
wallShapeDef.restitution = 0.4; //反発力
// 物体を作る
var wallBd:b2Body = _world.CreateBody(wallBdDef);
wallBd.m_userData = new Object();
wallBd.m_userData.id = 'wall';
// 形を物体に追加する
wallBd.CreateShape(wallShapeDef);
//----------------------------------
// 物体を10表示
//----------------------------------
for(var i : int = 0;i < 10;i++) {
var dx : Number = (stage.stageWidth / 10 * i);
createObject(dx);
}
//----------------------------------
// DebugDraw を有効にする
//----------------------------------
var debugDraw : b2DebugDraw = new b2DebugDraw();
debugDraw.m_sprite = this;
debugDraw.m_drawScale = _physScale;
debugDraw.m_fillAlpha = 0.8;
debugDraw.m_lineThickness = 1;
debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit;
_world.SetDebugDraw(debugDraw);
//毎フレームの処理
stage.addEventListener(Event.ENTER_FRAME, EnterFrame);
//タイマーイベント(5秒毎に物体を降らせる)
var timerObj:Timer = new Timer(5000);
timerObj.addEventListener(TimerEvent.TIMER, onTimerHandler);
timerObj.start();
//イベントハンドラ
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
//リサイズ処理
stage.addEventListener(Event.RESIZE, resizeHandler);
}
//リサイズ処理
private function resizeHandler(event : Event) : void {
//床の大きさ・位置を変更
for (var b2body : b2Body = _world.m_bodyList;b2body; b2body = b2body.m_next) {
if (b2body.m_userData) {
if (b2body.m_userData.id == "wall") {
var wallShapeDef : b2PolygonDef = new b2PolygonDef();
wallShapeDef.SetAsBox(stage.stageWidth / _physScale, 10 / _physScale);
b2body.CreateShape(wallShapeDef);
b2body.SetXForm(new b2Vec2(b2body.GetPosition().x, stage.stageHeight / _physScale), 0);
}
}
}
}
private function onTimerHandler(event : TimerEvent) : void {
var dx : Number = stage.stageWidth*Math.random();
createObject(dx);
}
private function mouseMoveHandler(event : MouseEvent) : void {
// mouseJointがnullでないときだけ処理を実行する
if (_mouseJoint) {
var p2 : b2Vec2 = new b2Vec2(event.stageX / _physScale, event.stageY / _physScale);
_mouseJoint.SetTarget(p2);
}
}
private function mouseDownHandler(event : MouseEvent) : void {
// マウスボタンを押したとき、該当のオブジェクト上にマウスカーソルがあるかを判定
var body : b2Body = GetBodyAtMouse(event.stageX, event.stageY);
//mouseJoint = b2MouseJoint(world.CreateJoint(mouseJointDef));
if (body) {
var md : b2MouseJointDef = new b2MouseJointDef();
md.body1 = _world.m_groundBody;
md.body2 = body;
md.target.Set(event.stageX / _physScale, event.stageY / _physScale);
md.maxForce = 500.0 * body.m_mass;
md.timeStep = _timeStep;
_mouseJoint = _world.CreateJoint(md) as b2MouseJoint;
body.WakeUp();
}
}
private function mouseUpHandler(event : MouseEvent) : void {
// マウスボタンが離されたら,マウスボタンを切り離す
if(_mouseJoint){
_world.DestroyJoint(_mouseJoint);
_mouseJoint = null;
}
}
//該当オブジェクトがあるかの判定
private function GetBodyAtMouse(stageX : Number, stageY : Number) : b2Body {
// Make a small box.
var mousePVec : b2Vec2 = new b2Vec2();
var mouseXWorldPhys : Number = stageX / _physScale;
var mouseYWorldPhys : Number = stageY / _physScale;
mousePVec.Set(mouseXWorldPhys, mouseYWorldPhys);
var aabb : b2AABB = new b2AABB();
aabb.lowerBound.Set(mouseXWorldPhys - 0.001, mouseYWorldPhys - 0.001);
aabb.upperBound.Set(mouseXWorldPhys + 0.001, mouseYWorldPhys + 0.001);
// Query the world for overlapping shapes.
var k_maxCount : int = 10;
var shapes : Array = new Array();
var count : int = _world.Query(aabb, shapes, k_maxCount);
var body : b2Body = null;
for (var i : int = 0;i < count; ++i) {
if (shapes[i].m_body.IsStatic() == false) {
var tShape : b2Shape = shapes[i] as b2Shape;
var inside : Boolean = tShape.TestPoint(tShape.m_body.GetXForm(), mousePVec);
if (inside) {
body = tShape.m_body;
break;
}
}
}
return body;
}
private function EnterFrame(event : Event) : void {
_world.Step(_timeStep, _iterations);
//画面外に行ったオブジェクトを削除する
var marginX : Number = 100;
var marginY : Number = 100;
for (var b : b2Body = _world.GetBodyList();b; b = b.GetNext()) {
var xPos : Number = b.GetWorldCenter().x * _physScale;
var yPos : Number = b.GetWorldCenter().y * _physScale;
if (!b.m_userData && (xPos > stage.stageWidth + marginX || xPos < -marginX || yPos > stage.stageHeight + marginY)) {
//マウスジョイントがある場合
if(_mouseJoint) {
if(_mouseJoint.m_body2 == b) {
_world.DestroyJoint(_mouseJoint);
_mouseJoint = null;
}
}
_world.DestroyBody(b);
}
}
}
// 物体を1個作る
private function createObject(mx : Number = 0,my : Number = 0) : void {
// 物体の定義を作る
var objBdDef : b2BodyDef = new b2BodyDef();
objBdDef.position.Set(mx / _physScale, my / _physScale);
objBdDef.angle = Math.PI / 2 * Math.random();
// 形の定義を作る
var shapeDef : b2PolygonDef = new b2PolygonDef();
shapeDef.SetAsBox(30 / _physScale, 30 / _physScale);
shapeDef.density = 1;
shapeDef.restitution = 0.2;
shapeDef.friction = 0.1;
//サークルを作る
var circleDef:b2CircleDef = new b2CircleDef();
circleDef.radius = (20*Math.random()+10) / _physScale;
circleDef.density = 1;
circleDef.restitution = 0.4;
circleDef.friction = 1;
// 物体を作る
var objBd : b2Body = _world.CreateBody(objBdDef);
// 形を物体に追加する
//objBd.CreateShape(shapeDef);
objBd.CreateShape(circleDef);
// 重さ・重心を計算する
objBd.SetMassFromShapes();
}
private function addCircle( ax:Number, ay:Number ):void
{
//任意の位置にCircleオブジェクト追加してく
//手順 ShapeなDef→BodyなDef→worldで実体をつくる感じ
var s:b2CircleDef = new b2CircleDef();
s.density = 1;
s.restitution = 0.2;
s.radius = 0.2;
var b:b2BodyDef = new b2BodyDef();
b.position.Set( ax, ay );
var bb:b2Body = _world.CreateBody( b );
var bs:b2Shape = bb.CreateShape( s );
bb.SetMassFromShapes();
//Shapeはあとでいじるので配列にいれとく
bs.m_userData = Number(0);
//circles.push( b2CircleShape(bs) );
}
}
}