物理エンジンライブラリ Box2DFlashAS3 ジョイント1(回転ジョイント・距離ジョイント)

ジョイントは、物体と物体を繋げて動かしたりもできる機能。
回転・距離・直動・滑車・歯車・マウスの6種類があります。

ここでは、回転ジョイントと距離ジョイントについてのメモ。

回転ジョイント(RevoluteJoint)

  • 物体と物体をピンで繋げるようなジョイント。
  • ピンを中心にくるくる回る。
  • モーターを使って回すことができる。
  • 回る角度の制限もできる。

使い方

  1. 繋げる2つの物体(b2Body)を指定
  2. 繋げる場所(座標)(b2Vec2)を1ヶ所指定
  3. ジョイントの性質(b2RevoluteJointDef)を設定(モーター使用・角度制限等)/li>
  4. ジョイントの初期化→ジョイント登録

距離ジョイント(DistanceJoint)

  • 物体と物体をロープで繋げるようなジョイント。
  • ロープに引っ張られながらそれぞれ勝手に動く。
  • 繋ぐ場所が2箇所あるのが、回転ジョイントと違う。

使い方

  1. 繋げる2つの物体(b2Body)を指定
  2. 繋げる場所(座標)(b2Vec2)を2ヶ所指定
  3. ジョイントの性質(b2DistanceJointDef)を設定(振動数?均衡等??ここの設定はわからないです...。)/li>
  4. ジョイントの初期化→ジョイント登録

サンプルコード

実行結果(きのこの谷)
きのこの谷

※Box2Dのまとめたクラス(Box2DBase)を作って、基本クラスで使ってます。ソースは物理エンジンライブラリ Box2DFlashAS3(基本)にあります。

Actionscript:
  1. public class StudyB2Joint1 extends B2Base
  2. {
  3.     private var m_screen_width:int = 600;
  4.     private var m_screen_height:int = 500;
  5.    
  6.     //ぐるぐるきのこ
  7.     private var m_b2_guru_kinoko1:b2Body;
  8.     private var m_b2_guru_kinoko2:b2Body;
  9.     private var m_b2_guru_kinoko3:b2Body;
  10.     private var m_b2_guru_kinoko4:b2Body;
  11.    
  12.     //ゆらゆら棒
  13.     private var m_b2_yura_bar:b2Body;
  14.     private var m_b2_yura_kinoko1:b2Body;
  15.     private var m_b2_yura_kinoko2:b2Body;
  16.    
  17.     //表示用のMCを入れる
  18.     private var m_display_blocks:Sprite;
  19.    
  20.     //落ちてくるきのこ発生装置
  21.     private var m_kinokoL:Sprite;
  22.     private var m_kinokoS:Sprite;
  23.    
  24.     public function StudyB2Joint1() : void{
  25.        
  26.         super(24, 10, 10);
  27.        
  28.         //表示用設定
  29.         this.m_display_blocks = new Sprite;
  30.         this.addChild(m_display_blocks);
  31.  
  32.         this.makeGake();    //ガケ作成
  33.  
  34.         //橋(距離ジョイント)
  35.         this.makeBridge();
  36.  
  37.         //ぐるぐるきのこ(回転ジョイント+距離ジョイント)
  38.         this.makeGuruguruKinoko()
  39.  
  40.         //ゆらゆら棒(回転ジョイント+距離ジョイント)
  41.         this.makeYurayuraBar();     
  42.        
  43.         this.initKinokoS()//小さいきのこ
  44.         this.initKinokoL()//大きいきのこ
  45.        
  46.         //this.setDebugDraw();
  47.                    
  48.         this.addEventListener(Event.ENTER_FRAME, this.update, false, 0, true);
  49.     }
  50.    
  51.     //ガケ作成
  52.     private function makeGake():void {
  53.        
  54.         this.makeB2BodyBox(120, 120, 60, 440, 0, 0, 0.5, 0.5);
  55.         this.makeB2BodyBox(120, 120, 540, 440, 0, 0, 0.5, 0.5);
  56.    
  57.     }
  58.  
  59.     //橋(真ん中のやつ)作成
  60.     //:距離Joint
  61.     private function makeBridge():void {
  62.  
  63.         var x:Number;
  64.         var y:Number = 390;
  65.         var i:int//カウンタ
  66.        
  67.         var rack:b2Body = this.m_b2_world.GetGroundBody(); //橋の岸
  68.        
  69.         var boards:Array = new Array();
  70.  
  71.         //橋の板
  72.         for (i = 0; i <= 5; i++){
  73.             x = i * 60 + 150//配置場所X
  74.             var borad_display:Sprite = new board_60_mc as Sprite;  //橋板(表示用)
  75.             var board:b2Body = this.makeB2BodyBox(60, 10, x, y, 0, 1, 1.5, 0.5, borad_display, m_display_blocks);
  76.             boards[i] = board;
  77.         }
  78.        
  79.         //Joint
  80.         var body1:b2Body; //距離Joint 繋ぐ物体1つ目
  81.         var body2:b2Body; //距離Joint 繋ぐ物体2つ目
  82.         var anc1:b2Vec2;  //距離Joint 繋ぎ場所1つ目
  83.         var anc2:b2Vec2;  //距離Joint 繋ぎ場所2つ目
  84.        
  85.         var dj_def:b2DistanceJointDef;  //距離Joint
  86.  
  87.        
  88.         //左岸と板
  89.         x = 120//繋げる場所
  90.        
  91.         body1 = rack;
  92.         body2 = boards[0];
  93.         anc1 = this.createB2Vec(x - 5, y);
  94.         anc2 = this.createB2Vec(x + 5, y);
  95.         dj_def = new b2DistanceJointDef();
  96.         //dj_def.length = 0;
  97.         dj_def.Initialize(body1, body2, anc1, anc2);
  98.  
  99.         this.m_b2_world.CreateJoint(dj_def);           
  100.        
  101.         //板と板
  102.         for (i = 0; i <= 4; i++){
  103.            
  104.             //板の左側を繋げる
  105.             x = (i * 60) + 210//繋げる場所
  106.            
  107.             body1 = boards[i];
  108.             body2 = boards[i + 1];
  109.             anc1 = this.createB2Vec(x - 5, y);
  110.             anc2 = this.createB2Vec(x + 5, y);
  111.             dj_def = new b2DistanceJointDef();
  112.             dj_def.Initialize(body1, body2, anc1, anc2);
  113.            
  114.             this.m_b2_world.CreateJoint(dj_def);
  115.         }
  116.  
  117.         //板と右岸
  118.         //板の右側を繋げる
  119.         x = 510//繋げる場所
  120.        
  121.         body1 = boards[5];
  122.         body2 = rack;
  123.         anc1 = this.createB2Vec(x - 5, y);
  124.         anc2 = this.createB2Vec(x + 5, y);
  125.         dj_def = new b2DistanceJointDef();
  126.         dj_def.Initialize(body1, body2, anc1, anc2);
  127.  
  128.         this.m_b2_world.CreateJoint(dj_def);
  129.     }
  130.  
  131.    
  132.     //ぐるぐるきのこ(左側のポールに繋がってる回ってる円盤)作成
  133.     //:回転ジョイント+距離ジョイント
  134.     private function makeGuruguruKinoko():void {
  135.        
  136.         //表示用
  137.         var kinoko1_display:kinoko_kurukuru_green_mc = new kinoko_kurukuru_green_mc;
  138.         var kinoko2_display:kinoko_kurukuru_red_mc = new kinoko_kurukuru_red_mc;
  139.         var kinoko3_display:kinoko_kurukuru_yellow_mc = new kinoko_kurukuru_yellow_mc;
  140.         var kinoko4_display:kinoko_kurukuru_green_mc = new kinoko_kurukuru_green_mc;
  141.         kinoko2_display.width = 30;
  142.         kinoko2_display.height = 30;
  143.         kinoko4_display.width = 30;
  144.         kinoko4_display.height = 30;
  145.        
  146.         //位置
  147.         var bura_x:int = 150;
  148.         var bura_y:int = 100;
  149.        
  150.         var kinoko1:b2Body = this.makeB2BodyCircle(60, bura_x, bura_y, 1, 0.5, 0.5, kinoko1_display, this.m_display_blocks);
  151.         var kinoko2:b2Body = this.makeB2BodyCircle(30, bura_x, bura_y + 90, 1, 0.5, 0.5, kinoko2_display, this.m_display_blocks);
  152.         var kinoko3:b2Body = this.makeB2BodyCircle(30, bura_x, bura_y + 180, 1, 0.5, 0.5, kinoko3_display, this.m_display_blocks);
  153.         var kinoko4:b2Body = this.makeB2BodyCircle(30, bura_x, bura_y + 270, 1, 0.5, 0.5, kinoko4_display, this.m_display_blocks);
  154.  
  155.        
  156.         //回転ジョイント
  157.        
  158.         //きのこ1はぐるぐる回る
  159.         var rj_def:b2RevoluteJointDef = new b2RevoluteJointDef;
  160.         rj_def.enableMotor = true;
  161.         rj_def.motorSpeed = 2.0;
  162.         rj_def.maxMotorTorque = 300000;
  163.        
  164.         rj_def.Initialize(this.m_b2_world.GetGroundBody(), kinoko1, kinoko1.GetPosition());
  165.         this.m_b2_world.CreateJoint(rj_def);
  166.        
  167.         //距離ジョイント
  168.        
  169.         //きのこ1と2(回るきのこ1の中心からずれた位置ときのこ2の中心を繋ぐ)
  170.         var anc1:b2Vec2 = this.createB2Vec(bura_x + 20, bura_y)//
  171.        
  172.         var dj_def1:b2DistanceJointDef = new b2DistanceJointDef;
  173.         dj_def1.Initialize(kinoko1, kinoko2, anc1, kinoko2.GetPosition());
  174.         this.m_b2_world.CreateJoint(dj_def1);
  175.        
  176.         //きのこ2と3(中心同士で繋ぐ)
  177.         var dj_def2:b2DistanceJointDef = new b2DistanceJointDef;
  178.         dj_def2.Initialize(kinoko2, kinoko3, kinoko2.GetPosition(), kinoko3.GetPosition());
  179.         this.m_b2_world.CreateJoint(dj_def2);
  180.        
  181.         //きのこ3と4(中心同士で繋ぐ)
  182.         var dj_def3:b2DistanceJointDef = new b2DistanceJointDef;
  183.         dj_def2.Initialize(kinoko3, kinoko4, kinoko3.GetPosition(), kinoko4.GetPosition());
  184.         this.m_b2_world.CreateJoint(dj_def2);
  185.        
  186.         //後から使えるように
  187.         this.m_b2_guru_kinoko1 = kinoko1;
  188.         this.m_b2_guru_kinoko2 = kinoko2;
  189.         this.m_b2_guru_kinoko3 = kinoko3;
  190.         this.m_b2_guru_kinoko4 = kinoko4;
  191.     }
  192.    
  193.    
  194.     //ゆらゆら棒(右側のポールに繋がってるモビールっぽいやつ)作成:回転ジョイント+距離ジョイント
  195.     private function makeYurayuraBar():void {
  196.        
  197.         //表示用
  198.         var bar_display:board_100_mc = new board_100_mc;
  199.         var kinoko1_display:kinoko_kurukuru_yellow_mc = new kinoko_kurukuru_yellow_mc;
  200.         var kinoko2_display:kinoko_kurukuru_red_mc = new kinoko_kurukuru_red_mc;
  201.         kinoko1_display.width = 40;
  202.         kinoko1_display.height = 40;
  203.         kinoko2_display.width = 40;
  204.         kinoko2_display.height = 40;
  205.        
  206.         var yura_x:int = 450;
  207.         var yura_y:int = 100;
  208.        
  209.         var bar:b2Body = this.makeB2BodyBox(100, 10, yura_x, yura_y, 0, 1, 0.5, 0.5, bar_display, this.m_display_blocks)//棒
  210.         var kinoko1:b2Body = this.makeB2BodyCircle(40, yura_x + 100, yura_y + 150, 1, 0.5, 0.5, kinoko1_display, this.m_display_blocks)//きのこ1
  211.         var kinoko2:b2Body = this.makeB2BodyCircle(40, yura_x - 100, yura_y + 150, 1, 0.5, 0.5, kinoko2_display, this.m_display_blocks)//きのこ2
  212.        
  213.         //回転ジョイント ゆれる棒
  214.         var rj_def:b2RevoluteJointDef = new b2RevoluteJointDef;
  215.         rj_def.enableLimit = true//角度制限付ける
  216.         rj_def.lowerAngle = -30  * Math.PI / 180;
  217.         rj_def.upperAngle = 30  * Math.PI / 180;
  218.        
  219.         rj_def.Initialize(this.m_b2_world.GetGroundBody(), bar, bar.GetPosition());
  220.         this.m_b2_world.CreateJoint(rj_def);
  221.        
  222.        
  223.         //距離ジョイント ゆれる棒ときのこ繋ぐ
  224.        
  225.         //きのこ1
  226.         var anc1:b2Vec2 = this.createB2Vec(yura_x + 50, yura_y);
  227.  
  228.         var dj_def1:b2DistanceJointDef = new b2DistanceJointDef;
  229.         dj_def1.Initialize(bar, kinoko1, anc1, kinoko1.GetPosition());
  230.         this.m_b2_world.CreateJoint(dj_def1);
  231.        
  232.         //きのこ2
  233.         var anc2:b2Vec2 = this.createB2Vec(yura_x - 50, yura_y);
  234.        
  235.         var dj_def2:b2DistanceJointDef = new b2DistanceJointDef;
  236.         dj_def2.Initialize(bar, kinoko2, anc2, kinoko2.GetPosition());
  237.         this.m_b2_world.CreateJoint(dj_def2);
  238.        
  239.         //後から使えるように
  240.         this.m_b2_yura_bar = bar;
  241.         this.m_b2_yura_kinoko1 = kinoko1;
  242.         this.m_b2_yura_kinoko2 = kinoko2;
  243.     }
  244.    
  245.    
  246.     //演算
  247.     private function update(e:Event):void{
  248.    
  249.         var self:StudyB2Joint1 = this;
  250.  
  251.         //距離ジョイントで繋げてる紐を描く
  252.        
  253.         //Body位置から描画位置移動する関数
  254.         var moveTo_Pos:Function = function(graphics:Graphics, body:b2Body, offset_x:Number = 0, offset_y:Number = 0):void {
  255.            
  256.             var x:Number = body.GetPosition().x * self.m_b2_physcale + offset_x;
  257.             var y:Number = body.GetPosition().y * self.m_b2_physcale + offset_y;
  258.        
  259.             graphics.moveTo(x, y);
  260.         }
  261.        
  262.        
  263.         //Body位置へ線を引く関数
  264.         var lineTo_Pos:Function = function(graphics:Graphics, body:b2Body):void {
  265.            
  266.             var x:Number = body.GetPosition().x * self.m_b2_physcale;
  267.             var y:Number = body.GetPosition().y * self.m_b2_physcale;
  268.  
  269.             graphics.lineTo(x, y);
  270.         }      
  271.        
  272.         this.m_display_blocks.graphics.clear();
  273.         this.m_display_blocks.graphics.lineStyle(1, 0x9FD06F);
  274.        
  275.         //ぐるぐるぐきのこ
  276.         moveTo_Pos(this.m_display_blocks.graphics, this.m_b2_guru_kinoko1);
  277.         lineTo_Pos(this.m_display_blocks.graphics, this.m_b2_guru_kinoko2);
  278.         lineTo_Pos(this.m_display_blocks.graphics, this.m_b2_guru_kinoko3);
  279.         lineTo_Pos(this.m_display_blocks.graphics, this.m_b2_guru_kinoko4);
  280.    
  281.    
  282.         //ゆらゆら棒
  283.         //棒は斜めになるので、角度から繋ぐ位置取得
  284.         var angle:Number = this.m_b2_yura_bar.GetAngle();
  285.         var offset_x:Number = Math.cos(angle) * 50;
  286.         var offset_y:Number = Math.sin(angle) * 50;
  287.         moveTo_Pos(this.m_display_blocks.graphics, this.m_b2_yura_bar, offset_x, offset_y);
  288.         lineTo_Pos(this.m_display_blocks.graphics, this.m_b2_yura_kinoko1);
  289.         moveTo_Pos(this.m_display_blocks.graphics, this.m_b2_yura_bar, -offset_x, -offset_y);
  290.         lineTo_Pos(this.m_display_blocks.graphics, this.m_b2_yura_kinoko2);
  291.        
  292.         //B2Boxの時間進める
  293.         this.m_b2_world.Step(this.m_b2_timeStep, this.m_b2_iterations);
  294.        
  295.         //各B2BoxのBodyの動きにあわせて中のSpriteを動かす
  296.         for (var bb:b2Body = this.m_b2_world.m_bodyList; bb; bb = bb.m_next){
  297.            
  298.             var bb_x:Number = bb.GetPosition().x * m_b2_physcale;
  299.             var bb_y:Number = bb.GetPosition().y * m_b2_physcale;
  300.            
  301.             //画面外に出て行ったきのこ削除
  302.             if (bb_x <-100 || bb_x> 700 || bb_y <-100 || bb_y> 600) {
  303.                 this.m_b2_world.DestroyBody(bb);
  304.                 if(bb.m_userData != null){
  305.                     this.m_kinokoS.removeChild(bb.m_userData);
  306.                     bb.m_userData = null;
  307.                 }
  308.             }
  309.            
  310.             //演算結果にあわせて表示用データ移動
  311.             if (bb.m_userData is Sprite){
  312.                 //メートルからピクセル単位に変換
  313.                 bb.m_userData.x = bb_x;
  314.                 bb.m_userData.y = bb_y;
  315.                 bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI);
  316.             }
  317.         }
  318.     }
  319.    
  320.     //-----きのこを降らす(ここは、基本と同じもの使用)-----
  321.    
  322.     //大きいきのこ作る
  323.     private function initKinokoL():void {
  324.        
  325.         var self:StudyB2Joint1 = this;
  326.        
  327.         //これはMC配置するだけ
  328.         var kinoko:kinoko_L_MC = new kinoko_L_MC;
  329.         kinoko.x = 555;
  330.         kinoko.y = 350;
  331.         kinoko.width = 60;
  332.         kinoko.height = 65;
  333.        
  334.         kinoko.buttonMode = true;
  335.        
  336.         kinoko.addEventListener(MouseEvent.MOUSE_OVER,
  337.             function(e:Event):void {
  338.                 kinoko.gotoAndPlay("frm_hover");
  339.             });
  340.                                
  341.         kinoko.addEventListener(MouseEvent.MOUSE_UP,
  342.             function(e:Event):void {
  343.                 kinoko.gotoAndPlay("frm_action");
  344.                 self.makeKinokoS(Math.random() * 550 + 50, 0);
  345.             });
  346.            
  347.         this.m_kinokoL = kinoko;
  348.        
  349.         this.addChild(this.m_kinokoL);
  350.  
  351.     }
  352.    
  353.    
  354.     //小さいきのこ入れるのを作って、小さいきのこ配置
  355.     private function initKinokoS():void {
  356.        
  357.         //小さいきのこを入れる
  358.         this.m_kinokoS = new Sprite();
  359.         this.addChild(this.m_kinokoS);
  360.        
  361.         //最初の小さいきのこ配置
  362.         for (var i:int = 0; i <5 ;i++){
  363.             this.makeKinokoS(Math.random() * 550 + 50, 0);
  364.         }
  365.     }
  366.    
  367.    
  368.     //小さいきのこ作成
  369.     private function makeKinokoS(x:Number, y:Number):void {
  370.        
  371.         var kinoko:Sprite;
  372.         var land = Math.random();
  373.        
  374.         if (land>= 0.6) {
  375.             //普通のきのこ
  376.             kinoko = new kinoko_S1_MC as Sprite;
  377.         }
  378.         else if(land>= 0.3){
  379.             //怪しいきのこ
  380.             kinoko = new kinoko_S2_MC as Sprite;
  381.         }
  382.         else {
  383.             //しめじ
  384.             kinoko = new kinoko_S3_MC as Sprite;
  385.         }   
  386.        
  387.         this.makeB2BodyCircle(30, x, y, 1.0, 0.5, 0.5, kinoko, this.m_kinokoS);
  388.     }
  389. }

コメント・トラックバック

  1. 冷吟閑酔 2009-06-18 06:12:57 (ピンバック)

    [...] DFlashAS3 ジョイント1(回転ジョイント・距離ジョイント) http://hokori.net/2009/03/05/box2dflashas3_joint1/ [...]

コメントを送る
※は入力必須です。コメントは管理者の承認後に表示されます。