↓↓クリックして頂けると励みになります。
【31 | 乱数】 << 【ホーム】 >> 【33 | AWTメニュー】
これまでにスレッドを生成する方法としてRunnableインターフェイスを実装する方法を紹介しましたが、今回はThreadのサブクラスを作成してスレッドを実現します。
スレッド自体の仕組みは以前と同様で、run()メソッド
に記述された処理がスレッドとして実行されます。
そしてスレッドを記述したインスタンスのstart()メソッド
を呼ぶことで実行されます。
public class MyThread extends Thread { /**コンストラクタ*/ public MyThread() { //コンストラクタの処理 } /**スレッド処理*/ public void run() { //スレッド処理 } public static void main(String[] args) { //スレッド生成 MyThread test = new MyThread(); //スレッド開始 test.start(); } }
次のThreadを継承したサンプルプログラム「MyTimer.java」を作成します。
新規作成 【MyTimer.java】
/** *Threadを継承したクラス */ public class MyTimer extends Thread { private int count=0; /**コンストラクタ*/ public MyTimer(int sec) { //super(); は省略 count = sec; } /**ループ処理のスレッド*/ public void run() { while (count > 0) { try { Thread.sleep(1000); } catch (InterruptedException ex) { System.err.println(ex); } count--; } } /**残り時間の取得*/ public int getTime() { return count; } /**mainメソッド*/ public static void main(String[] args) { MyTimer timer = new MyTimer(10); timer.start(); while (timer.getTime() > 0) { System.out.println("残り" + timer.getTime() + "秒"); } } }
早速実行してみましょう。
時間が減って0になるプログラムです。
「残り〜秒です」と表示し続けます。
10秒のタイマーです。
このプログラムは次に作成するジャンプゲームで利用します。
~/Desktop/Programming/JP $ javac MyTimer.java ~/Desktop/Programming/JP $ java MyTimer 残り10秒 残り10秒 残り10秒 残り10秒 残り10秒 残り10秒 残り10秒 残り10秒 ・・・ ・・・ ・・・
Visual Studio Codeで以下のJavaプログラム「JumpGame.java」を作成してみましょう。
新規作成 【JumpGame.java】
/**簡単なゲーム *時間制限があり *右から来る障害物を[SPACE]でジャンプして回避 *[s]キーで再ゲーム * ハイスコアの更新があります */ import java.awt.*; import java.awt.event.*; public class JumpGame extends Canvas implements KeyListener, Runnable { private final int MAX_IMAGE = 7; //キャラのイメージ枚数 private final int J_STAY = 0; //ジャンプしていない private final int J_UP = 1; //ジャンプして上昇中 private final int J_DOWN = 2; //ジャンプして下降中 private Graphics offg; //ダブルバッファリング用 private Image offImage; private int mx, my, mw, mh, oldmy, mspace; //キャラ用 private int mpx, mpy; //キャラの中心点 private int imCount, imNum; //キャラのイメージカウンターと番号 private int bx, by, bw, bh, oldbx, bspace; //障害物用 private int sx, sy, sc; //スコア表示用 private int hsx, hsy, hsc; //ハイスコア表示用 private int tx, ty, time; //残り時間表示用 private int meterx, metery, meterw, meterh; // メーター表示用 private int meterc; //メーター減少部分 / 秒 private Image[] im = new Image[MAX_IMAGE]; //キャラのイメージ private Image box, back, meter; //障害物と背景、メーターのイメージ //JumpGame2.javaでもgameFragを使用するのでこれのみpublicとする。 public boolean gameFlag; //ゲーム進行フラグ private int jFlag; //アニメーション(ジャンプ)の状態 private MediaTracker tracker; //イメージ通知用 private int key; //キーコード取得用 private MyTimer timer; //残り時間設定のためのタイマー /**コンストラクタ*/ public JumpGame() { setSize(500, 250); setBackground(Color.black); addKeyListener(this); Toolkit tk = Toolkit.getDefaultToolkit(); tracker = new MediaTracker(this); //メディアトラッカーにイメージを登録 box = tk.getImage("box.gif"); tracker.addImage(box, 1); for (int i=0; i<MAX_IMAGE; i++) { im[i] = tk.getImage("char" + i + ".gif"); tracker.addImage(im[i], 0); } //背景イメージを生成と登録 back = tk.getImage("back.gif"); tracker.addImage(back, 2); //背景イメージを生成と登録 meter = tk.getImage("meter.gif"); tracker.addImage(meter, 2); //全イメージを読み込むまで待つ try { tracker.waitForAll(); } catch (InterruptedException ex) { System.err.println(ex); } //キャラ、障害物、メーターのイメージの大きさを取得 mw = im[0].getWidth(this); mh = im[0].getHeight(this); bw = box.getWidth(this); bh = box.getHeight(this); meterw = meter.getWidth(this); meterh = meter.getHeight(this); //キャラの中心点を計算 mpx = mw/2; mpy = mh/2; //ハイスコアの初期設定はここでのみ行う hsc = 0; hsx = 200; hsy = 10; //ハイスコアの表示座標 } /**ゲーム開始処理*/ public void gameStart() { gameInit(); //変数の初期化 timer = new MyTimer(30); //タイマーの設定(30秒) new Thread(this).start(); //ゲーム開始 timer.start(); //秒タイマー開始 } /**ゲームに使用する変数の初期化*/ public void gameInit() { //キャラのx,y座標、ジャンプの間隔 mx = 100; my = 200; mspace = 5; //障害物のx,y座標、移動間隔 bx = 450; by = 200; bspace = 5; jFlag = J_STAY; //ジャンプしていない=0(上昇=1、下降=2) gameFlag = true; //ゲームオーバーならfalse sx = 10; //スコアの表示座標 sy = 10; sc = 0; //スコアは0点から tx = 400; //残り時間の表示座標 ty = 10; time = 30; //表示用に残り時間を初期化 meterx = 400; //残り時間メーターの表示座標 metery = 20; meterc = meterw/30; //メータ減少部分 / 秒 imCount = 0; //キャライメージの増減カウンター imNum = 0; //キャライメージ1枚目からスタート } /**メインの処理(スレッド処理)*/ public void run() { while (gameFlag == true) { //gameFlagがfalesになるまで繰り返し try { Thread.sleep(20); //20ミリ秒スリープ } catch ( InterruptedException ex) { System.err.println(ex); } repaint(); } } /**再描写が必要な場合の処理*/ public void update(Graphics g) { oldmy = my; oldbx = bx; //キャラクタ、障害物の消去(全画面消去) offg.setColor(Color.white); offg.fillRect(0, 0, getSize().width, getSize().height); //口を空けるアニメか、閉じるアニメかを設定 if (imNum >= (MAX_IMAGE-1)) { imCount = -1; } else if (imNum <= 0) { imCount = 1; } imNum+=imCount; //スペースキーが押されたときの処理 if (jFlag == J_UP) { my -= mspace; if (my <= 100) { //この位置まで来たらフラグ変更 jFlag = J_DOWN; } } else if (jFlag == J_DOWN) { //下降中 my += mspace; if ( my >= 200 ) { //この位置まで来たらフラグ変更 jFlag = J_STAY; } } //障害物を左へ移動 bx -= bspace; if (bx < 0) { bx = 450; sc++; } //残り時間の取得 time = timer.getTime(); //キャラと障害物が重なった場合(キャラの中心点で判定か、 //残り時間が無くなったときはゲームオーバー if ( (mx+mpx >= bx && mx+mpx < bx+bw && my+mpy >= by && my+mpy < by+bh) || time == 0) { gameFlag = false; //ハイスコアの更新チェック if (sc > hsc) { hsc = sc; } } //オフスクリーン・バッファへの描き込み。実際にはまだ見えない offg.drawImage(back, 0, 0, this); //背景 //残り時間メーター //第2~5引数(表示範囲)、第6~9引数(元イメージの範囲) offg.drawImage(meter, meterx, metery, meterx+meterc*time, metery+meterh, 0, 0, meterc*time, meterh, this); offg.drawImage(im[imNum], mx, my, this); offg.drawImage(box, bx, by, this); //スコアの表示 offg.setColor(Color.red); offg.drawString("Score:" + sc, sx, sy); //ハイスコアの表示 offg.setColor(Color.yellow); offg.drawString("Hi-Score:" + hsc, hsx, hsy); //残りタイムの表示 offg.setColor(Color.blue); offg.drawString("Time:" + time, tx, ty); if (gameFlag == false) { offg.setColor(Color.red); offg.drawString("Game Over!!", 100, 100); offg.drawString("Start [S] Key", 100, 150); } //オフスクリーン・バッファに描かれたものを画面に表示 g.drawImage(offImage, 0, 0, this); } /**キャンバスで描画の必要があるときに呼ばれるメソッド*/ public void paint(Graphics g) { //オフスクリーン・バッファの領域がない場合は作成 if (offg == null) { offImage = createImage(getSize().width, getSize().height); offg = offImage.getGraphics(); } //offImageを描画 g.drawImage(offImage, 0, 0, this); } /**キーが押されたときの処理*/ public void keyPressed(KeyEvent evt) { key = evt.getKeyCode(); //ゲームオーバー時に[S]キーでゲーム開始 if (gameFlag == false && key == evt.VK_S) { gameStart(); //ゲーム開始 } //スペースキーが押されて、 //なおかつジャンプしてないときのみ処理を行う if (key == evt.VK_SPACE && jFlag == J_STAY) { jFlag = J_UP; } } /**その他のキー処理*/ public void keyReleased(KeyEvent evt) { } public void keyTyped(KeyEvent evt) { } /**main()*/ public static void main(String[] args) { JumpGame sample = new JumpGame(); //クローズボタンで終了するように自作したクラス MyFrame frame = new MyFrame("JumpGame"); frame.add(sample); frame.pack(); frame.setVisible(true); sample.gameStart(); } }
なおこのプログラムを実行するには以下のイメージファイル(box.gif、back.gif、meter.gif)、画像ファイル(char0.gif〜char6.gif)が必要になります。
プログラムを保存するフォルダに保存してください。
[back.gif]
[box.gif]
[meter.gif]
[char0.gif]
[char1.gif]
[char2.gif]
[char3.gif]
[char4.gif]
[char5.gif]
[char6.gif]
ではコンパイルして実行します。
前のセッションで作成した「MyFrame.java」を利用していますのでクローズボタンを使って終了できます。
このセッションで作成した「MyTimer.java」を利用しています。
時間制限があります。
右から来る障害物を[SPACE]でジャンプして回避します。
[s]キーで再ゲーム開始です。
ただし、ゲームが始まったら一度、マウスで画面のどこかをクリックしなければキーボードの入力を受け付けてくれません。
ハイスコアの更新があります。
~/Desktop/Programming/JP $ javac JumpGame.java ~/Desktop/Programming/JP $ java JumpGame
【31 | 乱数】 << 【ホーム】 >> 【33 | AWTメニュー】
↓↓クリックして頂けると励みになります。