PROGRAMING2 report#8


課題
○Java Applet/AWTについて学び、Java Appletのオリジナルプログラムを作成し解説せよ。


Caveman.java

import java.applet.*; import java.awt.*; import java.awt.event.*; public class Caveman extends Applet implements Runnable, MouseListener, KeyListener{ Thread t; Image buffer; Graphics bufferg; Font normal = new Font("SansSerif", Font.BOLD, 16); // フォントのオブジェクトを生成 Font small = new Font("Serif", Font.PLAIN, 12); Font big = new Font("Serif", Font.BOLD, 36); Font stress = new Font("SansSerif",Font.BOLD, 20); boolean start = false; // ゲームスタートしたかどうか boolean col = false; // 衝突したかどうか boolean over= false; // ゲームオーバーしたかどうか Block b = new Block(); // ブロック生成 Jiki j[] = new Jiki[5]; // 自機を宣言 int score = 0; // 点数、及び開始からの時間 int top = 20; // 上下の幅 int bottom; int margin = 5; // タイトル画面での枠幅 int x[] = { 20, 15, 10, 5, 0 }; // 各自機の初期座標 int y[] = { 40, 35, 40, 45, 50 }; int highscore = 0; // ハイスコアを保存 int winWidth, winHeight; // ウインドウの幅と高さ public void init() { setFont(normal); // フォントを設定 // 自機を生成 for(int a = 0; a < 5; a++){ j[a] = new Jiki(x[a],y[a]); } addMouseListener(this); addKeyListener(this); requestFocus(); // スレッドを開始 t = new Thread(this); t.start(); // アプレットサイズの取得 Dimension d = getSize(); winWidth = d.width; winHeight = d.height; bottom = winHeight - 75; // バッファを作成 buffer = createImage(winWidth, winHeight); } public void run(){ try{ while(true) { // ゲーム中で、衝突してない状態 if(start && !col){ // 自機の現在の座標を記録 for(int a = 0; a < 4; a++){ j[a].log_y = j[a].y; } // 後続の自機に座標を伝える for(int a = 0; a < 4; a++){ j[a+1].y = j[a].log_y; } j[0].move(); // 先頭の自機を動かす // ブロックを生成するかどうか if(b.time > 9){ b.newBlock = true; b.time = 0; } // ブロックを生成する処理 if(b.newBlock){ if(b.num == 255){ b.num = 0; } b.x[b.num] = 190; b.y[b.num] = b.topLimit + (int)(Math.random() * b.bottomLimit); b.num++; b.newBlock = false; } b.time++; // ブロックを生成してからの時間を更新 score++; // スコアを更新 // ブロックの移動 for(int a = 0; a < b.num; a++){ b.x[a] -= 5; } // 地面と天井を動かす処理 if(score % 10 == 0){ if(score > 100 && score < 500 || score > 700 && score < 900){ top++; bottom--; b.topLimit++; b.bottomLimit--; } } // 衝突を判定 if(b.num < 9){ // 最初に描画されたブロックが画面端に届いてない場合 for(int a = 0; a < b.num; a++){ // ブロックとの衝突を判定 if(( j[0].x+5 >= b.x[a] && j[0].x <= b.x[a] + b.width) && (j[0].y+5 >= b.y[a] && j[0].y <= b.y[a] + b.height)){ col = true; } // 天井、地面との衝突を判定 else if( j[0].y <= top-1 || j[0].y + 5 >= bottom+1){ col = true; } } }else{ // 最初に描画されたブロックが画面端に届いた場合 for(int a = b.num-8; a < b.num; a++){ // ブロックとの衝突を判定 if(( j[0].x+5 >= b.x[a] && j[0].x <= b.x[a] + b.width) && (j[0].y+5 >= b.y[a] && j[0].y <= b.y[a] + b.height)){ col = true; } // 天井、地面との衝突を判定 else if( j[0].y <= top-1 || j[0].y + 5 >= bottom+1){ col = true; } } } } repaint(); // 再描画 Thread.sleep(100); // ウィンドウを更新する前に休止 } } catch(Exception e){ } } public void update(Graphics g){ paint(g); } public void paint(Graphics g){ // バッファのグラフィックコンテキストを取得 if(bufferg == null){ bufferg = buffer.getGraphics(); } // タイトル画面での描画 if(!start){ // 全体を塗りつぶす bufferg.setColor(Color.black); bufferg.fillRect(0, 0, winWidth, winHeight); // 枠内を描画 bufferg.setColor(Color.blue); bufferg.fillRect(margin ,margin ,winWidth - (margin*2), winHeight - (margin*2)); // タイトル等の文字を描画 bufferg.setColor(Color.white); bufferg.setFont(big); bufferg.drawString("Caveman", 20, 50); bufferg.setFont(small); bufferg.drawString("UP/click!", 40, 80); bufferg.drawString("Doun/newtral", 40, 100); bufferg.setFont(normal); bufferg.drawString("HISCORE: " + highscore, 40, 160); bufferg.drawString("SCORE : " + score, 40, 130); bufferg.setFont(stress); bufferg.drawString("Click to Start!", 40, 200); }else{ // ゲーム中の描画 if(!over){ // 全体を塗りつぶす bufferg.setColor(Color.black); bufferg.fillRect(0, 0, winWidth, winHeight); // 自機を描画 bufferg.setColor(Color.blue); for(int a = 0; a < 5; a++){ bufferg.fillRect(j[a].x, j[a].y, 5, 5); } // ブロックの描画 bufferg.setColor(Color.green); if(b.num < 9){ for(int a = 0; a < b.num; a++){ bufferg.fillRect(b.x[a], b.y[a], b.width, b.height); } }else{ for(int a = b.num-8; a < b.num; a++){ bufferg.fillRect(b.x[a], b.y[a], b.width, b.height); } } // 天井と壁を描画 bufferg.setColor(Color.green); bufferg.fillRect(0, 0, 200, top); bufferg.fillRect(0, bottom, winWidth, 200); bufferg.setColor(Color.green); bufferg.drawLine(0, top, winWidth, top); bufferg.drawLine(0, bottom, winWidth, bottom); // スコアを描画 bufferg.setFont(normal); bufferg.setColor(Color.white); bufferg.drawString("SCORE: " + score, 50, 190); bufferg.drawString("Click: UP" , 50, 210); } // ゲームオーバー時の描画 if(col){ // ゲームオーバー時の各文字列を描画 bufferg.setFont(normal); bufferg.setColor(Color.red); bufferg.drawString("GAME OVER" , 50, 100); highscore = Math.max(highscore,score); bufferg.drawString("HIGHSCORE: " + highscore, 40, 140); bufferg.setColor(Color.white); bufferg.drawString("Push enter key", 30, 230); // ゲームオーバー over = true; } } // ウインドウを更新 g.drawImage(buffer, 0, 0, this); } public void mouseClicked(MouseEvent ev){ // ゲームスタート if(!start){ start = true; score = 0; } } public void mouseEntered(MouseEvent ev){ } public void mouseExited(MouseEvent ev){ } public void mousePressed(MouseEvent ev){ // 自機を上昇させる if(!over){ for(int a = 0; a < 5; a++){ j[a].up = true; j[a].time = 1; } } } public void mouseReleased(MouseEvent me){ // 自機を下降させる if(!over){ for(int a = 0; a < 5; a++){ j[a].up = false; j[a].time = 1; } } } public void keyPressed(KeyEvent ke){ } public void keyReleased(KeyEvent ke) { // 押したキーの値を取得 int key = ke.getKeyCode(); // ゲームオーバー時の処理 if(over){ switch(key){ case KeyEvent.VK_ENTER: col = false; over = false; top = 20; bottom = 175; // 自機の再初期化 for(int a = 0; a < 5; a++){ j[a].jikiInit(); } // ブロックの再初期化 b.blockInit(); start = false; break; } } } public void keyTyped(KeyEvent ke) { } // プレイヤーが操作する物体のクラス class Jiki{ int x, y; // 現在の座標 int log_x, log_y; // 座標のログ int time; // 上昇、下降してからの経過時間 int x_first, y_first; // 座標の初期値 float gravity; // 天井と壁への引力 boolean up; // マウスがクリックされてるかどうか int vy_up, vy_down; // 上昇、下降時の速度 Jiki(int x, int y){ // コンストラクタ this.x = x; this.y = y; time = 1; gravity = 0.5f; x_first = x; y_first = y; log_x = 0; log_y = 0; up = false; vy_up = 0; vy_down = 0; gravity = 0.5f; } // マウスがクリックされてるかどうかで上昇、下降のどちらかを行う void move(){ if(!up){ y += ((int)(time * time * gravity / 4)) + vy_up + 1; vy_down = (int)(time * gravity); }else if(up){ y -= ((int)(time * time * gravity / 4)) - vy_down - 1; vy_up = -(int)(time * gravity); } // 上昇、下降してからの時間を更新 j[0].time++; } // ゲームをリスタートする場合に再初期化する void jikiInit(){ x = x_first; y = y_first; log_x = 0; log_y = 0; time = 1; up = false; vy_up = 0; vy_down = 0; } } // 前面から押し寄せてくるブロックのクラス class Block { int x[] = new int[256]; // ブロックの座標 int y[] = new int[256]; int width, height; // ブロックの幅と高さ int topLimit, bottomLimit; // ブロックが出現する高さの上限と下限 int time; // ブロックが出現する時間の間隔 int num; // 生成されたブロックの個数 boolean newBlock; // ブロックを新たに出現させるかどうか Block(){ // コンストラクタ for(int a = 0; a < 256; a++){ x[a] = 0; y[a] = 0; } width = 5; height = 30; topLimit = 20; bottomLimit = 125; time = 0; num = 0; newBlock = false; } // ゲームをリスタートする場合に再初期化する public void blockInit(){ for(int a = 0; a < num; a++){ x[a] = 0; y[a] = 0; } topLimit = 20; bottomLimit = 125; time = 0; num = 0; newBlock = false; } } }

実行結果はこちら!

考察

○Cavemanというゲームで、マウスをクリックしている間は上昇、離すと下降して、障害物をさけてできるだけ洞窟の奥まで進むゲームである。

○自分のケータイに4年前くらいから入っているゲームで、この課題を聞いたときから作ろうと思っていたが、難しくて、結局先輩のものを大幅に参考にした。

○手を加えた点は、タイトル画面、物体の色、出てくる壁の多さなど。ゲームの難易度を少し簡単にした。他にも試みたことは多いが、人のプログラムに手をつけると、すぐに動かなくなる。

反省・感想

 まず、期限を遅れて提出してしまったことを反省しています。今期は期限遅れ提出が多かった…
 この課題などは、じっくり考えながらやれば案外楽しいものだったと思いますが、提出を最優先したため、人のをほとんど真似るという結果になってしまいました。もう少し余裕を持って取り組めばよかった。
 これらの反省はこれからの講義に生かしたいと思います。1年間お世話になりました!