【JavaFX:横スクロールアクションゲーム】スクロールを実装

2018年8月22日

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

ゲームのスクロールの実装は以前カメラの実装時に説明した内容で実装します。

上記で説明した内容+カメラの移動有効範囲を設定しましょう。

カメラの移動有効範囲は固定値で持たせておきます。

処理は事前に移動予定座標を計算しておき、その有効範囲を超えていたら、移動予定の座標を有効範囲の値で上書きし、そこまで移動させます。有効範囲内であれば、そのまま移動させます。

実装するとしたらこんな計算になるでしょうか。

if ( rx < minX ) {
	rx = minX;
} else if ( rx + width > maxX ) {
	rx = maxX - width;
}
if ( ry < minY ) {
	ry = minY;
} else if ( ry + height > maxY ) {
	ry = maxY - height;
}
setTranslateX(rx);
setTranslateY(ry);

変数rx,ryは移動先の座標が入っているものとします。

width,heightはカメラの表示領域の幅です。

ライブラリに上記を実現するためのカメラクラスを入れてあるので、そいつにプレイヤーキャラを引数に引き渡すと使用できます。

中身の実装はJavaFXのCameraクラスに小細工をしてターゲットオブジェクトに追従して移動するようにしています。

FixedTargetCamera2DFX.createRangeCamera(
ウィンドウ横幅, ウィンドウ縦幅
, カメラのターゲットオブジェクト
, スクロール最小X座標, スクロール最小y座標, スクロール最大X座標, スクロール最大y座標
);

例えばターゲットオブジェクトの引数を敵にすると敵に追従するようになります。

それでは、スクロールのテストサンプルを実装してみます。縦スクロールもできるよう実装してるので、上下左右スクロール可能なサンプルになっています。

import com.nompor.gtk.fx.FixedTargetCamera2DFX;
import com.nompor.gtk.fx.GTKManagerFX;
import com.nompor.gtk.fx.GameViewFX;

import javafx.application.Application;
import javafx.stage.Stage;

public class Test4 extends Application {

	public static void main(String[] args) {
		launch(args);
	}

	@Override
	public void start(Stage primaryStage) throws Exception {
		final int WIDTH = 800, HEIGHT = 600;
		GTKManagerFX.start(primaryStage,WIDTH, HEIGHT);

		//GameViewFXはGroupを継承したクラスで、processメソッドはゲームループの処理を実装する
		GTKManagerFX.changeView(new GameViewFX() {
			Player p;
			Enemy e;
			GameField fields;

			@Override
			public void start() {

				//ワールド領域2000*1200に合わせて二次元配列構築
				final int MAX_W=2000,MAX_H=1200;
				final int ROW=MAX_H/50,COL=MAX_W/50;
				Field[][] field = new Field[ROW][COL];

				//画面一番下に地面ブロック配置
				final int UNDER_INDEX = (ROW-1);
				for ( int i = 0;i < COL;i++ ) {
					field[UNDER_INDEX][i] = FieldObjectAppearanceObserverFactory.createBlock(FieldObject.GROUND, i * 50,UNDER_INDEX*50);
				}

				//ブロックはテスト用に適当に追加
				for ( int i = 0;i < 5;i++ ) {
					field[10][i] = FieldObjectAppearanceObserverFactory.createBlock(FieldObject.BLOCK, i * 50,10*50);
				}

				for ( int i = 6;i < 12;i++ ) {
					field[15][i] = FieldObjectAppearanceObserverFactory.createBlock(FieldObject.BLOCK, i * 50,15*50);
				}

				for ( int i = 18;i < 25;i++ ) {
					field[ROW-3][i] = FieldObjectAppearanceObserverFactory.createBlock(FieldObject.BLOCK, i * 50,(ROW-3)*50);
				}

				//GameFieldオブジェクトの構築
				fields = new GameField(field);
				Field[][] fieldList = fields.getFieldList();
				for ( int i = 0;i < fieldList.length;i++ ) {
					for ( int j = 0;j < fieldList[i].length;j++ ) {
						Field fld = fieldList[i][j];
						if ( fld != null ) {
							getChildren().add(fld.getViewNode());
						}
					}
				}

				//プレイヤーの作成
				p = FieldObjectAppearanceObserverFactory.createPlayer();

				//プレイヤーの表示
				getChildren().add(p.getViewNode());

				//敵の作成
				e = FieldObjectAppearanceObserverFactory.createEnemy(FieldObject.SLIME,300,50);

				//敵表示
				getChildren().add(e.getViewNode());

				//カメラのセッティング
				GTKManagerFX.setGameCamera(
						FixedTargetCamera2DFX.createRangeCamera(
								WIDTH, HEIGHT
								,p
								, 0, 0, MAX_W, MAX_H
						)
				);
			}

			@Override
			public void process() {
				//ゲームループ

				p.update();
				e.update();

				fields.fieldCheck(p);
				fields.fieldCheck(e);
			}
		});
	}

}
実行結果

全ソース

JavaJavaFX

Posted by nompor