【JavaFX:横スクロールアクションゲーム】キャラとブロック縦並び時の判定と壁に当たった時の特殊動作

Ver1.00のブロック判定記事でやったことの続きを実装します。

前の記事 横スクロールアクションゲームTop 次の記事

今回はブロックを縦に並べても大丈夫なようにしてみましょう。



縦に並べてもうまく処理させるには

前回の判定記事で、うまくいかなかった理由を考えてみます。

上に押し上げる判定や下に押し下げる判定を優先にしているがために、そちらの処理が適用されてしまって、空中に浮かんだり、ジャンプ時に引っかかってしまうわけですね。

ということは、押し出し先にブロックがある場合は上下の判定をしないようにすれば、引っかかりの現象は直りそうです。

ブロックの周りにブロックがあるか調べる

ブロックの周りに(上下左右)にブロックがあるかどうかを判定しましょう。

判定するには、二次元配列上の上(縦-1)下(縦+1)左(横-1)右(横+1)にブロックオブジェクトが存在するかを調べます。

一応今回は4ブロック全部渡しますが、実際には左右は使いませんので上下の2ブロックだけでも問題ありません。

それでは、調べた4方向のフラグをsinkingReviseメソッドに渡します。


	//ブロックに衝突していた場合に隣接ブロックが上下左右にあるかどうかを保持する
	AdjoinBlockInfo info = new AdjoinBlockInfo();
	class AdjoinBlockInfo{
		boolean up;
		boolean bottom;
		boolean right;
		boolean left;
	}

	//キャラクタのフィールド位置チェックを行い補正する
	public void fieldCheck(CharaObject chara) {
		//キャラクタがフィールドのブロックオブジェクトと当たっているか判定し、当たっていたら押し戻す処理
		Node node = chara.getHitNode();
		Bounds b = node.getBoundsInParent();

		//判定対象となるブロックインデックスを算出(開始地点から終了地点)
		int sx = (int)b.getMinX() / Block.W;
		int sy = (int)b.getMinY() / Block.H;
		int ex = (int)b.getMaxX() / Block.W;
		int ey = (int)b.getMaxY() / Block.H;

		//インデックスが配列を越えていた場合は端点に修正
		if ( sx < 0 ) sx = 0;
		if ( sy < 0 ) sy = 0;
		if ( ex < 0 ) ex = 0;
		if ( ey < 0 ) ey = 0;
		if ( sx >= fields[0].length ) sx = fields[0].length - 1;
		if ( sy >= fields.length ) sy = fields.length - 1;
		if ( ex >= fields[0].length ) ex = fields[0].length - 1;
		if ( ey >= fields.length ) ey = fields.length - 1;

		//地上、空中、壁判定フラグを無衝突状態に初期化
		chara.isAir = true;
		chara.isGround = false;
		chara.isWall = false;

		//画面端である場合は壁に当たったものとする
		if ( b.getMaxX() > maxX ) {
			chara.moveX(maxX - b.getMaxX());
			chara.isWall = true;
		}
		if ( b.getMinX() < minX ) {
			chara.moveX(minX - b.getMinX());
			chara.isWall = true;
		}

		for ( int i = sy;i <= ey;i++ ) {
			for ( int j = sx;j <= ex;j++ ) {
				Field block = fields[i][j];
				if ( block != null && block.isHit(chara) ) {
					//隣接ブロックの有無
					info.up = false;
					info.right = false;
					info.bottom = false;
					info.left = false;
					if( getData(i-1,j).TYPE == ObjectType.BLOCK ) info.up = true;
					if( getData(i,j+1).TYPE == ObjectType.BLOCK ) info.right = true;
					if( getData(i+1,j).TYPE == ObjectType.BLOCK ) info.bottom = true;
					if( getData(i,j-1).TYPE == ObjectType.BLOCK ) info.left = true;

					//ブロックにめり込んだらめり込んだ分戻す
					block.sinkingRevise(chara, info);
				}
			}
		}
	}

後はsinkingReviseでこのフラグを見て上下移動に制限をかけましょう。



ブロック存在フラグを追加した後の判定処理

それでは実際に押し戻しの処理に手を加えます。

	//ブロックにめり込んだキャラクタを押し出すメソッド
	@Override
	public void sinkingRevise(CharaObject mv, AdjoinBlockInfo info) {

		//当たり判定オブジェクトの取得
		Node node = getHitNode();
		Node mvNode = mv.getHitNode();
		Bounds b = node.getBoundsInParent();
		Bounds mvb = mvNode.getBoundsInParent();

		if ( mv.preb <= b.getMinY() && !info.up ) {
			//キャラがブロックの上側から突っ込んだ場合めり込んだ分キャラを上にずらす
			//ただし、その上に別のブロックがある場合は押し上げない
			mv.moveY(-(mvb.getMaxY() - b.getMinY()));
			mv.isGround = true;
		} else if ( mv.pret >= b.getMaxY() && !info.bottom ) {
			//キャラがブロックの下側から突っ込んだ場合めり込んだ分キャラを下にずらす
			//ただし、その下に別のブロックがある場合は押し下げない
			mv.moveY(b.getMaxY() - mvb.getMinY());
		} else if ( mv.prer <= b.getMinX() ) {
			//キャラがブロックの左側から突っ込んだ場合めり込んだ分キャラを左にずらす
			mv.moveX(-(mvb.getMaxX() - b.getMinX()));
			mv.isWall = true;
		} else if ( mv.prel >= b.getMaxX() ) {
			//キャラがブロックの右側から突っ込んだ場合めり込んだ分キャラを右にずらす
			mv.moveX(b.getMaxX() - mvb.getMinX());
			mv.isWall = true;
		}

		//地上ではない場合は空中
		mv.isAir=!mv.isGround;
	}

修正した部分は11行目の!info.upの条件と16行目の!info.bottomです。

if ( mv.preb <= b.getMinY() && !info.up ) {
} else if ( mv.pret >= b.getMaxY() && !info.bottom ) {

他にもver1.00からの違いとして、右から突っ込んだときの判定と、左右から突っ込んできた場合に壁に当たったフラグを経てるように修正しました。

敵が壁を乗り越えてくる処理を実装

壁に当たったフラグを制御するようになりましたので、敵キャラが壁を乗り越えてくる処理などを実装するのが簡単になりました。

壁に当たったときはisWallフラグがtrueなのですぐに実装できますね。

例えば敵キャラのmoveメソッドを下記のように実装すると壁に当たった時にジャンプで乗り越えて来るようになります。



	@Override
	public void move() {
		if ( isGround ) {
			//地上だったら落下速度0
			fallSpeed = 0;

			//壁に当たったらジャンプ
			if ( isWall ) {
				//ジャンプしたなら落下速度を逆にする
				fallSpeed = -12;
			}
		} else if ( isAir ) {
			//空中だったら落下速度アップ
			fallSpeed++;
		}

		//上下移動処理
		moveY(fallSpeed);

		//左右移動
		moveX(speed);
	}

さて、それではVer1.10の記事は今回で最後にしたいと思いますので、完成ゲームのプレイ動画を乗っけて終わります。

ソースコードはこちらからどうぞ

JavaJavaFX

Posted by nompor