15パズル制作|Javaから楽しく学ぶ!ゲームプログラミング専門学校

Javaから楽しく学ぶ!ゲームプログラミング専門学校

ゲームプログラミングとはその名のとおりゲームのプログラムを作ることを指します。『Javaから楽しく学ぶ!ゲームプログラミング専門学校』ではゲームプログラミングについて、実際にゲームプログラムをJAVAプログラミング言語を使用し、作成していきながら詳しく解説していきます。

15パズル制作

Javaで15パズルを作成してみます。

まずはコマの画像ファイルを用意する必要があります。
自分で作成するのがめんどくさいという方は下記からダウンロードしてください。
http://www.gamesite8.com/sozai/block.zip

プログラム動作の流れを簡単にまとめます。

Javaアプレットが読み込まれたらまず、1〜15までのコマ画像を読み込みます。
コマをクリックしたら、そのコマの上下左右に空いているマスであるかを調べます。
もし上下左右いずれかのマスが空いていれば、クリックされたコマを空いているマスへ移動させます。
マスが空いていなければ何もしません。

今回はメインクラスである『Num』クラスと盤上のマス情報を管理する『GridInfo』クラスの二つのクラスを作成しました。

ソースファイルは下記からダウンロードできます。
http://www.gamesite8.com/code/01/num.java

それではソースコードを順に解説していきます。

『num』というクラスを作成しています。
Javaアプレットとして作成するため、Appletクラスを継承
マウス操作によるイベントを取得するため、MouseListenerクラスをインプリメント

public class Num extends Applet implements MouseListener{
private final int GAME_WAIT = 0; //ゲーム状態フラグ定数(タイトル画面時)
private final int GAME_ING = 1; //ゲーム状態フラグ定数(ゲーム中)
private final int GRID_X = 4; //ボードの横マス数
private final int GRID_Y = 4; //ボードの縦マス数
private final int GRID_WIDTH = 64; //マスの横幅
private final int GRID_HEIGHT = 64; //マスの縦幅
private int WIDTH; //アプレット画面横幅
private int HEIGHT; //アプレット画面縦幅
private int gameFlg; //ゲーム状態フラグ
private GridInfo GInfo; //グリッドクラス
private Image offImage; //画面バッファ
private Image tileImage[]; //コマイメージ(1〜15)

…省略
}


Appletクラスのinitメソッドをオーバーライトしています。
Javaアプレットに受け渡されたアプレット画面の横幅、縦幅を格納し、1〜15の数字が書かれた画像ファイル15個を読み込んでいます。

public void init(){
WIDTH = getSize().width;
HEIGHT = getSize().height;
setBackground(Color.white);
tileImage = new Image[GRID_X * GRID_Y + 1];
DecimalFormat decimalFormat = new DecimalFormat("00");
for(int i = 1; i < GRID_X * GRID_Y; i++){
tileImage[i] = getImage(getDocumentBase(),
"images/blk" + decimalFormat.format(i) + ".jpg");

}
offImage = createImage(WIDTH, HEIGHT);
}


mousePressedイベント(マウスがクリックされたときのイベント)が呼び出されたときの処理を下記に示します。
ゲーム状態フラグにより処理を場合分けしています。
タイトル画面時にアプレット画面がクリックされた場合、ゲーム初期化メソッド(gameInit)を呼び出しています。
ゲーム中であった場合はクリックされた座標をもとめ、その座標からクリックされたコマが置いてあるマスをもとめます。
グリッド情報クラス(GridInfo)のメソッドであるmoveTileメソッドを呼び出しています。
moveTileメソッドではコマが移動できる場合はコマを移動させています。

public void mousePressed(MouseEvent e){
int clickTileX;
int clickTileY;
boolean blnRet;

switch(gameFlg){
case GAME_WAIT:
gameInit();
break;
case GAME_ING:
/* クリック座標からクリックされたコマが置いてあるマスを取得 */
clickTileX = (int)(e.getX() / GRID_WIDTH);
clickTileY = (int)(e.getY() / GRID_HEIGHT);
/ *コマを移動させる。移動できない場合は何もしない */
blnRet = GInfo.moveTile(clickTileX, clickTileY);
/* コマが整列した場合はゲーム終了 */
blnRet = GInfo.getGameClearFlg();
if(blnRet == true){
/* ゲーム状態フラグを変更 */
gameFlg = GAME_WAIT;
}
break;
}
/ *描画 */
repaint();
}


paintイベント(画面を描画するイベント)が呼び出されたときの処理を下記に示します。
それぞれのマスに置かれているコマを描画しています。
どのマスに何番のコマが置かれているかの情報は、グリッド情報クラス(GridInfo)のメソッドであるgetTileNum(int,int)メソッドから取得しています。

public void paint(Graphics g){
Graphics gv = offImage.getGraphics();
gv.clearRect(0, 0, WIDTH, HEIGHT);

for(int y = 0; y < GRID_Y; y++){
for(int x = 0; x < GRID_X; x++){
if(GInfo.getTileNum(x, y) != 0){
gv.drawImage(tileImage[GInfo.getTileNum(x, y)],
x * GRID_WIDTH, y * GRID_HEIGHT,
GRID_WIDTH, GRID_HEIGHT, this);
}
}
}
switch(gameFlg){
case GAME_WAIT:
gv.drawString("Game Over", 100, 100);
gv.drawString("Click Start", 130, 130);
break;
case GAME_ING:
break;
}
g.drawImage(offImage, 0, 0, WIDTH, HEIGHT, this);
}


下記からは『GridInfo』クラスを作成しています。

class GridInfo
{
private int intGridXNum; //マスの横数
private int intGridYNum; //マスの縦数
private int intGridFlg[][]; //マス情報

/* コンストラクタ */
GridInfo(int xNum, int yNum){
/* 引数から渡されたマスの横幅、縦幅を保存 */
intGridXNum = xNum;
intGridYNum = yNum;

/* 各マスに置かれているコマを保持する2次元配列を定義 */
intGridFlg = new int[intGridXNum][intGridYNum];

/* 1〜15までの数を格納 */
for(int y = 0; y < intGridYNum; y++){
for(int x = 0; x < intGridXNum; x++){
intGridFlg[x][y] = (y * intGridYNum) + x + 1;
}
}
/* 右下のマスにはコマがないことを意味する0を格納 */
intGridFlg[intGridXNum - 1][intGridYNum - 1] = 0;
}

…省略
}


引数で渡されるクリックしたマス目を元にwhileループ内で上下左右にコマが置かれていないマスがないかを調べています。
もし見つかった場合はどのマスに何番のコマが置かれているかの情報を保持している『intGridFlg』2次元配列を更新し、whileループを抜けています。
また、『intGridFlg』2次元配列を更新した場合はクリックしたマスを空にしています。

public boolean moveTile(int clickX, int clickY){
boolean blnRet;
boolean blnExist;
blnRet = true;
blnExist = false;
while(true){
/* 右に移動できるか判別 */
if(clickX + 1 < intGridXNum && clickX >= 0
&& clickY >= 0 && clickY < intGridYNum){
if(intGridFlg[clickX + 1][clickY] == 0){
intGridFlg[clickX + 1][clickY] = intGridFlg[clickX][clickY];
blnExist = true;
break;
}
}
/* 左に移動できるか判別 */
if(clickX - 1 >= 0 && clickX < intGridXNum
&& clickY >= 0 && clickY < intGridYNum){
if(intGridFlg[clickX - 1][clickY] == 0){
intGridFlg[clickX - 1][clickY] = intGridFlg[clickX][clickY];
blnExist = true;
break;
}
}
/* 下に移動できるか判別 */
if(clickY + 1 < intGridYNum && clickY >= 0
&& clickX >= 0 && clickX < intGridXNum){
if(intGridFlg[clickX][clickY + 1] == 0){
intGridFlg[clickX][clickY + 1] = intGridFlg[clickX][clickY];
blnExist = true;
break;
}
}
/* 上に移動できるか判別 */
if(clickY - 1 >= 0 && clickY < intGridYNum
&& clickX >= 0 && clickX < intGridXNum){
if(intGridFlg[clickX][clickY - 1] == 0){
intGridFlg[clickX][clickY - 1] = intGridFlg[clickX][clickY];
blnExist = true;
break;
}
}
break;
}
/* クリックされたマスからコマを移動させたら、そのマスを空にする */
if(blnExist == true){
intGridFlg[clickX][clickY] = 0;
}
return blnRet;
}


ゲームがクリアされたかどうかを調べるメソッドです。
ゲームがクリアされていたらtrueを、まだクリアしていなかったらfalseを返しています。

public boolean getGameClearFlg(){
boolean blnRet;
blnRet = true;

for(int y = 0; y < intGridYNum; y++){
for(int x = 0; x < intGridXNum; x++){
/* 右下のマスが空いているかどうかを判断 */
if(y == intGridYNum - 1 && x == intGridXNum - 1){
if(intGridFlg[x][y] != 0){
blnRet = false; //右下のマスが空いていなかったらfalseを代入

}
}
/* 数字が整列されているかどうかを判断 */
else if(intGridFlg[x][y] != (y * intGridYNum) + x + 1){
blnRet = false; //数字が整列されていなかったらfalseを代入
}
}
}

return blnRet;
}


次回はコマのシャッフル機能を組み込んでみます。

トラックバック:0Edit
Copyright © Javaから楽しく学ぶ!ゲームプログラミング専門学校 All Rights Reserved.
当サイトのテキストや画像等すべての転載転用・商用販売を固く禁じます