メモ
衝突判定の組込み中。まだ途中。ひとまず現状のを上げる。今週末ぐらいにはできあがるかな。
//mxmlc Main.as //author Show=O=Healer package { //Common import flash.display.*; import flash.events.*; //PV3D import org.papervision3d.core.*; //Class public class Main extends Sprite { //Common private var m_Container : Sprite; //Param private const GRAVITY:Number = 10.0; //Constructor public function Main():void { {//Init Common //リサイズ対応 stage.addEventListener(Event.RESIZE, onStageResize); //定期的にupdateを呼ばせる addEventListener(Event.ENTER_FRAME, update); } addChild(new BlockManager()); } //=Common= private function update( event:Event ):void { } private function onStageResize(event:Event):void { m_Container.x = stage.stageWidth / 2; m_Container.y = stage.stageHeight / 2; } } } //=Local Class= import flash.display.*; class CollisionSphere { public var m_CollisionPos:Number3D; public var m_CollisionVel:Number3D = new Number3D(0.0, 0.0, 0.0); public var m_CollisionAcc:Number3D = new Number3D(0.0, 0.0, 0.0); public var m_CollisionRad:Number;//半径 public function CollisionSphere(in_X:Number, in_Y:Number, in_R:Number):void { m_CollisionPos = new Number3D(in_X, in_Y, 0.0); m_CollisionRad = in_R; } } class CollisionBox { public var m_CollisionPos:Number3D; public var m_CollisionVel:Number3D = new Number3D(0.0, 0.0, 0.0); public var m_CollisionAcc:Number3D = new Number3D(0.0, 0.0, 0.0); public var m_CollisionW:Number;//幅(端から端まで) public var m_CollisionH:Number;//高さ(端から端まで) public function CollisionBox(in_X:Number, in_Y:Number, in_W:Number, in_H:Number):void { m_CollisionPos = new Number3D(in_X, in_Y, 0.0); m_CollisionW = in_W; m_CollisionH = in_H; } } var BLOCK_DATA:Array = [ [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 1, 0], [0, 0, 0, 1, 1], [0, 1, 0, 1, 1], [0, 1, 1, 1, 1], [1, 1, 1, 1, 1] ]; //BLOCK_DATAをもとにBlockを生成 class BlockManager extends Sprite { private var m_PlayerSphere:CollisionSphere = new CollisionSphere(5.0, 5.0, 4.0); private var m_BlockCollisionList:Array = new Array(); //Param private const W:int = 10; private const H:int = 10; public function BlockManager():void { BLOCK_DATA.forEach( function(innerArray:Array, indexY:int, array:Array):void{ innerArray.forEach( function(val:int, indexX:int, array2:Array):void{ if(val == 1){ CreateBlock(indexX, indexY); m_BlockCollisionList.push(new CollisionBox(0.5*W + W*indexX, 0.5*H + H*indexY, W, H)); } } ); } ); } //指定箇所にブロックを作成 public function CreateBlock(x:int, y:int):void{ var block:Sprite = new Sprite(); block.graphics.lineStyle(1, 0x4b2503, 1.0); block.graphics.beginFill(0x8b4513); block.graphics.drawRect(-0.5*W, -0.5*H, W, H); block.graphics.endFill(); block.x = 0.5*W + W * x; block.y = 0.5*H + H * y; addChild(block); } // public UpdateCollision():void{ var deltaTime:Number = 1.0/60.0; { var sphere:CollisionSphere = m_PlayerSphere; var sphereRad:Number = sphere.m_CollisionRad; var restTime = deltaTime; var nowPos:Number3D = sphere.m_CollisionPos; var nowVel:Number3D = sphere.m_CollisionVel; var nowAcc:Number3D = sphere.m_CollisionAcc; for(;;)//continueでここまで戻ってきてもう一度処理する { //ここのループにカウンタを仕込めば、「N回だけ跳ね返りを考慮する」というのができる。 //ただ、その場合はすり抜けるかもしれない var nextPos:Number3D = nowPos + nowVel * restTime + 0.5 * nowAcc * restTime * restTime; var nextVel:Number3D = nowVel + nowAcc * restTime; var hitBlock:CollisionBlock = null; var hitTime:Number = restTime; var hitPos:Number3D; var hitVel:Number3D; m_BlockCollisionList.forEach( function(in_BlockCollision:CollisionBox, index:int, arr:Array){ //=ブロックと球の相対的な移動量を求める(ブロックをベースとする)= //ブロックにとっての前後上下左右の軸 var axisX:Number3D = new Number3D(1.0, 0.0, 0.0); var axisY:Number3D = new Number3D(0.0, 1.0, 0.0); // var axisZ:Number3D = new Number3D(0.0, 0.0, 1.0); //ブロックと球の相対位置 var nowGap:Number3D = Number3D.sub(nowPos, in_BlockCollision.m_CollisionPos); var nextGap:Number3D = Number3D.sub(nextPos, in_BlockCollision.m_CollisionPos); //各軸における相対差 var nowGapX:Number = Number3D.dot(axisX, nowGap); var nowGapY:Number = Number3D.dot(axisY, nowGap); // var nowGapZ:Number = Number3D.dot(axisZ, nowGap); var nextGapX:Number = Number3D.dot(axisX, nextGap); var nextGapY:Number = Number3D.dot(axisY, nextGap); // var nextGapZ:Number = Number3D.dot(axisZ, nextGap); //=衝突判定= //完全に範囲外となるなら、ここでヒットしないと判定して終了 if(nowGapX < -0.5*W - sphereRad && nextGapX < -0.5*W - sphereRad){return;} if(nowGapX > 0.5*W + sphereRad && nextGapX > 0.5*W + sphereRad){return;} if(nowGapY < -0.5*H - sphereRad && nextGapY < -0.5*H - sphereRad){return;} if(nowGapY > 0.5*H + sphereRad && nextGapY > 0.5*H + sphereRad){return;} // if(nowGapZ < -0.5*D - sphereRad && nextGapZ < -0.5*D - sphereRad){return;} // if(nowGapZ > 0.5*D + sphereRad && nextGapZ > 0.5*D + sphereRad){return;} //ブロックの各面に対して衝突判定を行う var contactPos:Number3D;//交点の座標 var movePos:Number3D = Number3D.sub(nextGap - nowGap); var scale:Number; if(nowGapX - nextGapX > 0.0){ //この面を通るとして、どの点を通るか // contactPos = nowPos + movePos * (nowGapX - W)/(movePos.Dot(axisX)); scale = (nowGapX - (W+sphereRad))/(movePos.Dot(axisX)); contactPos = Number3D.add(nowPos, new Number3D(movePos.x * scale, movePos.y * scale, movePos.z * scale)); //その点が内側の方を通るなら、単純に逆方向に反発 //外側ぎりぎりなら、球と点の衝突判定として計算しなおす } if(nowGapX - nextGapX < 0.0){ //逆サイドの面 } //!! } ); //何かとぶつかっていたら、新しい位置と方向を元に再び処理を開始 if(hitBlock != null){ restTime -= hitTime; nowPos = hitPos; nowVel = hitVel; continue; } //ぶつかっていなければ、求めた移動先に移動して終了 sphere.m_CollisionPos = nextPos; sphere.m_CollisionVel = nextVel; break; } } } }
休日だから一日中できるかと思ったけど、意外と時間を割けなかった。無念。