忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

Planck.jsサンプルコード 物体をマウスでつまむ その2

Planck.jsには物体をマウスでつまむためのMouseJointクラスが秘密裏に用意されており、これを使うと前回行ったのと同じようなことをよりきれいに書けます。ただし、このクラスはテスト用の隠しクラスで、ドキュメントには載っていないようです。


サンプルコード

<canvas id="canvas" width="400" height="400" style="border:solid"></canvas>

<script src="planck.js"></script>

<script>

var World = planck.World,
	Vec2 = planck.Vec2,
	Edge = planck.Edge,
	Box = planck.Box;


class Demo{
	constructor(){
		this.world = this._createWorld();
		this._initializeGround(this.world);
		this._initializeBox(this.world);
		this._initializeInput();
	}

	_initializeInput(){
		this.mouseBody = this.world.createBody();

		canvas.onmousedown = (e) => {
			if(!this.boxShape.testPoint(this.box.getTransform(), Vec2(e.offsetX, e.offsetY))){return;}

			this.mouseJoint = planck.MouseJoint({maxForce:1000000}, this.mouseBody, this.box, Vec2(e.offsetX, e.offsetY));
			this.world.createJoint(this.mouseJoint);
		};
		canvas.onmousemove = (e) => {
			if(this.mouseJoint){
				this.mouseJoint.setTarget(Vec2(e.offsetX, e.offsetY));
			}
		};
		canvas.onmouseleave = canvas.onmouseup = (e) => {
			if(this.mouseJoint){
				this.world.destroyJoint(this.mouseJoint);
				this.mouseJoint = null;
			}
		};
	}

	_createWorld(){
		var world = World();
		world.setGravity(Vec2(0, 100));
		return world;
	}

	_initializeGround(world){
		var ground = world.createBody();
		ground.createFixture(Edge(Vec2(0, canvas.height), Vec2(400, canvas.height)));
	}

	_initializeBox(world){
		this.box = world.createBody().setDynamic();
		this.box.setPosition(Vec2(200, 100));
		this.box.setAngle(Math.PI / 6);

		this.boxShape = Box(10, 40);
		this.box.createFixture(this.boxShape);
		this.box.setMassData(this._getMassData(this.boxShape));
	}

	_getMassData(boxShape){
		var massData = {center:Vec2()};
		boxShape.computeMass(massData, 1);
		return massData;
	}

	run(){
		window.requestAnimationFrame(() => this.run());
		this._update();
		this._draw();
	}

	_update(){
		this.world.step(1 / 60);
	}

	_draw(){
		var context = canvas.getContext("2d");
		context.clearRect(0, 0, canvas.width, canvas.height);
		this._drawBox(context);
		this._drawMouseJoint(context);
	}

	_drawMouseJoint(context){
		if(!this.mouseJoint){return;}

		context.strokeStyle = "orange";
		context.beginPath();
		var anchorA = this.mouseJoint.getAnchorA();
		context.lineTo(anchorA.x, anchorA.y);
		var anchorB = this.mouseJoint.getAnchorB();
		context.lineTo(anchorB.x, anchorB.y);
		context.stroke();
	}

	_drawBox(context){
		for(var fixture = this.box.getFixtureList(); fixture; fixture = fixture.getNext()){
			context.beginPath();

			for(var vertex of fixture.getShape().m_vertices){
				var transformedPosition = planck.Transform.mul(this.box.getTransform(), vertex);
				context.lineTo(transformedPosition.x, transformedPosition.y);
			}

			context.fill();
		}
	}
}


function main(){
	var demo = new Demo();
	demo.run();
}

main();

</script>

実行結果

解説

これは前回と同じように、マウスでブロックをつまんで引っ張れるプログラムです。

前回はロジックをすべて自前で書きましたが、同じようなことは既に用意されているMouseJointクラスを使ってもでき、こっちのほうが楽です。

ただし、MouseJoint.jsには不吉なコメントが書かれており、それによるとこのクラスはテスト用に開発されていて、それゆえマニュアルには書かれていないのだそうです。ということは、将来MouseJointの仕様が変更され、MouseJointを使っているプログラムが新しいバージョンのPlanck.jsでは動かなくなる可能性もあるということです。これを使うときには覚悟すべきかもしれません。もっとも、マニュアルに書かれたクラスだって変更される可能性はないわけではないですが。

拍手[0回]

PR