画像(logo)

HOME/[JAVA言語]ブロックパズルの作り方 目次/四日目 当たり判定「壁」

[JAVA言語 ブロックパズルの作り方]
四日目 当たり判定「壁」

広告

↓2017年04月19日発売↓

カラー図解 Javaで始めるプログラミング 知識ゼロからの定番言語「超」入門 (ブルーバックス)

新品価格
¥1,080から
(2017/5/1 13:45時点)

目次へ戻る

当たり判定

当たり判定のお時間です!今回は横に移動するのと壁の当たり判定を確認する所までやっていきます。

キー入力

まずは横に動かすためのキー入力の簡単なプログラムを作ってみます。

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.animation.AnimationTimer;
import javafx.scene.input.KeyEvent;
import javafx.event.EventHandler;

public class B_PMain extends Application{
	private B_PThread b_pthread;
	private Key key;

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

	@Override
	public void start(Stage stage){
		stage.setTitle("BLOCK PUZZLE");
		Pane pane = new Pane();
		Scene scene = new Scene(pane);
		stage.setScene(scene);

		Canvas canvas = new Canvas(640,480);
		GraphicsContext gc = canvas.getGraphicsContext2D();
		pane.getChildren().add(canvas);

		key = new Key();

		scene.setOnKeyPressed(
			new EventHandler<KeyEvent>(){
				public void handle(KeyEvent e){
					key.key_pressed(e);
				}
			}
		);

		scene.setOnKeyReleased(
			new EventHandler<KeyEvent>(){
				public void handle(KeyEvent e){
					key.key_released(e);
				}
			}
		);

		b_pthread = new B_PThread(gc,key);
		b_pthread.start();

		stage.show();
	}
}

class B_PThread extends AnimationTimer{
	private GraphicsContext gc;
	private Key key;

	/*変数の宣言などを書いていく*/

	B_PThread(GraphicsContext gc,Key key){
		this.gc = gc;
		this.key = key;

		/*コンストラクタ*/
		/*最初の1回だけ実行されるので初期化などを書く*/
	}

	@Override
	public void handle(long time){
		gc.clearRect(0,0,640,480);

		/*ゲームループ*/
		/*この部分がすごい速さで繰り返される*/
		/*メインプログラムを書く*/

		key.calc_key_count();

		gc.fillText("左 = " + key.get_left(),450,450);
		gc.fillText("右 = " + key.get_right(),450,470);
	}

	/*この後に追加の自作メソッドなどを書いていく*/
}

class Key{
	private boolean left,right;
	private int left_count,right_count;

	Key(){
		left = false;
		right = false;
		left_count = 0;
		right_count = 0;
	}

	void key_pressed(KeyEvent e){
		switch(e.getCode()){
		case LEFT:
			left = true;
			break;
		case RIGHT:
			right = true;
			break;
		default:
			break;
		}
	}

	void key_released(KeyEvent e){
		switch(e.getCode()){
		case LEFT:
			left = false;
			break;
		case RIGHT:
			right = false;
			break;
		default:
			break;
		}
	}
	
	void calc_key_count(){
		if(left)left_count++;
		else left_count = 0;

		if(right)right_count++;
		else right_count = 0;
	}

	int get_left(){
		return left_count;
	}
	int get_right(){
		return right_count;
	}
}

■実行結果■

画像(jb_4_1)

キー入力を確認するためのプログラムです。

わかりやすいように土台のプログラムにキー入力の部分を加えております。

矢印キーの「左←」か「右→」を押すと反応するようになってます。

入力状態を取得

まずキーが押されたかどうかの入力状態を取得するには

import javafx.scene.input.KeyEvent;
import javafx.event.EventHandler;

こちらをインポートした上で

scene.setOnKeyPressed(
	new EventHandler<KeyEvent>(){
		public void handle(KeyEvent e){
			switch(e.getCode()){
			case LEFT:
				/*左が押された時の処理*/
				break;
			case RIGHT:
				/*右が押された時の処理*/
				break;
			}
			default:
				break;
			}
		}
	}
);

こちらを書くだけで取得できます。

「setOnKeyPressed」→キーが押された時って事ですね。

細かい事はイベントハンドラがどうしたとか多少めんどくさい話になるのでこのカタマリのまま覚えてしまいましょう。

「LEFT」・・・左

「UP」・・・上

「RIGHT」・・・右

「DOWN」・・・下

「Z」・・・Z

「H」・・・H

「ENTER」・・・エンター

とりあえず今回使用するキーの定数になります。

他のキーに関しては「java fx keyevent リファレンス」などで検索してみてください。

広告

押しっぱなし、ちょい押し

上記の方法だけでもキー入力は取得できますが、押しっぱなした時や少しだけ押された時などの微妙なニュアンスのキー入力処理ができません。

そこで少し工夫したものが次のクラスになります。

class Key{
	private boolean left,right;
	private int left_count,right_count;

	Key(){
		left = false;
		right = false;
		left_count = 0;
		right_count = 0;
	}

	void key_pressed(KeyEvent e){
		switch(e.getCode()){
		case LEFT:
			left = true;
			break;
		case RIGHT:
			right = true;
			break;
		default:
			break;
		}
	}

	void key_released(KeyEvent e){
		switch(e.getCode()){
		case LEFT:
			left = false;
			break;
		case RIGHT:
			right = false;
			break;
		default:
			break;
		}
	}
	
	void calc_key_count(){
		if(left)left_count++;
		else left_count = 0;

		if(right)right_count++;
		else right_count = 0;
	}

	int get_left(){
		return left_count;
	}
	int get_right(){
		return right_count;
	}
}

押されたキーの状態を数値化して保存しなおすクラス「Key」になります。

押されたキーの状態を数値化する為の変数を用意してキーが押された時はインクリメント、キーが放された時はインクリメントされた数値をもとに戻すみたいなことをしております。

こうする事によってさきほどのプログラムの実行結果のようにキーを少し押せば値が少しだけ上昇し、長押せばその押した分だけ値が上昇するので微妙なキー入力のニュアンスも処理できるようになります!

実際に使う時は

if(key.get_left() > 0){
	/*左が押された時の処理*/
}

のようにすればキーが押されれば即時に反応しますし、

if(key.get_left() > 100){
	/*左が押された時の処理*/
}

長押しした時

if(key.get_left() > 10 && key.get_left() < 30){
	/*左が押された時の処理*/
}

ちょい押しした時

のように細かく入力を処理できます。

当たり判定

キー入力のやり方がわかったので次は当たり判定です。このままだと壁を突き抜けて、どこまででも行ってしまいます。

固まったブロックや壁を保存「stage」

固まったブロックや壁の状態を保存しているのは「stage」でした。

なのでこの「stage」と現在のブロック「block」を調べれば良さそうです。

void my_collision_left(){
	collision_flag = 0;

	for(int y=0;y<BLOCK_HEIGHT;y++){
		for(int x=0;x<BLOCK_WIDTH;x++){
			if(block[y][x] != 0){
				if(stage[block_y + y][block_x + (x - 1)] != 0){
					collision_flag = 1;
				}
				else if((int)(block_y_count - (block_y * DRAW_BLOCK_WIDTH)) > 0){
					if(stage[block_y + (y + 1)][block_x + (x - 1)] != 0){
						collision_flag = 1;
					}
				}
			}
		}
	}
}

ブロックの左側の当たり判定を調べる「my_collision_left()」です。

当たり判定用のフラグとして変数「int collision_flag」を用意してそこに当たり判定の結果を格納します。

そして当たり判定の方法ですが、まずは現在の「block」の状態を調べます。

for(int y=0;y<BLOCK_HEIGHT;y++){
	for(int x=0;x<BLOCK_WIDTH;x++){
		if(block[y][x] != 0){
		}
	}
}

「block」が「0」でなければ、つまりそこがブロックならば今度は「stage」上の現在のブロックの座標周りを調べれば必要な情報が得られます。

if(stage[block_y + y][block_x + (x - 1)] != 0){
	collision_flag = 1;
}

今回は左側の当たり判定なので「x座標 - 1」の部分を調べれば大丈夫ですね!

これだけで基本は大丈夫ですが、マス目の間

画像(jb_4_2)

こんな状態の時の当たり判定も加えないと、画像の例ではもう左側には移動できないのにめり込むようなカタチで移動できてしまいます。

それを防ぐ為の判定部分も作ります。

else if((int)(block_y_count - (block_y * DRAW_BLOCK_WIDTH)) > 0){
	if(stage[block_y + (y + 1)][block_x + (x - 1)] != 0){
		collision_flag = 1;
	}
}

こちらの部分ですね!

まずさきほどの画像のような状態は次の計算で得られます。

if((int)(block_y_count - (block_y * DRAW_BLOCK_WIDTH)) > 0)

実際に落下している場所「block_y_count」からその落下しているマス目分引いたものが「0」以上であれば画像のような状態という事になります。

そしてこの状態というのはマス目でいうトコロの一つ下の部分との当たり判定になるので

if(stage[block_y + (y + 1)][block_x + (x - 1)] != 0){
	collision_flag = 1;
}

stage[block_y + (y + 1)][block_x + (x - 1)]と一つ下の部分の一つ左側の部分を調べれば画像のような状態の当たり判定も大丈夫です!

同じように右側の当たり判定用関数も作ります。

キー入力に当たり判定を組み込む

あとはキー入力時に当たり判定用関数を組み込むだけですね!

void my_move_block(){
	if(key.get_left() % 5 == 1){
		my_collision_left();
		if(collision_flag == 0){
			block_x--;
		}
	}
		
	if(key.get_right() % 5 == 1){
		my_collision_right();
		if(collision_flag == 0){
			block_x++;
		}
	}
}

それぞれのキー入力に合わせて当たり判定用関数を呼び出し「collision_flag」を確認して「block_x」を移動させます。

キー入力はそのまま受け取るとけっこうシビアになるので余りをとる事によって少し調節しております。

これで左右の当たり判定ができました。

ゲームループ

ゲームループになります。

@Override
public void handle(long time){
	gc.clearRect(0,0,640,480);
	key.calc_key_count();

	my_make_block();
	my_move_block();
	my_draw_back();
	my_draw_variable();
	my_draw_block();
	my_draw_stage();
	my_fall_block();

	if(block_y_count > DRAW_BLOCK_WIDTH * 17){
		block_y_count = 0;
		block_y = 0;
	}
}

キー入力をカウントする「key.calc_key_count()」と移動処理の「my_move_block()」を加えました。

画像(jb_4_3)

左右の壁を確認しながら落下します!

キー入力のクラス設置に際し細かいトコロが変わっておりますので詳しくは中間ソースをご覧ください。

ここまでの中間ソースになります。

中間ソース3

それでは次回は底辺の当たり判定をつけたいと思います。

次回

五日目 当たり判定「底辺」

□ページの先頭へ□

□目次へ戻る□

□HOME□

広告

↓2016年06月25日発売↓

新・明解Java入門 (明解シリーズ)

新品価格
¥2,916から
(2017/5/1 13:47時点)

↓2017年04月18日発売↓

Java本格入門 ~モダンスタイルによる基礎からオブジェクト指向・実用ライブラリまで

新品価格
¥3,218から
(2017/5/1 13:50時点)

↓2017年05月17日発売↓

新・明解 Javaで学ぶアルゴリズムとデータ構造 (明解シリーズ)

新品価格
¥2,592から
(2017/5/1 13:54時点)

↓2017年04月04日発売↓

Java 第2版 入門編 ゼロからはじめるプログラミング (プログラミング学習シリーズ)

新品価格
¥2,030から
(2017/5/1 13:55時点)