[Box2D] ピタゴラスイッチみたいなことがしたかった 反省はしている
初めてさわった滑車ジョイントがわからなすぎて、悪戦苦闘でした
ときどきボールが壁をすり抜けます
どきどき通路がボールで詰まります
[ 機能 ]
・スライダーを移動させるとボールの量が変えられます
・
[ 参考にさせていただいたサイト ]
http://plug.heteml.jp/motulog/2008/10/box2dflashas3201-2.html#more
http://hokori.net/category/note/
http://www.at-sonic.com/blog/index.php?page=5
http://www.kyucon.com/doc/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.html#methodSummary
/*
初めてさわった滑車ジョイントがわからなすぎて、悪戦苦闘でした
ときどきボールが壁をすり抜けます
どきどき通路がボールで詰まります
[ 機能 ]
・スライダーを移動させるとボールの量が変えられます
・
[ 参考にさせていただいたサイト ]
http://plug.heteml.jp/motulog/2008/10/box2dflashas3201-2.html#more
http://hokori.net/category/note/
http://www.at-sonic.com/blog/index.php?page=5
http://www.kyucon.com/doc/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.html#methodSummary
*/
package {
import Box2D.Collision.b2AABB;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.b2Vec2;
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2BodyDef;
import Box2D.Dynamics.b2DebugDraw;
import Box2D.Dynamics.b2World;
import Box2D.Dynamics.Joints.*;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.utils.getTimer;
public class windmill extends Sprite {
private var world:b2World;
private const SCALE:int = 100;
private var m_sprite:Sprite;
private var colors:Array;
private var ADD_INTERVAL_TIME:int = 525;
private var myTimer:Timer;
public function windmill():void {
stage.quality = StageQuality.BEST;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
init();
}
private function init():void {
//物理エンジン初期化
createWorld();
//風車作成( 半径, x座標, y座標, 分割数(かごの数));
createWindmill( 40, 100, 80, 6);
//壁作成
createWall();
//滑車作成
createPulley();
//スライダー作成
createSlider();
//シミュレーションスタート
start();
}
//物理エンジン初期化
private function createWorld():void {
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-100.0, -100.0);
worldAABB.upperBound.Set(100.0, 100.0);
var doSleep:Boolean = true;
// 重力を定義する
var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);
// 世界のインスタンスを作成する
world = new b2World( worldAABB, gravity, doSleep );
m_sprite = new Sprite();
addChild(m_sprite);
debugMode();
}
//デバッグ
private function debugMode():void {
var debugDraw:b2DebugDraw = new b2DebugDraw();
debugDraw.m_sprite = this;
debugDraw.m_drawScale = SCALE; // 1mを100ピクセルにする
debugDraw.m_fillAlpha = 0.8; // 不透明度
debugDraw.m_lineThickness = 1; // 線の太さ
//debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit | b2DebugDraw.e_centerOfMassBit;
debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
world.SetDebugDraw(debugDraw);
}
//風車作成
private function createWindmill( radius:int, xpos:Number, ypos:Number, segment:int ):void {
//風車の車体?を作成
var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.position.Set( xpos/SCALE, ypos/SCALE);
bodyDef.angle = 0;
var cdef:b2CircleDef= new b2CircleDef();
cdef.radius = radius/SCALE; // 半径
cdef.density = 0.5; // 密度:0だと動かない
cdef.friction = 0.0; // 摩擦:大きいと滑りにくい
cdef.restitution = 1; // 反発:大きいと反発しにくい
// 物体を作る
var b2_Body:b2Body = world.CreateBody( bodyDef );
// 形を物体に追加する
b2_Body.CreateShape( cdef );
// 動く物体として作る
b2_Body.SetMassFromShapes();
//風車を回転させる基点を作成
var baseBodyDef:b2BodyDef = new b2BodyDef();
baseBodyDef.position.Set( xpos/SCALE, ypos/SCALE);
var bcdef:b2CircleDef = new b2CircleDef();
bcdef.radius = 0.1; // 半径
bcdef.density = 0.5; // 密度:0だと動かない
bcdef.friction = 0.0; // 摩擦:大きいと滑りにくい
bcdef.restitution = 1; // 反発:大きいと反発しにくい
// 物体を作る
var b2_BaseBody:b2Body = world.CreateBody( baseBodyDef );
// 形を物体に追加する
b2_BaseBody.CreateShape( bcdef );
// 風車とワールドを固定するジョイントの定義
var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
jointDef.enableLimit = false;
/*
jointDef.enableMotor = true;
jointDef.motorSpeed = 0;
jointDef.maxMotorTorque = 100000;
*/
var anchor:b2Vec2 = new b2Vec2( xpos/SCALE, ypos/SCALE);
//var anchor = new b2Vec2(1.98, 2.7);
jointDef.Initialize( b2_Body, b2_BaseBody, anchor );
//(rev_joint, rev_box, new b2Vec2(13, 6.5));
var revolute_joint : b2RevoluteJoint = world.CreateJoint( jointDef ) as b2RevoluteJoint;
//風車のかごを作成してジョイントで風車に固定する
for( var i:int=0; i < segment; i++){
var angle:Number = 360/segment*i;
var rad:Number = angle * Math.PI/180;
//trace( "angle : "+angle );
//trace( "rad : "+rad );
var x:Number = radius*Math.cos(rad)+xpos;
var y:Number = radius*Math.sin(rad)+ypos;
//trace("x : "+x);
//trace("y : "+y);
//trace("----------");
var boxBodyDef:b2BodyDef = new b2BodyDef();
boxBodyDef.position.Set(x/SCALE, y/SCALE);
//boxBodyDef.position.Set(0,0);
boxBodyDef.angle = rad;
// 物体を作る
var boxBody:b2Body = world.CreateBody( boxBodyDef );
var boxShapeDef:b2PolygonDef= new b2PolygonDef();
boxShapeDef.density = 6; // 密度
boxShapeDef.restitution = 0.01; // 反発係数
boxShapeDef.vertexCount = 4;
boxShapeDef.vertices[0].Set( 0.30, 0.00 );
boxShapeDef.vertices[1].Set( 0.30, 0.30 );
boxShapeDef.vertices[2].Set( 0.25, 0.30 );
boxShapeDef.vertices[3].Set( 0.25, 0.00 );
// 形を物体に追加する
boxBody.CreateShape( boxShapeDef );
/**/
// 定義を変更してもう1個の形を追加する
boxShapeDef.vertexCount = 4;
boxShapeDef.vertices[0].Set( 0.00, 0.00 );
boxShapeDef.vertices[1].Set( 0.30, 0.00 );
boxShapeDef.vertices[2].Set( 0.30, 0.07 );
boxShapeDef.vertices[3].Set( 0.00, 0.07 );
// 形を物体に追加する
boxBody.CreateShape( boxShapeDef );
//
boxBody.SetMassFromShapes();
// ジョイントの定義
var pinJointDef : b2RevoluteJointDef = new b2RevoluteJointDef();
// joint
pinJointDef.Initialize( boxBody, b2_Body, new b2Vec2(x/SCALE, y/SCALE));
//pinJointDef.collideConnected = true;
pinJointDef.enableLimit = true
pinJointDef.lowerAngle = 0*Math.PI/180;
pinJointDef.upperAngle = 0*Math.PI/180;
var distance_joint : b2RevoluteJoint = world.CreateJoint( pinJointDef ) as b2RevoluteJoint;
}
}
private function createBasket():void {
}
//壁作成
private function createWall():void {
var wxArr:Array = [ 173, 280, 225, 280, 352, stage.stageWidth, 385, 352, 385 ]; //x座標
var wyArr:Array = [ 240, 190, 352, 415, 360, 0, 395, 430, 460 ]; //y座標
var wwArr:Array = [ 100, 5, 5, 5, 150, 5, 150, 150, 150 ]; //幅
var whArr:Array = [ 5, 250, 225, 120, 5, stage.stageHeight*2, 5, 5, 5 ]; //高さ
var rArr:Array = [ 20, 0, 0, 0, 30, 0, -15, 15 , -15 ]; //角度(傾き)
/* make wall */
for (var i:int = 0; i < wxArr.length; i++) {
var wallBodyDef:b2BodyDef = new b2BodyDef();
wallBodyDef.position.Set(wxArr[i] /SCALE, wyArr[i] /SCALE);
var wallShapeDef:b2PolygonDef = new b2PolygonDef();
wallShapeDef.restitution = 0.01; // 反発係数
wallShapeDef.friction = 0.0;
wallShapeDef.SetAsOrientedBox( wwArr[i] / 2 / SCALE, whArr[i]/2 / SCALE, new b2Vec2(0,0), rArr[i]/180/Math.PI );
var wallBody:b2Body = world.CreateBody( wallBodyDef );
wallBody.CreateShape( wallShapeDef );
}
}
//滑車作成
private function createPulley():void {
var jd:b2PulleyJointDef = new b2PulleyJointDef();
//bodyDef
var bd1:b2BodyDef = new b2BodyDef();
bd1.position.Set(250 / SCALE, 200 / SCALE);
var bd2:b2BodyDef = new b2BodyDef();
bd2.position.Set(400 / SCALE, 250 / SCALE);
//body
var body1:b2Body = world.CreateBody( bd1);
//box
var box1:b2PolygonDef = new b2PolygonDef();
box1.density = 0.5; // 密度:0だと動かない
box1.friction = 0.5; // 摩擦:大きいと滑りにくい
box1.restitution = 0.1; // 反発:大きいと反発しにくい
/**/
box1.vertexCount = 4;
box1.vertices[0].Set( -0.25, 0.00 );
box1.vertices[1].Set( 0.25, 0.00 );
box1.vertices[2].Set( 0.25, 0.05 );
box1.vertices[3].Set( -0.25, 0.05 );
// 形を物体に追加する
body1.CreateShape( box1 );
/**/
box1.vertexCount = 4;
box1.vertices[0].Set( 0.20, 0.00 );
box1.vertices[1].Set( 0.25, 0.00 );
box1.vertices[2].Set( 0.25, 0.75 );
box1.vertices[3].Set( 0.20, 0.75 );
// 形を物体に追加する
body1.CreateShape( box1 );
box1.vertexCount = 4;
box1.vertices[0].Set( -0.20, 0.30 );
box1.vertices[1].Set( -0.20, 0.75 );
box1.vertices[2].Set( -0.25, 0.75 );
box1.vertices[3].Set( -0.25, 0.30 );
// 形を物体に追加する
body1.CreateShape( box1 );
/**/
box1.vertexCount = 4;
// 形を物体に追加する
box1.vertices[0].Set( 0.25, 0.95 );
box1.vertices[1].Set( 0.25, 1.05 );
box1.vertices[2].Set( -0.25, 0.80 );
box1.vertices[3].Set( -0.25, 0.70 );
body1.CreateShape( box1 );
box1.vertexCount = 4;
box1.vertices[0].Set( -0.25, 0.00 );
box1.vertices[1].Set( -0.25, -0.50 );
box1.vertices[2].Set( -0.20, -0.50 );
box1.vertices[3].Set( -0.20, 0.00 );
// 形を物体に追加する
body1.CreateShape( box1 );
body1.SetMassFromShapes();
//同じ質量のボックスでないと釣り合いが取れないっぽい…?
//body
var body2:b2Body = world.CreateBody( bd2);
//box1よりすこしだけ密度を上げる→重くする
//box
var box2:b2PolygonDef = new b2PolygonDef();
box2.density = 0.6; // 密度:0だと動かない
box2.friction = 0.5; // 摩擦:大きいと滑りにくい
box2.restitution = 0.1; // 反発:大きいと反発しにくい
// 形を物体に追加する
box2.SetAsBox(20 / SCALE, 20 / SCALE);
// 形を物体に追加する
body2.CreateShape( box2 );
body2.SetMassFromShapes();
//joint
var ground1:b2Vec2 = new b2Vec2(250 /SCALE, 10 /SCALE);
var ground2:b2Vec2 = new b2Vec2(400 /SCALE, 10 /SCALE);
var anchor1:b2Vec2 = bd1.position;
var anchor2:b2Vec2 = bd2.position;
var ratio:Number = 1;
jd.Initialize(body1, body2, ground1, ground2, anchor1, anchor2, ratio);
world.CreateJoint(jd);
}
//ボール追加
private function addBall(e:Event):void{
var circleDef:b2CircleDef = new b2CircleDef();
var crad:Number = 0.075;
//var crad = 0.030 + Math.random()/10;
//trace(crad);
//circleDef.radius = Math.random()/10+0.00075;
circleDef.radius = crad;
circleDef.density = 5.0;
circleDef.friction = 0.5;
circleDef.restitution = 0.5;
var circleBD:b2BodyDef = new b2BodyDef();
//circleBD.position.Set(1.8, 0);
circleBD.position.Set(0.35, 0);
//circleBD.position.Set(1.7, 1.7);
// 実際の円を生成
var sp:Sprite = new Sprite;
sp.graphics.beginFill( getColor(), 0.8);
sp.graphics.drawCircle(0, 0, 30);
sp.graphics.endFill();
//一時的に画面外へ
sp.x = -crad*SCALE*2;
sp.y = -crad*SCALE*2;
// 円を保存
circleBD.userData = sp;
circleBD.userData.width = crad*SCALE*2;
circleBD.userData.height = crad*SCALE*2;
m_sprite.addChild(circleBD.userData);
var circleBody:b2Body = world.CreateBody( circleBD );
circleBody.CreateShape( circleDef );
circleBody.SetMassFromShapes();
}//end of function
//配列に登録したランダムな色を返す
private function getColor():Number {
var colors:Array = [ 0xdffe24, 0x84d90a, 0x2a95bf, 0xf2b910, 0xff368c, 0x6cbace];
return colors[ Math.floor(Math.random()*colors.length) ];
}//end of function
//シミュレーションスタート
private function start():void {
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
myTimer = new Timer(ADD_INTERVAL_TIME, 0);
myTimer.addEventListener(TimerEvent.TIMER, addBall);
myTimer.start();
}//end of function
private function enterFrameHandler(event:Event):void {
// 物理シミュレーションを進める
world.Step(1 / 24, 10);
if (world == null) {
return;
}
for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next){
/**/
if (bb.m_userData is Sprite){
bb.m_userData.x = bb.GetPosition().x * SCALE;
bb.m_userData.y = bb.GetPosition().y * SCALE;
bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI);
}
//trace(bb.GetPosition().y*SCALE);
if( bb.GetPosition().y*SCALE > stage.stageHeight ){
//trace("delete : "+bb);
world.DestroyBody( bb );
m_sprite.removeChild( bb.m_userData );
}
}
//trace("-----");
}
/*------スライダー関係
*/
private var bar:Sprite = new Sprite;
private var point:Sprite = new Sprite;
private function createSlider():void {
bar.graphics.beginFill( 0xcccccc, 1.0 );
bar.graphics.drawRect( 0, 0, 150, 5 );
bar.graphics.endFill();
point.graphics.beginFill( 0xFF0000, 1.0);
point.graphics.drawRect(0, 0, 10, 10);
point.graphics.endFill();
bar.addChild( point );
addChild( bar );
bar.x = 10;
bar.y = 400;
point.x = bar.width/2 - point.width/2;
point.y = -2;
point.buttonMode = true;
point.addEventListener( MouseEvent.MOUSE_DOWN, startMove );
}
private function startMove(e:Event):void {
stage.addEventListener( MouseEvent.MOUSE_UP, stopMove );
stage.addEventListener( MouseEvent.MOUSE_UP, updateIntervalTime );
point.startDrag( true,new Rectangle( 0, -2, bar.width - point.width,0) );
point.alpha = 0.8;
point.addEventListener( MouseEvent.MOUSE_MOVE, updateIntervalTime );
}
private function stopMove( e:Event ):void {
point.stopDrag();
point.alpha = 1.0;
}
private function updateIntervalTime( e:Event ):void {
var def:Number = point.x - bar.width/2;
ADD_INTERVAL_TIME = 525 + def*6;
myTimer.reset();
myTimer.removeEventListener(TimerEvent.TIMER, addBall);
myTimer = new Timer(ADD_INTERVAL_TIME, 0);
myTimer.addEventListener(TimerEvent.TIMER, addBall);
myTimer.start();
//trace(ADD_INTERVAL_TIME);
}
}
}