メモ

衝突判定の組込み中。まだ途中。ひとまず現状のを上げる。今週末ぐらいにはできあがるかな。

//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;
			}
		}
	}
}


休日だから一日中できるかと思ったけど、意外と時間を割けなかった。無念。