Box2DでActionScript物理プログラミング

第5回 ジョイントで物をつなぐ

この記事を読むのに必要な時間:およそ 4 分

マウスジョイントを使って車を持ち運ぶ

ただ車が走っているだけではつまらないので,マウスで持ち運べるようにしましょう。マウスで操作をするときには,マウスジョイント(b2MouseJointDef)を使います。

クラスにプロパティを追加する

まず準備段階として,クラスに以下の3つのプロパティを追加します。

// 物理エンジンの管理クラス
private var world:b2World; // ← この行までは最初からある
// 車体
private var body:b2Body;
// マウスジョイントの定義
private var mouseJointDef:b2MouseJointDef;
// マウスジョイント
private var mouseJoint:b2MouseJoint;

このうち,bodyは先ほど車体として使っていたローカル変数を移動させたものです。そのため,bodyを作っている行を以下のように書き換えます。

var body:b2BodyDef = world.CreateDynamicBody(bodyDef);
 ↓ 書き換える
body = world.CreateDynamicBody(bodyDef);

mouseJointDefとmouseJointは,今回新しく追加されたもので,マウスジョイントの定義と,ジョイントそのものです。

マウスジョイントを定義する

車を作り終わった直後のところに,マウスジョイントの定義を設定するプログラムを書きます。

// マウスジョイントを定義する
mouseJointDef = new b2MouseJointDef();
// 片方のbodyにはワールド全体を設定する
mouseJointDef.body1 = world.GetGroundBody();
// もう片方には移動させたい物体(=車体)を設定する
mouseJointDef.body2 = body;
// 車体の中心座標を設定する
mouseJointDef.target = body.GetWorldCenter();
// マウスで引っ張られるときの力
mouseJointDef.maxForce = 5;
// シミュレーションの間隔
mouseJointDef.timeStep = 1 / 24;

回転ジョイントのときと同じように,つなぎたい物体をbody1とbody2に設定します。ここではb2WorldクラスのGetGroundBodyメソッドを使って,片方をワールド全体に設定します。もう片方にはマウスで動かしたい物体を設定します。

targetには,引っ張られる対象の座標を設定します。今回は車体を引っ張ることにするので,body.GetWorldCenterを使って車体の中心座標を設定します。

maxForceとtimeStepは,それぞれ説明にあるとおり,マウスで引っ張る力とシミュレーションの間隔です。maxForceが小さすぎると,重力に打ち勝つことができずに車が落ちていってしまいます。このあたりは実際に値を書き換えてみて試してみてください。シミュレーション間隔は,Flashの画面更新間隔と同じ1/24秒にします。

マウスイベントのハンドラを追加する

ここまで書いて気づいたかもしれませんが,マウスジョイントの定義は作りましたが,マウスジョイントそのものは作っていません。なぜかというと,マウスジョイントを作ってしまうと,車体が引っ張られ続けてしまうからです。マウスボタンが押されている間だけジョイントでつなぐという処理が必要になります。

マウス操作が絡んでくるので,イベントハンドラを登録しなければなりません。コンストラクタの最後に,以下の3行を追加してください。

stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);

マウスジョイントを作る

マウスボタンが押されたときに,マウスジョイントを作ります。作り方は回転ジョイントと同じくCreateJointメソッドを使います。

private function mouseDownHandler(event:MouseEvent):void {
	// マウスボタンが押されたら,マウスジョイントを作る
	mouseJoint = b2MouseJoint(world.CreateJoint(mouseJointDef));
}

マウスジョイントを切り離す

重要なのはマウスボタンが離されたときで,ここでジョイントを切らないと車が宙に浮いたままになってしまいます。ジョイントを切るには,以下のようにDestroyJointメソッドを使います。ジョイントを切ったら,mouseJointをnullにしておきます。

private function mouseUpHandler(event:MouseEvent):void {
	// マウスボタンが離されたら,マウスボタンを切り離す
	world.DestroyJoint(mouseJoint);
	mouseJoint = null;
}

マウスジョイントの位置を更新する

最後に,マウスカーソルが動かされたときの処理です。mouseJointがnullでないとき,つまりジョイントが存在しているときだけ処理を実行します。実行する処理とは,現在のマウスカーソル位置をマウスジョイントに設定することです。これには,SetTargetメソッドを使います。

private function mouseMoveHandler(event:MouseEvent):void {
	// mouseJointがnullでないときだけ処理を実行する
	if (mouseJoint) {
		// マウスが押された場所を物理エンジン内の座標系に変換する
		var x:Number = event.stageX / DRAW_SCALE;
		var y:Number = event.stageY / DRAW_SCALE;
		// マウスジョイントのカーソル位置を更新
		mouseJoint.SetTarget(new b2Vec2(x, y));
	}
}

これで完成です。コンパイルすると以下のようなFlashができると思います。画面上部でマウスを適当にドラッグすると,車を持ち運ぶことができます。

ここまで編集してきたソースを,クラス名を変えて置いておきますので,参考にしてください。

まとめ

6種類あるジョイントの中から回転ジョイントとマウスジョイントを使い,マウスで持ち運ぶことのできる車を作りました。ジョイントを使うことで,より動きがあり,Box2DらしいFlashが作れると思います。今回説明し切れなかったジョイントについては,Box2Dのサンプルなどを参考にしてぜひ試してみてください。

次回は脱DebugDrawをテーマに,自前の描画を行う方法について説明したいと思います。

著者プロフィール

木村秀敬(きむらひでたか)

茨城高専,北陸先端大を卒業後,独立系ベンチャーにあこがれてjig.jpに就職。 ActionScript好きですが,根はコテコテのC/C++プログラマです。Flash/ActionScriptに興味のある方は是非Spark Projectへ。