内容
Wiiリモコンの傾きに応じて箱が回転し、その中を球が転がるサンプルです。
実際には、箱が回転しているのではなく、重力方向を変えているだけなので、回転によって球に箱からの力が加わったりすることはありません。
基本的に、視点はWiiリモコンを上から見た形になるので、ボールは奥側に転がっていきます。
WiiFlash Serverを立ち上げなければ操作できないので、コードのみ置いておきます。
コード
//mxmlc WiiWoW.as //author Show=O=Healer /* Wiiリモコンで傾けた箱の中を球が転がるサンプル 実際には箱は移動しておらず、重力方向を変化させている そのため、急激に傾けても箱からの力は加わらないため、球の移動はゆっくり 箱(m_BoundArea)の中をボール(m_Sphere)が転がっていて、それを上から見てる状況 */ package { //Common import flash.display.*; import flash.events.*; //PV3D import org.papervision3d.core.*; import org.papervision3d.core.proto.*; import org.papervision3d.scenes.*; import org.papervision3d.objects.*; import org.papervision3d.cameras.*; import org.papervision3d.materials.*; //WoW import fr.seraf.wow.constraint.*; import fr.seraf.wow.core.*; import fr.seraf.wow.core.data.*; import fr.seraf.wow.math.*; import fr.seraf.wow.primitive.*; import fr.seraf.wow.util.*; //WiiFlash import org.wiiflash.Wiimote; import org.wiiflash.events.ButtonEvent; //Class public class WiiWoW extends Sprite { //Common private var m_Container : Sprite; //PV3D private var m_Scene : Scene3D; // private var m_Camera : Camera3D; private var m_Camera : FreeCamera3D; private var m_RootNode : DisplayObject3D; // private var m_BoundArea : DisplayObject3D; private var m_Sphere : DisplayObject3D; private var m_Cube : DisplayObject3D; //WoW private var m_WoWEngine:WOWEngine; private var m_BoundArea_WoW:WBoundArea; private var m_Sphere_WoW:WSphere; //WiiFlash private var m_Wiimote:Wiimote = new Wiimote(); //Param private const BOUND_AREA_W:Number = 600; private const BOUND_AREA_H:Number = 200; private const BOUND_AREA_D:Number = 500; private const SPHERE_INIT_X:Number = 0; private const SPHERE_INIT_Y:Number = 100; private const SPHERE_INIT_Z:Number = -50; private const SPHERE_RAD:Number = 20; private const CAMERA_DISTANCE:Number = 400; private const GRAVITY:Number = 10.0; //Constructor public function WiiWoW():void { {//Init Common //リサイズ対応 stage.addEventListener(Event.RESIZE, onStageResize); //定期的にupdateを呼ばせる addEventListener(Event.ENTER_FRAME, update); } {//Init PV3D {//m_Container // 表示用の Sprite オブジェクトを生成 m_Container = new Sprite(); m_Container.x = 400 / 2; // at center : swf width = 400 m_Container.y = 400 / 2; // at center : swf height = 400 addChild(m_Container); } {//m_Scene // シーンオブジェクトを作る m_Scene = new Scene3D(m_Container); } {//m_Camera // カメラオブジェクトを作る // m_Camera = new Camera3D(); m_Camera = new FreeCamera3D(); m_Camera.z = -CAMERA_DISTANCE; m_Camera.focus = 500; m_Camera.zoom = 1; } {//m_RootNode // ルートノードを作る m_RootNode = new DisplayObject3D(); m_Scene.addChild(m_RootNode); } {//m_BoundArea //Planeを内側に表示する //front m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xFFFFFF), BOUND_AREA_W, BOUND_AREA_H, 8); obj.z = 0.5*BOUND_AREA_D; return obj; }() ); //back m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xAAAAAA), BOUND_AREA_W, BOUND_AREA_H, 8); obj.z = -0.5*BOUND_AREA_D; obj.rotationY = 180; return obj; }() ); //right m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xFFAAAA), BOUND_AREA_D, BOUND_AREA_H, 8); obj.x = 0.5*BOUND_AREA_W; obj.rotationY = 90; return obj; }() ); //left m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xAAAAFF), BOUND_AREA_D, BOUND_AREA_H, 8); obj.x = -0.5*BOUND_AREA_W; obj.rotationY = -90; return obj; }() ); //top m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xAAFFAA), BOUND_AREA_W, BOUND_AREA_D, 8); obj.y = 0.5*BOUND_AREA_H; obj.rotationX = 90; return obj; }() ); //bottom m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xFFFFAA), BOUND_AREA_W, BOUND_AREA_D, 8); obj.y = -0.5*BOUND_AREA_H; obj.rotationX = -90; return obj; }() ); } {//m_Sphere m_Sphere = function():DisplayObject3D { var material:ColorMaterial = new ColorMaterial(0x000000); var sphere:DisplayObject3D = new Sphere(material, SPHERE_RAD); sphere.x = SPHERE_INIT_X; sphere.y = SPHERE_INIT_Y; sphere.z = SPHERE_INIT_Z; return sphere; }(); m_RootNode.addChild(m_Sphere); } } {//Init WoW {//m_WoWEngine m_WoWEngine= new WOWEngine(); m_WoWEngine.collisionResponseMode = m_WoWEngine.SELECTIVE; m_WoWEngine.addMasslessForce(new WVector(0.1, -1, 0));//重力っぽいもの m_WoWEngine.damping = 1; } {//m_BoundArea m_BoundArea_WoW = new WBoundArea(BOUND_AREA_W, BOUND_AREA_H, BOUND_AREA_D); m_BoundArea_WoW.setPosition(0, 0, 0);//中心位置 m_BoundArea_WoW.elasticity = 1;//弾性 m_BoundArea_WoW.friction = 0.050;//摩擦 m_WoWEngine.setBoundArea(m_BoundArea_WoW); } {//m_Sphere_WoW var IsFixed:Boolean = false; m_Sphere_WoW = new WSphere(SPHERE_INIT_X, SPHERE_INIT_Y, SPHERE_INIT_Z, SPHERE_RAD, IsFixed, 43, 0.65); m_WoWEngine.addParticle(m_Sphere_WoW); } } //Init WiiFlash { //サーバに接続したときのリスナ m_Wiimote.addEventListener(Event.CONNECT, handleConnect); //接続開始 m_Wiimote.connect(); } } //=Common= private function update( event:Event ):void { //リモコンの方向から、重力の方向を決定して変更。カメラ位置もそれに合わせる { var gravityX:Number = -m_Wiimote.sensorY; var gravityY:Number = -m_Wiimote.sensorZ; var gravityZ:Number = m_Wiimote.sensorX; m_WoWEngine.masslessForce = new WVector(GRAVITY*gravityX, GRAVITY*gravityY, GRAVITY*gravityZ); var cameraDir:Number3D = new Number3D(-gravityX, -gravityY, -gravityZ); cameraDir.normalize(); m_Camera.x = cameraDir.x * CAMERA_DISTANCE; m_Camera.y = cameraDir.y * CAMERA_DISTANCE; m_Camera.z = cameraDir.z * CAMERA_DISTANCE; var upAxis_Normal:Number3D = Number3D.cross(new Number3D(-1, 0, 0), cameraDir); var upAxis_CaseX:Number3D = new Number3D(0, 0, 1); var ratio:Number = cameraDir.x; if(ratio < 0.0){ratio = -ratio;} var upAxis:Number3D = new Number3D( upAxis_Normal.x * (1.0-ratio) + upAxis_CaseX.x * ratio, upAxis_Normal.y * (1.0-ratio) + upAxis_CaseX.y * ratio, upAxis_Normal.z * (1.0-ratio) + upAxis_CaseX.z * ratio ); upAxis.normalize(); m_Camera.lookAt(DisplayObject3D.ZERO, upAxis); } //物理エンジンの更新 m_WoWEngine.step(); {//球体の位置を物理エンジンの計算結果に対応させる m_Sphere.x = m_Sphere_WoW.px; m_Sphere.y = m_Sphere_WoW.py; m_Sphere.z = m_Sphere_WoW.pz; } //描画 m_Scene.renderCamera(m_Camera); } private function onStageResize(event:Event):void { m_Container.x = stage.stageWidth / 2; m_Container.y = stage.stageHeight / 2; } //=WiiFlash= //WiiFlash Serverに接続したときのリスナ private function handleConnect(e:Event):void { trace("Connect"); } } }
参考
このサンプルは主に以下のページを参考に作成しました。
- [ヅラド] Papervision3D のプリミティブオブジェクトを生成するサンプル by Flex SDK
- PV3Dの導入からサンプルまで
- http://cs3book.flashoop.jp/wiki/index.php?Wii%E3%83%AA%E3%83%A2%E3%82%B3%E3%83%B3%E3%81%A8AS3
- WiiFLashの導入からサンプルまで
- WOWEngineで、ミクとリンが跳梁跋扈!! – タロタローグ ブログ
- WoW-Engineの導入からサンプルまで
- Adobe Flash - テクニカルノート一覧
- AS3のリファレンス
- JS や AS で長い関数をリファクタリングする1手法 - てっく煮ブログ 跡地
- AS3でのローカル関数の作成について
- [ヅラド] Papervision3D でテクスチャぐるぐる PlaneWorld サンプル その3 by Flex SDK
- PV3Dでのカメラの設定について
- http://www.trick7.com/blog/2007/08/19-120206.php
- PV3Dの1.5が1.5じゃない件