/*
adlight.java ファイァーオン (古典パズルゲーム)
auth kaihatsu@ad2000-ltd.com
edit 2001/08/01
*/
import java.util.*; //必要なライブラリのインポート
import com.kddi.io.*;
import com.kddi.system.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
import java.lang.Object;
public class Adlight extends MIDlet implements CommandListener { //起動クラスの開始
static GameCvs MyCanvas; //ゲーム用キャンバスの用意
static Display MyDisplay; //自分自身の表示キャンバス
static Thread runner; //自分自身のタスク
public Adlight() {
MyCanvas = new GameCvs(); //ゲームキャンバスの作成
MyDisplay = Display.getDisplay(this); //用意されたディスプレイオブジェクトを取得
MyDisplay.setCurrent(MyCanvas); //それをカレントに設定
MyCanvas.setCommandListener(this); //コマンドリスナーをセット
runner = new Thread(MyCanvas); //ゲームキャンバスをタスクにして…、
runner.start(); // 実行開始
MyCanvas.startTimer(); //タイマータスクも起動
}
protected void destroyApp(boolean unconditional){ //終了時に必要な処理
}
protected void pauseApp(){ //ポーズ時に必要な処理
}
protected void startApp(){ //起動エントリ
}
//---------------------- コマンドボタンの処理
private Command exitCommand = new Command("終了", Command.BACK , 1); //終了ボタンをBACKボタンとして作成
private Command game1Command = new Command("盤面1", Command.SCREEN ,1); //盤面1ボタンをSCREENボタンとして作成
private Command game2Command = new Command("盤面2", Command.SCREEN ,1); //盤面2ボタンをSCREENボタンとして作成
private Command game3Command = new Command("乱数面", Command.SCREEN ,1); //乱数面ボタンをSCREENボタンとして作成
private Command game4Command = new Command("続きから", Command.SCREEN ,1);//継続ボタンをSCREENボタンとして作成
public void commandAction(Command com, Displayable disp) { //SOFTKEYが押されたらここに来る
if(com == exitCommand){ //終了ボタンが押されたら、
MyCanvas.GameMode = MyCanvas.GameMode_Exit; // その旨記す
}
if(MyCanvas.GameMode == MyCanvas.GameMode_StartWait){ // ゲーム開始待ち中であることを確認して、
if(com == game1Command){ //盤面1が押されたら、
MyCanvas.GameMode = MyCanvas.GameMode_1_Start; // その旨記す
}
if(com == game2Command){ //盤面2が押されたら、
MyCanvas.GameMode = MyCanvas.GameMode_2_Start; // その旨記す
}
if(com == game3Command){ //乱数面が押されたら、
MyCanvas.GameMode = MyCanvas.GameMode_3_Start; // その旨記す
}
if(com == game4Command){ //継続が押されたら、
MyCanvas.GameMode = MyCanvas.GameMode_4_Start; // その旨記す
}
}
}
//----------------------- ゲームキャンバス
public class GameCvs extends Canvas //ゲームの本体クラス
implements Runnable { //当然実行できるようにする
private Timer timer; //タイマー関連の定義
private MyTimer timerTask; //
private int TimerCounter; //
private Random rand; //乱数発生用
private Font fTime; //使用するFont
//ゲーム中での状態を分類しておく
private final int GameMode_Top = 10; // 開始待ちへの移行状態
private final int GameMode_StartWait = 20; // 開始待ち状態
private final int GameMode_1_Start = 21; // ゲーム1開始
private final int GameMode_2_Start = 22; // ゲーム2開始
private final int GameMode_3_Start = 23; // ゲーム3開始
private final int GameMode_4_Start = 24; // ゲーム4開始
private final int GameMode_Play = 40; // ゲームプレイ中
private final int GameMode_Flash1 = 50; // 画面フラッシュ中1
private final int GameMode_Flash2 = 60; // 画面フラッシュ中2
private final int GameMode_End = 70; // ゲーム終了への移行状態
private final int GameMode_EndWait = 80; // プレイ終了表示状態
private final int GameMode_Exit = -1; // ゲーム終了
private int GameMode; //ゲームの状態を保管する変数
private int Key; //押されたキーを保管する変数
private final int PictX = 32; //パネル画像のXサイズ
private final int PictY = 32; // 上記Yサイズ
private final int GrXWidth = PictX*3; //ゲーム画面の横幅をパネル3枚分とする
private final int GrYWidth = PictY*3; //ゲーム画面の縦幅をパネル3枚分とする
private int CvsGetWidth; //端末の表示可能な横幅
private int CvsGetHeight; //端末の表示可能な縦幅
private int MinimamX; //ゲームに使う表示エリアの左上のX値
private int MinimamY; // 上記のY値
private int MaxmamX; //ゲームに使う表示エリアの右下のX値
private int MaxmamY; // 上記のY値
private final byte ChangeOffset = 8; //パネルの反転マーク用の値
private final int ChgTableSize = 6; //下記の1行分のレコードサイズ
private final int [] ChgTable = { //押されたキーと反転対象となるパネルナンバーのリスト
KEY_NUM1, 0, 1, 3,-1,-1, // 0-8:対応するパネル番号
KEY_NUM2, 0, 1, 2, 4,-1, // -1:は対象無し
KEY_NUM3, 1, 2, 5,-1,-1, // ChgTableSizeで1キー分を構成
KEY_NUM4, 0, 3, 4, 6,-1,
KEY_NUM5, 1, 3, 4, 5, 7,
KEY_NUM6, 2, 4, 5, 8,-1,
KEY_NUM7, 3, 6, 7,-1,-1,
KEY_NUM8, 4, 6, 7, 8,-1,
KEY_NUM9, 5, 7, 8,-1,-1,
-1 //キー比較時のエンドマーク
};
private final int MapSize = 9; //パネルの総数
private final byte [] GameOrgMap = { //初期盤面 (問題図) の定義
0,0,0, // 0:消灯 1:点灯
0,0,0, // MapSizeの個数で1ブロックとする
0,0,0,
1,1,1,
1,0,1,
1,1,1
};
private final byte [] GameMap = new byte [MapSize]; //表示の元となるパネルの状態を保管する配列
private int FlashMode; //フラッシュ表示の後ゲーム中とするか、ゲームクリアとするかのフラグ
private int LoopCount; //実行ループのカウンタ
public GameCvs() { //コンストラクタ
} // 特に何もない
public void startTimer(){ //タイマータスクの設定&起動
timerTask = new MyTimer(this); //
timer = new Timer(); //
timer.schedule(timerTask, 0, 100); //100msecのタイマーとする
}
//------------------------ タイマー割り込み処理
public void myTimerTask(){ //タイマー割り込みが発生したら、
TimerCounter++; // 変数をカウントアップ
}
//------------------------ キー処理
public void keyPressed(int param){ //キーが押されたらここに来る
Key = param; //押されたキーを保存
}
private int getMyKey(){ //キーを取り出す
int result = Key; //保管されているキーを取り出し、
Key = 0; //保管庫はクリアしておく
return result; //
}
//------------------------ グラフィックリソースの読み込み
private final int GrFireOff = 0; //パネルの状態値定義 (リソース番号にも対応)
private final int GrFireOn = 1; //
private Image [] Gr = new Image[2]; //要素2のリソース配列を作成
private void loadResource() { //対応するリソースファイルを指定の配列要素に保管
Gr[GrFireOff] = loadGres("fireoff.png"); //消灯図柄の読み込み
Gr[GrFireOn ] = loadGres("fireon.png"); //点灯図柄の読み込み
}
private Image loadGres(String s){ //リソース読み込み用関数
Image a = null; // イメージの本体を作成して、
try { //
a = Image.createImage("/"+s); // 名称を指定して読み込む
} catch (Exception ex) { //おそらく使われないエラー処理
ex.printStackTrace(); //
} //
return a; //読み込んだイメージを返す
}
//------------------------ データ―ストレージレコード
private final String MyRecName = "MyRecord"; //保存ファイル名の定義
private int RecERR; //汎用エラー保管変数(今回は利用されていない)
public int saveRecord(){ //データ保存関数
RecordStore recordStore = null; //ファイルハンドルを準備
delRecordFile(); //本例では保存時に全部書き直すのでいったん全消去する
RecERR = 0; //エラー内容のクリア
try{ //エラー検出のため try を使用
recordStore = RecordStore.openRecordStore(MyRecName,true); // ファイルが存在しなければ作成する指定でオープンする
recordStore.addRecord(GameMap,0,MapSize); // GameMapの内容をMapSize分書き出す
recordStore.closeRecordStore(); // ファイルハンドルをクローズする
}catch(RecordStoreNotOpenException e){ //ハンドルオープン時のエラーが検出されれば、
RecERR = 1; // エラー値として1を記録
}catch(RecordStoreException e){ //記録中などにエラーが検出されたら、
RecERR = 2; // エラー値として2を記録
}
return RecERR; //エラー値を返す (0なら正常)
}
private void delRecordFile(){ //保存ファイルの削除
try { //エラーフェッチのためtryを使用
RecordStore.deleteRecordStore(MyRecName); // ファイルの削除
} catch (RecordStoreNotFoundException e){ //エラーを取得、分類する必要があれば
} catch (RecordStoreException e){ // ここで RecERR に値を代入してもよい
} catch (Exception ex) {
}
}
public int loadRecord(){ //保存ファイルの読み出し
byte [] buff; //読み込み用バッファ
RecordStore recordStore = null; //ファイルハンドルを準備
RecERR = 0; //エラー内容のクリア
try{ //エラー検出のため try を使用
recordStore = RecordStore.openRecordStore(MyRecName,false); // ファイルが存在しなければ作成しない指定でオープンする
buff = recordStore.getRecord(1); // 内容をバッファに読み出す
recordStore.closeRecordStore(); // ファイルハンドルをクローズする
for(int i=0;iMapSize;i++){
GameMap[i] = GameOrgMap[num*MapSize+i]; // 初期盤面配列からコピーする
}
saveRecord(); // 経過ファイルの作成
break;
case GameMode_3_Start: //乱数面作成であれば、
for(int i=0;i 0){ //登録キーを読み出しエンドマークではない間繰り返す
if(PushedKey == n){ // 押されたキーと同じならば、
int j = 1; // 反転対象のリスト番号
while((n = ChgTable[i*ChgTableSize+j]) >= 0){ // リストから反転対象番号を取得し有効値であれば、
GameMap[n] = (byte)( GameMap[n]+ChangeOffset ); // その対象パネルに反転マークをつける
if(++j >= ChgTableSize){ // ポイントを進め、必要数を超えていれば中断
break;
}
}
return true; // 変更ありとして真を返す
}
i++; // キー比較用ポインタを進める
}
return false; //無効キーであったため変更無しとして偽を返す
}
private boolean checkClr(){ //ゲームクリア (完成) 検出関数
int i; //forループ用変数
for(i=0;iMapSize;i++){ //全パネルフラッシュ用に
GameMap[i] += ChangeOffset; // 全パネルに反転マークをつける
}
return true; //ゲームクリアとして真を返す
}
private void chgFlagClr(int sw){ //反転マーク消去関数
for(int i=0;i= ChangeOffset){ // 反転マークがついていたら、
GameMap[i] -= ChangeOffset; // 反転マークを取り去る
if(sw != 0){ // 結果反転指定であれば、
GameMap[i] = (byte)((GameMap[i] != 0)?(0):(1)); // 結果を反転させる
} // (ゲームクリア時のフラッシュ後は反転させていない)
}
}
}
//------------------------ 画面表示
public void paint(Graphics g) { //描画が要求されたらここに来る
clearDisplay(g); //とりあえず画面をベース色でクリア
switch(GameMode){ //現在のゲーム状態により処理分岐
case GameMode_StartWait: // 開始前の待ちであれば、
if((LoopCount & 2) != 0){ // ゲームループカウンタの値に応じて、
dispStringCenter(g,"SELECT MENU"); // 文字列を書く
} // これで点滅することになる
break;
case GameMode_Flash1: //画像フラッシュ1ならば
flashView(g,2); // &条件2で点滅
break;
case GameMode_Flash2: //画像フラッシュ2ならば
flashView(g,1); // &条件1で点滅
break;
case GameMode_Play: //プレイ中か
case GameMode_End: //終了移行中なら
dispView(g,0); // 通常表示
break;
case GameMode_EndWait: //終了表示中なら、
dispView(g,0); // 通常表示
if((LoopCount & 2) != 0){ // ゲームループカウンタの値に応じて、
dispStringCenter(g,"CLEAR!"); // クリアメッセージを書く
} // これで点滅させている
break;
}
}
private void clearDisplay(Graphics g){ //画面のクリア
g.clipRect(MinimamX,MinimamY,GrXWidth,GrYWidth); //書き換え領域を指定
g.setColor(255,255,255); //色は白
g.fillRect(MinimamX,MinimamY,GrXWidth,GrYWidth); //ゲーム領域を塗りつぶす
}
private void dispStringCenter(Graphics g,String str){ //画面中央に文字列を表示
g.setColor(0,0,0); //色は黒
g.setFont(fTime); //表示フォントを指定
//文字列の中央を画面の中央に指定して、文字列を表示
g.drawString(str,MinimamX+GrXWidth/2,MinimamY+GrYWidth/2,Graphics.HCENTER | Graphics.VCENTER );
}
private void flashView(Graphics g,int sw){ //フラッシュ表示
if((LoopCount & sw) != 0){ // ゲームループカウンタの値に応じて、
dispView(g,0); // そのままの画面を表示
}else{ // もしくは
dispView(g,1); // マークした部分を反転表示する
}
}
private void dispView(Graphics g,int sw){ //全パネルの表示
int x,y,c; //ループ用と表示パネル選択用変数定義
for(y=0;y<3;y++){ //Yループ
for(x=0;x<3;x++){ // Xループ
c = GameMap[y*3+x]; // X・Yで特定されるパネル状態を取得
if(c >= ChangeOffset){ // 反転マークがついていたら
c -= ChangeOffset; // とりあえず反転マークを取り除いて
if(sw!=0){ // 判定指定があれば、
c = (c!=0)?(0):(1); // 表示内容を反転させる
}
} // cの内容に基づいた図柄をX・Yで特定される位置に表示
g.drawImage(Gr[c],MinimamX+x*PictX,MinimamY+y*PictY,Graphics.TOP | Graphics.LEFT);
}
}
}
//------------------------ ゲーム状態処理
public void run(){ //このタスクの実行はここ
rand = new Random(); //乱数使用の準備
GameMode = 0; //初期化中ということで状態を未規定に
Key = 0; //入力キーもクリア
CvsGetWidth = MyCanvas.getWidth(); //端末の画面情報から表示可能横サイズを取得
CvsGetHeight = MyCanvas.getHeight(); //端末の画面情報から表示可能縦サイズを取得
MinimamX = (CvsGetWidth-GrXWidth)/2; //ゲーム領域の基点のXを作成
MinimamY = (CvsGetHeight-GrYWidth)/2-5; // 上記のYを作成 (下部ソフトキーエリアにかかってしまう端末にラフ対策)
if(MinimamY < 0){MinimamY = 0;} //予想外にYが小さい端末でのラフ対策
if(MinimamX < 0){MinimamX = 0;} // 上記のXに関して
MaxmamX = GrXWidth+MinimamX; //ゲーム画面のX最大値を作成
MaxmamY = GrYWidth+MinimamY; // 上記のYに関して
loadResource(); //画像リソースの取り込み
//使用フォントの指定
fTime = Font.getFont(Font.FACE_MONOSPACE,Font.STYLE_PLAIN,Font.SIZE_SMALL);
MyCanvas.addCommand(exitCommand); //終了ボタンの設置
GameMode = GameMode_Top; //ゲーム状態を開始準備へ
LoopCount = 0; //ゲームループカウンターをクリア
TimerCounter = 0; //タイマーカウンターもクリア
//ゲームループ (メイン)
while(GameMode != GameMode_Exit){ //終了状態でなければ繰り返す
System.gc(); //ガベージコレクションを済ませておく
switch(GameMode){ //各ゲーム状態により処理分岐する
case GameMode_Top: // 開始準備であれば、
initCommand(); // コマンドボタンを設定して、
GameMode = GameMode_StartWait; // 次の開始待ちへ
break;
case GameMode_StartWait: // 開始待ちであれば、
break; // ただ待ってる
case GameMode_1_Start: // 盤面1ボタン、
case GameMode_2_Start: // 盤面2ボタン、
case GameMode_3_Start: // 乱数面ボタン、
case GameMode_4_Start: // 継続ボタンが押されてゲーム開始となれば、
initGame(); // 初期化して
GameMode = GameMode_Play; // プレイ中へ移行する
break;
case GameMode_Play: // プレイ中であれば、
if(checkClr()){ // 完成したのであれば、
LoopCount = 0; // カウンタを値で見るため初期化して
FlashMode = 1; // ゲームクリアフラグを立てておいて
GameMode = GameMode_Flash1; // フラッシュ表示に移行
}else if(keyAction()){ // キーイベントが起きたら、
LoopCount = 0; // カウンタを値で見るため初期化して
GameMode = GameMode_Flash1; // フラッシュ表示に移行
}
break;
case GameMode_Flash1: // フラッシュ表示モード1なら
if(LoopCount >= 5){ // カウンターの値が5未満であればそのまま、
GameMode = GameMode_Flash2; // 超過したら次のモードへと移行する
}
break;
case GameMode_Flash2: // フラッシュ表示モード2なら
if(LoopCount >= 10){ // カウンターの値が10未満であればそのまま、
if(FlashMode == 1){ // 超過して、ゲームクリアフラグが立っていれば
chgFlagClr(0); // 完成状態に戻し
delRecordFile(); // 経過ファイルは消去
GameMode = GameMode_End; // 終了状態へ
}else{ // 超過して、通常状態ならば
chgFlagClr(1); // 指定部分を反転させて
saveRecord(); // 経過ファイルの作成
GameMode = GameMode_Play; // プレイ中に戻す
}
}
break;
case GameMode_End: // クリアしたら、
GameMode = GameMode_EndWait; // クリア表示へと進む
break;
case GameMode_EndWait: // クリア表示状態ならば、
if(LoopCount >= 30){ // カウンターの値が30未満であればそのまま、
GameMode = GameMode_Top; // 超過したら開始準備へと移行する
}
break;
}
while(TimerCounter==0){ //タイマー割り込みがあるまで待つ
}
repaint(MinimamX,MinimamY,GrXWidth,GrYWidth); //画面再描画予約
serviceRepaints(); //今すぐに再描画させる
TimerCounter--; //割り込み評価終了でカウンターを減少させる
if(++LoopCount >= 9999){ //ゲームループカウンターを増やすが、
LoopCount = 0; // とんでもない値にならないように上限でもつけておく
}
}
//ここに来るときは、終了ボタンが押された時
notifyDestroyed(); // 終了手続き
}
}
}
class MyTimer extends TimerTask { //タイマークラスの定義
Adlight.GameCvs canvas; //
MyTimer(Adlight.GameCvs c) { //コンストラクト時に対象キャンバスを覚えておいて
canvas = c; //
}
public void run() { //タイマーでよびだされる都度、
try { //
canvas.myTimerTask(); //そのキャンバス内の指定関数に割り込む
} catch (Exception ex) { //
}
}
}
// end of file
|