球と面の衝突判定実装ログ
現状
3次元配列をもとに、ブロック(正確にはその面)を表示するところまで完了。意外と時間がかかった。
明日から、ようやく3次元の衝突判定の実装開始。
どうも会社からftpでサーバに入れないので、swfはあとで家から上げる予定。
動作
上げてみた。
コード
forEachの内部など、コードが汚いところがあるので、そこらへんを綺麗にしつつ衝突処理を実装予定。
//mxmlc Main.as //author Show=O=Healer package { //Common import flash.display.*; import flash.events.*; //Debug import flash.text.*; import flash.ui.*; import flash.utils.*; //Input import flash.ui.Keyboard; //Class public class Main extends Sprite { //Block private var m_BlockManager:BlockManager; //Input private var m_InputL:int = 0; private var m_InputR:int = 0; private var m_InputU:int = 0; private var m_InputD:int = 0; //Param private const PLAYER_VEL:Number = 160.0; private const GRAVITY:Number = 0.0;//-1000.0; //Debug public static var m_Label:TextField; //Constructor public function Main():void { {//Init Block m_BlockManager = new BlockManager(); addChild(m_BlockManager); // m_BlockManager.m_PlayerSphere.m_CollisionAcc.y = GRAVITY; } {//Init Input stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp); } {//Init Common //リサイズ対応 // stage.addEventListener(Event.RESIZE, m_BlockManager.onStageResize); //定期的にupdateを呼ばせる addEventListener(Event.ENTER_FRAME, update); } {//Init Debug m_Label = new TextField(); m_Label.autoSize = TextFieldAutoSize.LEFT; m_Label.selectable=false addChild(m_Label); } } //=Common= private function update( event:Event ):void { //プレイヤーの移動速度をセット // m_BlockManager.m_PlayerSphere.m_CollisionVel.x = PLAYER_VEL * (m_InputR - m_InputL); // if(m_InputU > 0){ // m_BlockManager.m_PlayerSphere.m_CollisionVel.y = -PLAYER_VEL; // } //コリジョンを元に位置更新 m_BlockManager.UpdateCollision(); //描画 m_BlockManager.Render(); //更新した位置を表示に反映 // m_Player.x = m_BlockManager.m_PlayerSphere.m_CollisionPos.x; // m_Player.y = m_BlockManager.m_PlayerSphere.m_CollisionPos.y; } //=Input= private function onKeyDown(event:KeyboardEvent):void{ if(event.keyCode == Keyboard.LEFT){ m_InputL = 1; } if(event.keyCode == Keyboard.RIGHT){ m_InputR = 1; } if(event.keyCode == Keyboard.UP){ m_InputU = 1; } if(event.keyCode == Keyboard.DOWN){ m_InputD = 1; } } private function onKeyUp(event:KeyboardEvent):void{ if(event.keyCode == Keyboard.LEFT){ m_InputL = 0; } if(event.keyCode == Keyboard.RIGHT){ m_InputR = 0; } if(event.keyCode == Keyboard.UP){ m_InputU = 0; } if(event.keyCode == Keyboard.DOWN){ m_InputD = 0; } } } } //=Local Class= //Common import flash.display.*; import flash.events.*; //Debug import flash.text.*; import flash.ui.*; import flash.utils.*; //Input import flash.ui.Keyboard; //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.*; //=3次元ベクトル= class CVector { //メンバ public var x:Number = 0; public var y:Number = 0; public var z:Number = 0; //コンストラクタ public function CVector(in_x:Number = 0, in_y:Number = 0, in_z:Number = 0):void{ x = in_x; y = in_y; z = in_z; } //長さ public function Length():Number{ return Math.sqrt(x*x + y*y + z*z); } //=各種オペレータ= //本体には影響を与えない //vecA + vecB の代わりに vecA.Plus(vecB) とやる感じ //あるいは vecA.Dot(vecB) の延長で vecA.Plus(vecB) がある感じ //和 public function Plus(rhs:CVector):CVector{ return new CVector(x + rhs.x, y + rhs.y, z + rhs.z); } //差 public function Minus(rhs:CVector):CVector{ return new CVector(x - rhs.x, y - rhs.y, z - rhs.z); } //内積 public function Dot(rhs:CVector):Number{ return x * rhs.x + y * rhs.y + z * rhs.z; } //外積 public function Cross(rhs:CVector):CVector{ return new CVector(y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x); } //スケール public function Scale(scl:Number):CVector{ return new CVector(x * scl, y * scl, z * scl); } //正規化 public function Normal():CVector{ var distance:Number = Length(); if(distance > 0.0){ return new CVector(x/distance, y/distance, z/distance); } return new CVector(0, 0, 0);//err } //線形補間 public function Lerp(rhs:CVector, ratio:Number):CVector{ //this * (1 - ratio) + rhs * ratio return Scale(1.0 - ratio).Plus(rhs.Scale(ratio)); } //値の比較 public function Equals(rhs:CVector):Boolean{ return (x == rhs.x) && (y == rhs.y) && (z == rhs.z); } } //=ブロックの配置= var BLOCK_DATA:Array = [ [ [0, 0, 1, 0, 0], [0, 1, 1, 1, 0], [1, 1, 1, 1, 1], [0, 1, 1, 1, 0], [0, 0, 1, 0, 0], ], [ [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ], /* [ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ], //*/ ]; //=ブロックの管理と衝突管理(できれば分けたい)= class BlockManager 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; //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 = 10; private const SPHERE_INIT_Z:Number = 20; private const SPHERE_RAD:Number = 8; private const CAMERA_DISTANCE:Number = 400; private const GRAVITY:Number = 10.0; //ブロックの幅 private const W:int = 20; private const H:int = 20; private const D:int = 20; //Constructor public function BlockManager():void { {//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.x = 50; m_Camera.y = 50; m_Camera.z = 0; m_Camera.focus = 500; m_Camera.zoom = 1; } {//m_RootNode // ルートノードを作る m_RootNode = new DisplayObject3D(); m_Scene.addChild(m_RootNode); } {//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); } //ブロックの描画の登録と、その境界線上にコリジョン配置 //配列の中心が原点に来るようにする var centerPos:CVector = new CVector(0.5*W * BLOCK_DATA[0][0].length, 0.5*H * BLOCK_DATA.length, 0.5*D * BLOCK_DATA[0].length); BLOCK_DATA.forEach( function(innerArray:Array, indexY:int, array:Array):void{ innerArray.forEach( function(innerArray2:Array, indexZ:int, array:Array):void{ innerArray2.forEach( function(val:int, indexX:int, array2:Array):void{ //境界線上に描画面とコリジョンを配置(端が抜けているが、今回は気にしない) var pos:CVector; var axis:CVector; if(indexX > 0){ if(BLOCK_DATA[indexY][indexZ][indexX-1] != val){ pos = (new CVector(W * (indexX), H * (indexY+0.5), D * (indexZ+0.5))).Minus(centerPos); axis = new CVector(0, 1, 0); // m_PlaneCollisionList.push(new CollisionLine(pos, axis, H)); //描画用の面 m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xCCCCFF), D, H, 8); obj.x = pos.x; obj.y = pos.y; obj.z = pos.z; if(val == 1){ obj.rotationY = 90; }else{ obj.rotationY = -90; } return obj; }() ); } if(indexX == BLOCK_DATA[0][0].length-1){ if(val == 1){ pos = (new CVector(W * (indexX+1), H * (indexY+0.5), D * (indexZ+0.5))).Minus(centerPos); axis = new CVector(0, 1, 0); // m_PlaneCollisionList.push(new CollisionLine(pos, axis, W)); //描画用の面 m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xCCCCFF), D, H, 8); obj.x = pos.x; obj.y = pos.y; obj.z = pos.z; obj.rotationY = -90; return obj; }() ); } } }else{ if(val == 1){ pos = (new CVector(W * (indexX), H * (indexY+0.5), D * (indexZ+0.5))).Minus(centerPos); axis = new CVector(0, 1, 0); // m_PlaneCollisionList.push(new CollisionLine(pos, axis, H)); //描画用の面 m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xCCCCFF), D, H, 8); obj.x = pos.x; obj.y = pos.y; obj.z = pos.z; obj.rotationY = 90; return obj; }() ); } } if(indexY > 0){ if(BLOCK_DATA[indexY-1][indexZ][indexX] != val){ pos = (new CVector(W * (indexX+0.5), H * (indexY), D * (indexZ+0.5))).Minus(centerPos); axis = new CVector(1, 0, 0); // m_PlaneCollisionList.push(new CollisionLine(pos, axis, W)); //描画用の面 m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xCCFFCC), W, D, 8); obj.x = pos.x; obj.y = pos.y; obj.z = pos.z; if(val == 1){ obj.rotationX = 90; }else{ obj.rotationX = -90; } return obj; }() ); } if(indexY == BLOCK_DATA.length-1){ if(val == 1){ pos = (new CVector(W * (indexX+0.5), H * (indexY+1), D * (indexZ+0.5))).Minus(centerPos); axis = new CVector(1, 0, 0); // m_PlaneCollisionList.push(new CollisionLine(pos, axis, W)); //描画用の面 m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xCCFFCC), W, D, 8); obj.x = pos.x; obj.y = pos.y; obj.z = pos.z; obj.rotationX = -90; return obj; }() ); } } }else{ if(val == 1){ pos = (new CVector(W * (indexX+0.5), H * (indexY), D * (indexZ+0.5))).Minus(centerPos); axis = new CVector(1, 0, 0); // m_PlaneCollisionList.push(new CollisionLine(pos, axis, W)); //描画用の面 m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xCCFFCC), W, D, 8); obj.x = pos.x; obj.y = pos.y; obj.z = pos.z; obj.rotationX = 90; return obj; }() ); } } if(indexZ > 0){ if(BLOCK_DATA[indexY][indexZ-1][indexX] != val){ pos = (new CVector(W * (indexX+0.5), H * (indexY+0.5), D * (indexZ))).Minus(centerPos); axis = new CVector(0, 0, 1); // m_PlaneCollisionList.push(new CollisionLine(pos, axis, W)); //描画用の面 m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xFFCCCC), W, H, 8); obj.x = pos.x; obj.y = pos.y; obj.z = pos.z; if(val == 1){ }else{ obj.rotationX = 180; } return obj; }() ); } if(indexZ == BLOCK_DATA[0].length-1){ if(val == 1){ pos = (new CVector(W * (indexX+0.5), H * (indexY+0.5), D * (indexZ+1))).Minus(centerPos); axis = new CVector(0, 0, 1); // m_PlaneCollisionList.push(new CollisionLine(pos, axis, W)); //描画用の面 m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xFFCCCC), W, H, 8); obj.x = pos.x; obj.y = pos.y; obj.z = pos.z; obj.rotationX = -180; return obj; }() ); } } }else{ if(val == 1){ pos = (new CVector(W * (indexX+0.5), H * (indexY+0.5), D * (indexZ))).Minus(centerPos); axis = new CVector(0, 0, 1); // m_PlaneCollisionList.push(new CollisionLine(pos, axis, W)); //描画用の面 m_RootNode.addChild( function():DisplayObject3D { var obj:DisplayObject3D = new Plane(new ColorMaterial(0xFFCCCC), W, H, 8); obj.x = pos.x; obj.y = pos.y; obj.z = pos.z; // obj.rotationX = 180; return obj; }() ); } } } ); } ); } ); } } public function UpdateCollision():void{ } private var m_CameraRot:Number = 0;//カメラ回転用 //描画 public function Render():void{ //カメラを回転させてみる m_CameraRot += 0.1; m_Camera.x = 50 * Math.cos(m_CameraRot); m_Camera.z = 50 * Math.sin(m_CameraRot); //描画 m_Scene.renderCamera(m_Camera); } }