var MovableStageObjectClass = function(stage, args)
{
	MovableStageObjectClass.base.apply(this, arguments);

	this.movingSpeed = new Point2D(0, 0);
	//2 * hysteresis >= movingFrictionであることを推奨する。
	//そうでない場合、摩擦での減速後に完全に停止できない可能性がある。
	//this.movingFriction = 1000;
	//this.hysteresis = this.movingFriction/ 60;
	// 現在このオブジェクトが設置しているかを確認するには ( (instance) .collideFlag & 4) != 0 とする
	// 重力がなくなったらこの方法では接地を検出できなくなるがそれは
	//this.collideFlag = 0;
	// この物体に働く重力(物体別にそれぞれ指定可、マイナス値指定可)
	//this.gravity = 800;	
	//段差や坂を乗り越えられるレベル 0だと坂を全く上れない
	this.caterpillar = 2.5;
	this.antigravity = 0;
	this.isItemCollector = false;
	this.inWater = false;
	this.onLadder = false;
	this.collectedItems = new Array();

}.extend(StageObject, {
	className: "MovableStageObjectClass",
	tick: function(){
		//抵抗処理
		//運動処理
		if(this.ownerUID == 0 || this.ownerUID == this.ownerStage.manager.userID){
			this.moveTo(
				this.origin.x + (this.movingSpeed.x / this.ownerStage.manager.tickPerSecond),
				this.origin.y + (this.movingSpeed.y / this.ownerStage.manager.tickPerSecond)
			);
		}
		//取得
		this.checkTouchingDirection();
		
	},
	canMoveTo: function(x, y){
		//すべてのオブジェクトに対して(x, y)にあるときの自分の衝突状態を調べる。
		var retv = true;
		var d = this.ownerStage.stageObjectLinearList;
		
		this.onLadder = false;
		for(var i = 0, i_max = d.length; i < i_max; i++){
			var f = d[i];
			if(f !== this){
				//自分でない
				if(f.isOverlappedWithLocatedObject(this, x, y)){
					//衝突先fの衝突範囲内にいる
					if(this.isItemCollector){
						//衝突先fを取得したアイテムに加える。
						var titem = null;
						for(titem in this.collectedItems){
							//複数追加の防止
							if(titem == f){
								break;
							}
						}
						if(titem != f){
							this.collectedItems.push(f);
							if(f instanceof LadderBlockClass){
								this.onLadder = true;
							}
						}
					}
					if(f.isPhantom){
						//衝突先fが衝突判定無視だったら、衝突はしない
					} else{
						//衝突した
						retv = false;
						//break;
					}
					
				}
			}
		}
		return retv;
	},
	moveTo : function(x, y) {
		//現在の座標から(x,y)に向けて、移動できるだけ移動する。
		//衝突方向フラグも設定する。
		this.collectedItems = new Array();
		if(!this.originDetail) this.originDetail = new Point2D(this.origin.x, this.origin.y);
		
		var sx = this.originDetail.x;				//sx, sy : 自分の元の座標
		var sy = this.originDetail.y;
		var lx = x - sx;				//lx, ly : 目的地までの移動距離(マイナス可)
		var ly = y - sy;
		//移動距離をどちらか一軸ではかる
		var ct = Math.ceil(Math.max(Math.abs(lx), Math.abs(ly)));	
		//移動しない軸があるかどうか（高速化）
		var fx = (lx == 0);
		var fy = (ly == 0);
		//実際に移動する先の座標
		var ex = sx;					//ex, ey : 現在移動できることが確認されている位置
		var ey = sy;
		//ctを基準にした一単位当たりの移動量
		var dx = lx / ct;				//dx, dy : 一回当たりの移動量(マイナス可）
		var dy = ly / ct;
		//段差を乗り越える係数
		var c = Math.abs(this.caterpillar * dx);
		var gx = sx, gy = sy;
		
		var collidedDirection = 0;	//相手が受けた衝突の方向
		var collideDirection = 0;	//自分が受けた衝突の方向

		if(!(fx && fy)){
			for(var i = 0; i < ct; i++){
				if(!fx && !this.canMoveTo(getRoughVal(ex + dx, lx<0), getRoughVal(ey, ly<0))){
					//caterpillarの高さを足して移動できるか試してみる
					if(c != 0 && !this.canMoveTo(getRoughVal(ex + dx, lx<0), getRoughVal(ey - c, ly<0))){
							//それでもx軸が衝突したので移動を停止しフラグをセットする
							fx = true;
							this.movingSpeed.x = 0;
							collidedDirection |= lx > 0 ? CollideLeft : CollideRight;
							collideDirection  |= lx < 0 ? CollideLeft : CollideRight;
					} else{
						//高さを変えれば移動できるので高さを変えて継続する
						ey -= c;
					}
				}
				if(!fy && !this.canMoveTo(getRoughVal(ex, lx<0), getRoughVal(ey + dy, ly<0))){
					//y軸が衝突したので移動を停止しフラグをセットする。
					fy = true;
					this.movingSpeed.y = 0;
					collidedDirection |= ly > 0 ? CollideTop : CollideBottom;
					collideDirection  |= ly < 0 ? CollideTop : CollideBottom;
				}
				if(!fx){
					//explusdx = ex + dx;
					ex += dx;
				}
				if(!fy){
					//eyplusdy = ey + dy;
					ey += dy;
				}else if(fx){
					// fx && fy であればこれ以上ループしても意味ないので抜ける
					break;
				}
			}
		}
		
		//移動
		
		this.originDetail.x = ex;
		this.originDetail.y = ey;
		
		ex = getRoughVal(ex, lx>0);
		ey = getRoughVal(ey, ly>0);

		this.origin.x = ex;
		this.origin.y = ey;
		
		var myObjectAttackedExists = this.objectAttacked != undefined;
				
		for(var i in this.collectedItems){
			var item = this.collectedItems[i];
			if(myObjectAttackedExists){
				this.objectAttacked(item, item.origin.x, item.origin.y, collideDirection);
			}
			if(item.objectAttacked){
				//アイテムに対して取得されたことを通知する。(取得したオブジェクトのインスタンスおよび座標）
				item.objectAttacked(this, ex, ey, collidedDirection);
			}
		}
		return;
	},
});

function getRoughVal(val, cutUp)
{
	return cutUp ? Math.floor(val) : Math.ceil(val);
}
