ActionScript3 で 3D 振り子を作るサンプル
3D描画ライブラリ Papervision と 3D物理演算ライブラリ WOW-Engine を利用して 3D 振り子を作ります。(Papervision3D 逆引きシリーズ)
3D 振り子を作るにあたって必要な Papervision3D の使い方や WOW-Engine の導入法・使い方は過去のエントリを見てね。今回新しく出てきて肝となる部分はすごく少ないです。
まずパーティクルを作成
振り子の「支点」と「おもり」用に2つのパーティクル*1を作成します。支点のほうのパーティクルはコンストラクタの第5引数を false にして固定しておくのを忘れずに。こうすると、物理現象の影響を受けないパーティクルになり直接座標を指定しない限りは動かなくなります。
// 支点を作成 var particle1:WSphere = new WSphere(0, 100, 0, 30, true); wow.addParticle(particle1); // おもりを作成 var particle2:WSphere = new WSphere(0, 0, 0, 30, false, 1); wow.addParticle(particle2);
WSpringConstraint
支点とおもりを作ったら、今度はこの2つを繋ぐ「ひも」を作ります。2つのパーティクルを繋ぐには WSpringConstraint クラスを使います。
// 二つのパーティクルを接続 // particle1 と particle2 を強さ 1 で接続 var spring:WSpringConstraint = new WSpringConstraint(particle1, particle2, 1); spring.restLength = 100; wow.addConstraint(spring);
- new WSpringConstraint()
- コンストラクタではどのパーティクルを繋ぐかと接続の強度を指定します。接続の強度は0から1の数値で1ならば2つのパーティクル間の距離は常に一定に保たれるようになり、逆に0だと二つのパーティクルは接続されていないかのようにふるまいます。中間の値を指定するとばねで接続されたようになります。
- spring.length
- lenght プロパティでは二つのパーティクル間の距離を設定します。
- addConstraint
- 最後に WOW-Engine にこの WSpringConstraint を追加します。
たったこれだけ!
あとは過去のエントリと同じように Papervision3D の初期化や WOW-Engine の初期化。フレーム毎に座標の更新などを行えば振り子の完成です。
WSpringConstraint は応用が効いて、パーティクルを平面に並べて接続すれば布の表現ができるし、立方体の頂点にパーティクルを配置して接続すれば「回転」を含めた箱の表現ができるし、いろいろ面白そうです。
全体のコード
package { import flash.display.Sprite; import flash.events.Event; import fr.seraf.wow.constraint.WSpringConstraint; import fr.seraf.wow.core.data.WVector; import fr.seraf.wow.core.WOWEngine; import fr.seraf.wow.primitive.WBoundArea; import fr.seraf.wow.primitive.WSphere; import org.papervision3d.lights.PointLight3D; import org.papervision3d.materials.shadematerials.GouraudMaterial; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.materials.WireframeMaterial; import org.papervision3d.objects.primitives.Sphere; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.view.BasicView; [SWF(width="320", height="240", backgroundColor="#FFFFFF")] public class Sample005 extends Sprite { public function Sample005 () { // 物理計算のために WOWEngine を作成 var wow:WOWEngine = new WOWEngine(1); wow.addMasslessForce(new WVector(0, -4, 0)); // バウンドエリアを設定 var boundArea:WBoundArea = new WBoundArea(1000, 300, 1000); wow.setBoundArea(boundArea); // 支点を作成 var particle1:WSphere = new WSphere(0, 100, 0, 30, true); wow.addParticle(particle1); // おもりを作成 var particle2:WSphere = new WSphere(0, 0, 0, 30, false, 1); wow.addParticle(particle2); // 二つのパーティクルを接続 // particle1 と particle2 を強さ 1 で接続 var spring:WSpringConstraint = new WSpringConstraint(particle1, particle2, 1); spring.restLength = 100; wow.addConstraint(spring); // 表示のために PaperVision のビューを作成 var view:BasicView = new BasicView(); view.camera.y = 500; view.camera.x = 600; view.camera.z = -900; addChild(view); view.startRendering(); // 光源を作る var light:PointLight3D = new PointLight3D(false); light.x = 500; light.y = 800; light.z = 0; // 地面表示用 3D オブジェクトを作る var plane:Plane = new Plane(new WireframeMaterial(0xff99bb), 1000, 1000, 3, 3); plane.rotationX = 90; plane.y = -150; view.scene.addChild(plane); // パーティクルに対応する 3D オブジェクトを作る var sphere1:Sphere = new Sphere(new GouraudMaterial(light, 0xeeeeee, 0x666666), 30, 30, 30); var sphere2:Sphere = new Sphere(new GouraudMaterial(light, 0xeeeeee, 0x666666), 30, 30, 30); view.scene.addChild(sphere1); view.scene.addChild(sphere2); // 毎フレームごとの処理 var c:int = 0; addEventListener(Event.ENTER_FRAME, function():void { // 計算を行い WOW-Engine のオブジェクトを次の位置へ wow.step(); // 新たな位置を PaperVision3D のオブジェクトへ設定 sphere1.x = particle1.px; sphere1.y = particle1.py; sphere1.z = particle1.pz; sphere2.x = particle2.px; sphere2.y = particle2.py; sphere2.z = particle2.pz; // 支点を移動 particle1.px = 150*Math.sin(3.9*c*Math.PI/180); particle1.pz = 150*Math.cos(12.0*c*Math.PI/180); // カメラを移動 view.camera.x = 900*Math.sin(c*Math.PI/180); view.camera.z = 900*Math.cos(c*Math.PI/180); c++; }); } } }
*1:WOW-Engine で物理演算の対象になるオブジェクト