6 『フレームワークとコンポーネント』

6.1 CUIアプリケーションフレームワーク

6.1.1 2つのアプリケーションの抽象化

6.1.1.1 成績管理アプリケーション

6.1.1.2 作文さんアプリケーション

6.1.1.3 抽象CUIアプリケーション

6.1.2 CUIアプリケーションフレームワークの構築

6.1.2.1 CUIアプリケーションフレームワーククラス図

6.1.2.2 CUIアプリケーション実行エンジン

リスト 6.1.2.2.1 CUIApplicationEngine.java
  1: import obpro.cui.Input;
  2: 
  3: /*
  4:  * CUIApplicationEngine.java
  5:  * Copyright(c) 2005 CreW Project. All rights reserved.
  6:  */
  7: 
  8: /**
  9:  * CUIアプリケーション フレームワーク 
 10:  * 実行エンジン
 11:  * 
 12:  * @author macchan
 13:  * @version 1.0
 14:  */
 15: public class CUIApplicationEngine {
 16: 
 17: 	public static void main(String[] args) {
 18: 		if (args.length != 1) {
 19: 			System.out.println("起動には引数が必要です");
 20: 			return;
 21: 		}
 22: 
 23: 		//アプリケーションを生成し,エンジンを起動する
 24: 		AbstractCUIApplication application = (AbstractCUIApplication) BReflection
 25: 				.createInstanceByName(args[0]);
 26: 		CUIApplicationEngine engine = new CUIApplicationEngine(application);
 27: 		engine.run();
 28: 	}
 29: 
 30: 	//実行するアプリケーション
 31: 	private AbstractCUIApplication application;
 32: 
 33: 	/**
 34: 	 * コンストラクタ
 35: 	 */
 36: 	private CUIApplicationEngine(AbstractCUIApplication application) {
 37: 		this.application = application;
 38: 	}
 39: 
 40: 	//アプリケーションを実行する
 41: 	private void run() {
 42: 		//アプリケーションの開始を知らせる
 43: 		application.showTitle();
 44: 
 45: 		//アプリケーションを実行する
 46: 		application.initializeData();
 47: 		executeProcessLoop();
 48: 
 49: 		//アプリケーションの終了を知らせる
 50: 		application.showEndTitle();
 51: 	}
 52: 
 53: 	//アプリケーションを実行する
 54: 	private void executeProcessLoop() {
 55: 		//アプリケーションを実行する
 56: 		while (true) {
 57: 			//コマンドの入力を受け取る
 58: 			String command = getCommand();
 59: 
 60: 			//コマンドを実行する
 61: 			if (command.equals(application.getQuitCommand())) {
 62: 				break;
 63: 			} else {
 64: 				application.executeCommand(command);
 65: 			}
 66: 		}
 67: 	}
 68: 
 69: 	//コマンド入力を受け取る
 70: 	private String getCommand() {
 71: 		//メニューを出力する
 72: 		application.showCommandMenu();
 73: 
 74: 		//コマンドの入力を受け取る
 75: 		String command = Input.getString();
 76: 		return command;
 77: 	}
 78: 
 79: }

6.1.2.3 抽象CUIアプリケーションクラス(スーパークラス)

リスト 6.1.2.3.1 AbstractCUIApplication.java
  1: /*
  2:  * AbstractCUIApplication.java
  3:  * Copyright(c) 2005 CreW Project. All rights reserved.
  4:  */
  5: 
  6: /**
  7:  * CUIアプリケーション フレームワーク 
  8:  * 抽象アプリケーションクラス(スーパークラス)
  9:  * 
 10:  * @author macchan
 11:  * @version 1.0
 12:  */
 13: public class AbstractCUIApplication {
 14: 
 15: 	/**
 16: 	 * アプリケーションの開始を知らせる
 17: 	 */
 18: 	public void showTitle() {
 19: 	}
 20: 
 21: 	/**
 22: 	 * アプリケーションの終了を知らせる
 23: 	 */
 24: 	public void showEndTitle() {
 25: 	}
 26: 
 27: 	/**
 28: 	 * データを初期化する
 29: 	 */
 30: 	public void initializeData() {
 31: 	}
 32: 
 33: 	/**
 34: 	 * コマンドメニューを表示する
 35: 	 */
 36: 	public void showCommandMenu() {
 37: 	}
 38: 
 39: 	/**
 40: 	 * 終了コマンドを取得する
 41: 	 */
 42: 	public String getQuitCommand() {
 43: 		return "q";
 44: 	}
 45: 
 46: 	/**
 47: 	 * コマンドを実行する
 48: 	 */
 49: 	public void executeCommand(String command) {
 50: 	}
 51: 
 52: }

6.1.3 適用例(1) 成績管理アプリケーション

6.1.3.1 成績管理アプリケーション(抽象CUIアプリケーションクラスを継承)

リスト 6.1.3.1.1 ScoreManager.java
  1: import java.util.ArrayList;
  2: import java.util.List;
  3: 
  4: import obpro.cui.Input;
  5: 
  6: /**
  7:  * 成績管理するアプリケーション(オブジェクト指向 その5)
  8:  * (フレームワークを使う)
  9:  * (エラー処理なし)
 10:  * 
 11:  * 下記のコマンドにより成績を管理できる
 12:  * ・成績の追加(コマンド:add)
 13:  * ・成績の削除(コマンド:del)
 14:  * ・成績の検索(コマンド:search)
 15:  * ・成績一覧と平均表示(コマンド:show)
 16:  * 
 17:  * @author Yoshiaki Matsuzawa
 18:  * @date 2005/07/7 オブプロ第12回
 19:  * @version 1.0
 20:  */
 21: public class ScoreManagerApplication extends AbstractCUIApplication {
 22: 
 23: 	// 定数
 24: 	final int NULL_INDEX = -1; // 添字未定を表現する数
 25: 
 26: 	final String ADD = "add";
 27: 	final String DELETE = "del";
 28: 	final String SEARCH = "search";
 29: 	final String SHOW = "show";
 30: 
 31: 	//成績データ
 32: 	private List scoreList;
 33: 
 34: 	//アプリケーションの開始を知らせる
 35: 	public void showTitle() {
 36: 		System.out.println("★★★★★★成績管理アプリケーション★★★★★★");
 37: 	}
 38: 
 39: 	//アプリケーションの終了を知らせる
 40: 	public void showEndTitle() {
 41: 		System.out.println("アプリケーションを終了します。");
 42: 	}
 43: 
 44: 	//データを初期化する
 45: 	public void initializeData() {
 46: 		scoreList = new ArrayList();
 47: 	}
 48: 
 49: 	//	メニューを出力する
 50: 	public void showCommandMenu() {
 51: 		System.out.print("コマンドを入力してください");
 52: 		System.out.print("(" + ADD + ":成績の追加");
 53: 		System.out.print(", " + DELETE + ":成績の削除");
 54: 		System.out.print(", " + SEARCH + ":成績の検索");
 55: 		System.out.print(", " + SHOW + ":成績一覧と平均点の表示");
 56: 		System.out.print(", " + getQuitCommand() + ":終了" + ")");
 57: 		System.out.println();
 58: 	}
 59: 
 60: 	//コマンドを実行する
 61: 	public void executeCommand(String command) {
 62: 		if (command.equals(ADD)) {
 63: 			addScore();
 64: 		} else if (command.equals(DELETE)) {
 65: 			deleteScore();
 66: 		} else if (command.equals(SEARCH)) {
 67: 			searchScore();
 68: 		} else if (command.equals(SHOW)) {
 69: 			showScoreList();
 70: 		} else {
 71: 			System.out.println("そのようなコマンドはありません");
 72: 		}
 73: 	}
 74: 
 75: 	//成績を追加する
 76: 	private void addScore() {
 77: 		//成績の入力を受け取る
 78: 		System.out.println("名前を入力してください");
 79: 		String name = Input.getString();
 80: 		System.out.println("成績を入力してください");
 81: 		int score = Input.getInt();
 82: 
 83: 		//成績を追加する
 84: 		scoreList.add(new Score(score, name));
 85: 
 86: 		//追加結果を出力する
 87: 		System.out.println("成績を登録しました");
 88: 	}
 89: 
 90: 	private void deleteScore() {
 91: 		//削除対象の入力を受け取る
 92: 		System.out.println("削除する成績の名前を入力してください");
 93: 		String name = Input.getString();
 94: 
 95: 		//成績を削除する
 96: 		int deleteIndex = searchScoreIndexByName(name);
 97: 		scoreList.remove(deleteIndex);
 98: 
 99: 		//削除結果を出力する
100: 		System.out.println("成績を削除しました");
101: 	}
102: 
103: 	//検索する
104: 	private void searchScore() {
105: 		//検索対象の入力を受け取る
106: 		System.out.println("検索する成績の名前を入力してください");
107: 		String name = Input.getString();
108: 
109: 		//検索する
110: 		int searchIndex = searchScoreIndexByName(name);
111: 
112: 		//検索結果を出力する
113: 		Score score = (Score) scoreList.get(searchIndex);
114: 		System.out.println(score.getName() + "さんの点数は" + score.getScore()
115: 				+ "点です");
116: 	}
117: 
118: 	//名前をキーに成績を検索する
119: 	private int searchScoreIndexByName(String name) {
120: 		for (int i = 0; i < scoreList.size(); i++) {
121: 			if (((Score) scoreList.get(i)).getName().equals(name)) {
122: 				return i;
123: 			}
124: 		}
125: 		return NULL_INDEX;
126: 	}
127: 
128: 	//成績一覧と平均点を表示する
129: 	private void showScoreList() {
130: 		//成績一覧を表示する
131: 		System.out.println("★★★★★★成績一覧表★★★★★★");
132: 		for (int i = 0; i < scoreList.size(); i++) {
133: 			Score score = (Score) scoreList.get(i);
134: 			System.out.println(score.getName() + "さん" + score.getScore() + "点");
135: 		}
136: 
137: 		//平均点を表示する
138: 		System.out.println("★★★★★★平均点★★★★★★");
139: 		double average = getAverageScore();
140: 		System.out.println("平均点:" + average + "点");
141: 	}
142: 
143: 	//平均点を計算する
144: 	private double getAverageScore() {
145: 		//合計点を計算する
146: 		double total = 0d;
147: 		for (int i = 0; i < scoreList.size(); i++) {
148: 			total = total + ((Score) scoreList.get(i)).getScore();
149: 		}
150: 
151: 		//平均点を計算する
152: 		double average = total / scoreList.size();
153: 
154: 		return average;
155: 	}
156: 
157: }

6.1.3.2 成績を表現するクラス

リスト 6.1.3.2.1 Score.java
  1: /**
  2:  * 成績を表現するクラス
  3:  * 
  4:  * @author Yoshiaki Matsuzawa
  5:  * @version 1.0
  6:  */
  7: public class Score {
  8: 
  9: 	private int score;
 10: 	private String name;
 11: 
 12: 	/**
 13: 	 * コンストラクタ
 14: 	 */
 15: 	public Score(int score, String name) {
 16: 		this.score = score;
 17: 		this.name = name;
 18: 	}
 19: 
 20: 	/**
 21: 	 * 名前を取得する 
 22: 	 */
 23: 	public String getName() {
 24: 		return this.name;
 25: 	}
 26: 
 27: 	/**
 28: 	 * 点数を取得する 
 29: 	 */
 30: 	public int getScore() {
 31: 		return this.score;
 32: 	}
 33: }

6.1.4 適用例(2)作文さんアプリケーション

6.1.4.1 作文さんアプリケーション(抽象CUIアプリケーションクラスを継承)

リスト 6.1.4.1.1 SakubunApplication.java
  1: import java.util.ArrayList;
  2: import java.util.List;
  3: 
  4: import obpro.cui.Input;
  5: 
  6: /*
  7:  * SakubunApplication.java
  8:  * Copyright(c) 2005 CreW Project. All rights reserved.
  9:  */
 10: 
 11: /**
 12:  * 作文さんアプリケーション
 13:  * 
 14:  * @author macchan
 15:  * @date 2005/07/7 オブプロ第12回
 16:  * @version 1.0
 17:  */
 18: public class SakubunApplication extends AbstractCUIApplication {
 19: 
 20: 	private List nouns = new ArrayList();
 21: 	private List verbs = new ArrayList();
 22: 
 23: 	//アプリケーションの開始を知らせる
 24: 	public void showTitle() {
 25: 		System.out.println("作文さん開始");
 26: 	}
 27: 
 28: 	//アプリケーションの終了を知らせる
 29: 	public void showEndTitle() {
 30: 		System.out.println("作文さん終了");
 31: 	}
 32: 
 33: 	//コマンドメニューを表示する
 34: 	public void showCommandMenu() {
 35: 		System.out.println("メニュー(1.名詞追加 2.動詞追加 3.作文 q.終了)");
 36: 	}
 37: 
 38: 	//コマンドを実行する
 39: 	public void executeCommand(String command) {
 40: 		if (command.equals("1")) {
 41: 			addNoun();
 42: 		} else if (command.equals("2")) {
 43: 			addVerb();
 44: 		} else if (command.equals("3")) {
 45: 			makeSentence();
 46: 		} else {
 47: 			System.out.println("無効なコマンドです");
 48: 		}
 49: 	}
 50: 
 51: 	//名詞を追加する
 52: 	private void addNoun() {
 53: 		System.out.println("名詞を入力してください");
 54: 		String noun = Input.getString();
 55: 		nouns.add(noun);
 56: 		System.out.println("名詞" + noun + "を追加しました");
 57: 	}
 58: 
 59: 	//動詞を追加する
 60: 	private void addVerb() {
 61: 		System.out.println("動詞を入力してください");
 62: 		String verb = Input.getString();
 63: 		verbs.add(verb);
 64: 		System.out.println("動詞" + verb + "を追加しました");
 65: 	}
 66: 
 67: 	//作文する
 68: 	private void makeSentence() {
 69: 		//語句を選ぶ
 70: 		String noun = (String) nouns.get((int) (Math.random() * nouns.size()));
 71: 		String verb = (String) verbs.get((int) (Math.random() * verbs.size()));
 72: 
 73: 		//結果を表示する
 74: 		System.out.println(noun + "は" + verb);
 75: 	}
 76: 
 77: }

6.2 GUIアニメーションアプリケーションフレームワーク

6.2.1 Rectangleアニメーション

6.2.2 抽象GUIアプリケーション

6.2.3 CUIアプリケーションフレームワーククラス図

6.2.4 GUIアプリケーション実行エンジン

リスト 6.2.4.1 GUIAnimationApplicationEngine.java
  1: import java.util.ArrayList;
  2: import java.util.List;
  3: 
  4: import obpro.gui.BCanvas;
  5: import obpro.gui.BWindow;
  6: 
  7: /*
  8:  * GUIAnimationApplicationEngine.java
  9:  * Copyright(c) 2005 CreW Project. All rights reserved.
 10:  */
 11: 
 12: /**
 13:  * GUIゲーム フレームワーク 
 14:  * 実行エンジン
 15:  * 
 16:  * @author macchan
 17:  * @version 1.0
 18:  */
 19: public class GUIAnimationApplicationEngine {
 20: 
 21: 	public static void main(String[] args) {
 22: 		if (args.length != 1) {
 23: 			System.out.println("起動には引数が必要です");
 24: 			return;
 25: 		}
 26: 
 27: 		//アプリケーションを生成し,エンジンを起動する
 28: 		AbstractGUIAnimationApplication application = (AbstractGUIAnimationApplication) BReflection
 29: 				.createInstanceByName(args[0]);
 30: 		GUIAnimationApplicationEngine engine = new GUIAnimationApplicationEngine(
 31: 				application);
 32: 		engine.run();
 33: 	}
 34: 
 35: 	//実行するアプリケーション
 36: 	private AbstractGUIAnimationApplication application;
 37: 
 38: 	//ウインドウ
 39: 	private BWindow window;
 40: 
 41: 	//アニメーションオブジェクトの集合
 42: 	private List elements = new ArrayList();
 43: 
 44: 	//1コマの秒数
 45: 	private double stepInterval = 0.03d;
 46: 
 47: 	/**
 48: 	 * コンストラクタ
 49: 	 */
 50: 	public GUIAnimationApplicationEngine(
 51: 			AbstractGUIAnimationApplication application) {
 52: 		this.application = application;
 53: 		application.setEngine(this);
 54: 	}
 55: 
 56: 	//アプリケーションを実行する
 57: 	private void run() {
 58: 		openWindow();
 59: 		application.prepareAnimationStart();//アニメーションの開始準備をする(オブジェクトなどを初期化する)
 60: 		doAnimation();
 61: 	}
 62: 
 63: 	//ウインドウを開く
 64: 	private void openWindow() {
 65: 		window = new BWindow();
 66: 		application.initializeWindow(window);
 67: 		window.show();
 68: 	}
 69: 
 70: 	//アニメーションする
 71: 	private void doAnimation() {
 72: 		//キャンバスを取得する
 73: 		BCanvas canvas = window.getCanvas();
 74: 
 75: 		//アニメーションする
 76: 		while (true) {
 77: 			{//1コマの処理を行う
 78: 				//ゲーム全体としての1コマの処理を行う
 79: 				application.processOneStepForApplication(canvas);
 80: 
 81: 				//各オブジェクトの1コマの処理を行う
 82: 				for (int i = 0; i < elements.size(); i++) {
 83: 					AnimationElement element = (AnimationElement) elements
 84: 							.get(i);
 85: 					element.processOneStep(canvas);
 86: 				}
 87: 			}
 88: 
 89: 			//図形を描く
 90: 			canvas.clear();
 91: 			application.drawForApplication(canvas);
 92: 			for (int i = 0; i < elements.size(); i++) {
 93: 				AnimationElement element = (AnimationElement) elements.get(i);
 94: 				element.draw(canvas);
 95: 			}
 96: 			canvas.update();
 97: 
 98: 			//眠る
 99: 			canvas.sleep(stepInterval);
100: 		}
101: 	}
102: 
103: 	/**
104: 	 * 1ステップの時間を設定する
105: 	 */
106: 	public void setStepInterval(double stepInterval) {
107: 		this.stepInterval = stepInterval;
108: 	}
109: 
110: 	/**
111: 	 * キャラクターを追加する
112: 	 */
113: 	public void addElement(AnimationElement element) {
114: 		elements.add(element);
115: 	}
116: 
117: 	/**
118: 	 * キャラクターを削除する
119: 	 */
120: 	public void removeElement(AnimationElement element) {
121: 		elements.remove(element);
122: 	}
123: 
124: }

6.2.5 抽象GUIアプリケーションクラス(スーパークラス)

リスト 6.2.5.1 AbstractGUIAnimationApplication.java
  1: import obpro.gui.BCanvas;
  2: import obpro.gui.BWindow;
  3: 
  4: /*
  5:  * AbstractGUIAnimationApplication.java
  6:  * Copyright(c) 2005 CreW Project. All rights reserved.
  7:  */
  8: 
  9: /**
 10:  * GUIゲーム フレームワーク 
 11:  * 抽象アプリケーションクラス(スーパークラス)
 12:  * 
 13:  * @author macchan
 14:  * @version 1.0
 15:  */
 16: public class AbstractGUIAnimationApplication {
 17: 
 18: 	private GUIAnimationApplicationEngine engine;
 19: 
 20: 	/**
 21: 	 * アプリケーションを駆動するエンジンを取得する(final:オーバーライド禁止)
 22: 	 */
 23: 	public final GUIAnimationApplicationEngine getEngine() {
 24: 		return this.engine;
 25: 	}
 26: 
 27: 	/**
 28: 	 * アプリケーションを駆動するエンジンを設定する(final:オーバーライド禁止)
 29: 	 */
 30: 	public final void setEngine(GUIAnimationApplicationEngine engine) {
 31: 		this.engine = engine;
 32: 	}
 33: 
 34: 	/**
 35: 	 * ウインドウの初期化をする
 36: 	 */
 37: 	public void initializeWindow(BWindow window) {
 38: 		window.setLocation(100, 100);
 39: 		window.setSize(640, 480);
 40: 	}
 41: 
 42: 	/**
 43: 	 * アニメーション開始の準備をする
 44: 	 */
 45: 	public void prepareAnimationStart() {
 46: 	}
 47: 
 48: 	/**
 49: 	 * 1ステップの処理をする
 50: 	 */
 51: 	public void processOneStepForApplication(BCanvas canvas) {
 52: 	}
 53: 
 54: 	/**
 55: 	 * 描画する
 56: 	 */
 57: 	public void drawForApplication(BCanvas canvas) {
 58: 	}
 59: 
 60: }

6.3 シューティングゲーム

6.3.1 シューティングゲーム(6)(フレームワークのコンポーネントとする)

リスト 6.3.1.1 ShootingGame6.java
  1: import java.util.ArrayList;
  2: import java.util.List;
  3: 
  4: import obpro.gui.BCanvas;
  5: import obpro.sound.BSound;
  6: 
  7: /**
  8:  * シューティングゲームサンプル(その6 フレームワークのコンポーネントとする) 
  9:  * 
 10:  * @author macchan
 11:  * @date 2005/07/7 オブプロ第12回
 12:  * @version 1.0
 13:  */
 14: public class ShootingGame6 extends AbstractGUIAnimationApplication {
 15: 
 16: 	//種類別アニメーションオブジェクト
 17: 	private Background background;
 18: 	private ScoreBoard scoreBoard;
 19: 	private PlayerAircraft player;
 20: 	private List enemies = new ArrayList();
 21: 	private List bullets = new ArrayList();
 22: 	
 23: 	//BGM
 24: 	BSound bgm;
 25: 
 26: 	/**
 27: 	 * 各オブジェクトを初期化する
 28: 	 */
 29: 	public void prepareAnimationStart() {
 30: 		//ステップの間隔を設定する
 31: 		getEngine().setStepInterval(0.01);
 32: 
 33: 		//BGM
 34: 		initializeSounds();
 35: 		bgm.loop();
 36: 
 37: 		//背景
 38: 		background = new Background();
 39: 		getEngine().addElement(background);
 40: 
 41: 		//得点板
 42: 		scoreBoard = new ScoreBoard(100, 30, 0, 0);
 43: 		getEngine().addElement(scoreBoard);
 44: 
 45: 		//プレイヤー
 46: 		player = new PlayerAircraft(50, 50, this);
 47: 		getEngine().addElement(player);
 48: 	}
 49: 	
 50: 	/**
 51: 	 * サウンドを初期化する
 52: 	 */
 53: 	private void initializeSounds() {
 54: 		//BGM
 55: 		bgm = new BSound("sound/bgm.mp3");
 56: 
 57: 		//効果音はメモリ上に読み込む
 58: 		BSound.load("sound/explode_enemy.mp3");
 59: 		BSound.load("sound/explode_player.mp3");
 60: 		BSound.load("sound/fire.mp3");
 61: 		BSound.load("sound/optionvoice.mp3");
 62: 		BSound.load("sound/powerup.mp3");
 63: 	}
 64: 
 65: 	/**
 66: 	 * ゲーム全体としての1ステップの処理を行う
 67: 	 */
 68: 	public void processOneStepForApplication(BCanvas canvas) {
 69: 		//敵を出す
 70: 		int randomNumber = (int) (Math.random() * 30);//確率1/30コマの抽選
 71: 		if (randomNumber == 0) {
 72: 			int y = (int) (Math.random() * canvas.getCanvasHeight());//y座標決め抽選
 73: 			EnemyAircraft enemy = new EnemyAircraft(canvas.getCanvasWidth(), y,
 74: 					this);
 75: 			addEnemy(enemy);
 76: 		}
 77: 
 78: 		//自機と敵の当たり判定とあたった場合の処理を行う
 79: 		for (int i = 0; i < enemies.size(); i++) {
 80: 			EnemyAircraft enemy = (EnemyAircraft) enemies.get(i);
 81: 			if (enemy.isAlive() && player.intersects(enemy)) {
 82: 				player.explode();
 83: 			}
 84: 		}
 85: 
 86: 		//弾と敵の当たり判定とあたった場合の処理を行う
 87: 		for (int i = 0; i < enemies.size(); i++) {
 88: 			EnemyAircraft enemy = (EnemyAircraft) enemies.get(i);
 89: 			for (int j = 0; j < bullets.size(); j++) {
 90: 				Bullet bullet = (Bullet) bullets.get(j);
 91: 				if (bullet.isAlive() && enemy.isAlive()
 92: 						&& enemy.intersects(bullet)) {
 93: 					enemy.explode();
 94: 					bullet.destroy();
 95: 					scoreBoard.addScore(100);
 96: 				}
 97: 			}
 98: 		}
 99: 	}
100: 
101: 	/**
102: 	 * 敵を追加する
103: 	 */
104: 	public void addEnemy(EnemyAircraft enemy) {
105: 		enemies.add(enemy);
106: 		getEngine().addElement(enemy);
107: 	}
108: 
109: 	/**
110: 	 * 敵を削除する
111: 	 */
112: 	public void removeEnemy(EnemyAircraft enemy) {
113: 		enemies.remove(enemy);
114: 		getEngine().removeElement(enemy);
115: 	}
116: 
117: 	/**
118: 	 * 弾を追加する
119: 	 */
120: 	public void addBullet(Bullet bullet) {
121: 		bullets.add(bullet);
122: 		getEngine().addElement(bullet);
123: 	}
124: 
125: 	/**
126: 	 * 弾を削除する
127: 	 */
128: 	public void removeBullet(Bullet bullet) {
129: 		bullets.remove(bullet);
130: 		getEngine().removeElement(bullet);
131: 	}
132: 
133: }

6.3.2 アニメーションするオブジェクトすべてのスーパークラス

リスト 6.3.2.1 AnimationElement.java
  1: import obpro.gui.BCanvas;
  2: 
  3: /**
  4:  * アニメーションするオブジェクトすべてのスーパークラス
  5:  */
  6: public class AnimationElement {
  7: 
  8: 	/**
  9: 	 * 1ステップの処理をする
 10: 	 */
 11: 	public void processOneStep(BCanvas canvas) {
 12: 	}
 13: 
 14: 	/**
 15: 	 * 描画する
 16: 	 */
 17: 	public void draw(BCanvas canvas) {
 18: 	}
 19: 
 20: }

6.3.3 背景を表現するクラス

リスト 6.3.3.1 Background.java
  1: import obpro.gui.BCanvas;
  2: 
  3: /**
  4:  * 背景を表現するクラス
  5:  */
  6: public class Background extends AnimationElement {
  7: 
  8: 	private int x1 = 0;
  9: 	private int x2 = 1000;
 10: 
 11: 	/**
 12: 	 * 1ステップの処理をする(オーバーライド)
 13: 	 */
 14: 	public void processOneStep(BCanvas canvas) {
 15: 		x1--;
 16: 		if (x1 < -1000) {
 17: 			x1 = 1000;
 18: 		}
 19: 		x2--;
 20: 		if (x2 < -1000) {
 21: 			x2 = 1000;
 22: 		}
 23: 	}
 24: 
 25: 	/**
 26: 	 * 描画する(オーバーライド)
 27: 	 */
 28: 	public void draw(BCanvas canvas) {
 29: 		canvas.drawImage("img/background.jpg", x1, 0);
 30: 		canvas.drawImage("img/background.jpg", x2, 0);
 31: 	}
 32: 
 33: }

6.3.4 ゲームのキャラクターを表現するクラス

リスト 6.3.4.1 Character.java
  1: /**
  2:  * ゲームのキャラクターを表現するクラス
  3:  */
  4: public class Character extends AnimationElement {
  5: 
  6: 	//属性
  7: 	private int x = 0;
  8: 	private int y = 0;
  9: 	private int width = 0;
 10: 	private int height = 0;
 11: 
 12: 	/**
 13: 	 * コンストラクタ
 14: 	 */
 15: 	public Character(int x, int y, int width, int height) {
 16: 		this.x = x;
 17: 		this.y = y;
 18: 		this.width = width;
 19: 		this.height = height;
 20: 	}
 21: 
 22: 	/**
 23: 	 * 高さを取得する
 24: 	 */
 25: 	public int getHeight() {
 26: 		return this.height;
 27: 	}
 28: 
 29: 	/**
 30: 	 * 幅を取得する
 31: 	 */
 32: 	public int getWidth() {
 33: 		return this.width;
 34: 	}
 35: 
 36: 	/**
 37: 	 * X座標を取得する
 38: 	 */
 39: 	public int getX() {
 40: 		return this.x;
 41: 	}
 42: 
 43: 	/**
 44: 	 * Y座標を取得する
 45: 	 */
 46: 	public int getY() {
 47: 		return this.y;
 48: 	}
 49: 
 50: 	/**
 51: 	 * 位置を再設定する
 52: 	 */
 53: 	public void setLocation(int newX, int newY) {
 54: 		x = newX;
 55: 		y = newY;
 56: 	}
 57: 
 58: 	/**
 59: 	 * 動かす
 60: 	 */
 61: 	public void move(int moveX, int moveY) {
 62: 		x = x + moveX;
 63: 		y = y + moveY;
 64: 	}
 65: 
 66: 	/**
 67: 	 * 他のキャラクターとの衝突判定をする
 68: 	 */
 69: 	public boolean intersects(Character another) {
 70: 		int self_leftX = this.getX();
 71: 		int self_rightX = this.getX() + this.getWidth();
 72: 		int another_leftX = another.getX();
 73: 		int another_rightX = another.getX() + another.getWidth();
 74: 		int self_topY = this.getY();
 75: 		int self_bottomY = this.getY() + this.getHeight();
 76: 		int another_topY = another.getY();
 77: 		int another_bottomY = another.getY() + another.getHeight();
 78: 
 79: 		return (another_leftX < self_rightX && another_rightX > self_leftX
 80: 				&& another_topY < self_bottomY && another_bottomY > self_topY);
 81: 	}
 82: }

6.3.5 自機を表現するクラス

リスト 6.3.5.1 PlayerAircraft.java
  1: import java.util.ArrayList;
  2: import java.util.List;
  3: 
  4: import obpro.gui.BCanvas;
  5: import obpro.sound.BSound;
  6: 
  7: /**
  8:  * 自機を表現するクラス
  9:  */
 10: public class PlayerAircraft extends Character {
 11: 
 12: 	//定数
 13: 	private final int ALIVE = 1;
 14: 	private final int EXPLODING = 2;
 15: 	private final int DEAD = 3;
 16: 
 17: 	private final int EXPLODING_ANIMATION_SIZE = 11;
 18: 
 19: 	//状態
 20: 	private int liveState = ALIVE;
 21: 	private int explodingCount = 0;
 22: 
 23: 	//関連参照
 24: 	private ShootingGame6 game;
 25: 	private List options = new ArrayList();
 26: 
 27: 	/**
 28: 	 * コンストラクタ
 29: 	 */
 30: 	public PlayerAircraft(int x, int y, ShootingGame6 game) {
 31: 		super(x, y, 100, 50);
 32: 		this.game = game;
 33: 	}
 34: 
 35: 	/**
 36: 	 * 動く
 37: 	 */
 38: 	public void move(int moveX, int moveY) {
 39: 		//自機を動かす
 40: 		super.move(moveX, moveY);
 41: 
 42: 		//オプションを動かす
 43: 		for (int i = 0; i < options.size(); i++) {
 44: 			Option option = (Option) options.get(i);
 45: 			option.move(moveX, moveY);
 46: 		}
 47: 	}
 48: 
 49: 	/**
 50: 	 * 1ステップの処理をする(オーバーライド)
 51: 	 */
 52: 	public void processOneStep(BCanvas canvas) {
 53: 		if (liveState == ALIVE) {
 54: 			//矢印キー入力によって自機を操作する
 55: 			if (canvas.isKeyPressing(37)) {//左キー
 56: 				move(-5, 0);
 57: 			}
 58: 			if (canvas.isKeyPressing(38)) {//上キー
 59: 				move(0, -5);
 60: 			}
 61: 			if (canvas.isKeyPressing(39)) {//右キー
 62: 				move(5, 0);
 63: 			}
 64: 			if (canvas.isKeyPressing(40)) {//下キー
 65: 				move(0, 5);
 66: 			}
 67: 
 68: 			//Fキー入力によって弾を出す
 69: 			if (canvas.isKeyDown()) {
 70: 				int keyCode = canvas.getKeyCode();
 71: 				if (keyCode == 70) {//fキー
 72: 					fire();
 73: 				}
 74: 			}
 75: 
 76: 			//Gキー入力によってオプションを出す
 77: 			if (canvas.isKeyDown()) {
 78: 				int keyCode = canvas.getKeyCode();
 79: 				if (keyCode == 71) {//gキー
 80: 					BSound.play("sound/optionvoice.mp3", 100);
 81: 					BSound.play("sound/powerup.mp3");
 82: 					options.add(new Option(getX(), getY(), getWidth(),
 83: 							getHeight(), options.size() + 1));
 84: 				}
 85: 			}
 86: 
 87: 			//オプションの1ステップの処理を行なう
 88: 			for (int i = 0; i < options.size(); i++) {
 89: 				Option option = (Option) options.get(i);
 90: 				option.processOneStep(canvas);
 91: 			}
 92: 		} else if (liveState == EXPLODING) {
 93: 			processExplode();
 94: 		}
 95: 	}
 96: 
 97: 	/**
 98: 	 * 活きているかどうか調べる
 99: 	 */
100: 	public boolean isAlive() {
101: 		return liveState == ALIVE;
102: 	}
103: 
104: 	/**
105: 	 * 爆発の処理をする
106: 	 */
107: 	private void processExplode() {
108: 		explodingCount++;
109: 		if (explodingCount >= EXPLODING_ANIMATION_SIZE) {
110: 			liveState = DEAD;
111: 		}
112: 	}
113: 
114: 	/**
115: 	 * 爆発する(爆発状態に遷移する)
116: 	 */
117: 	public void explode() {
118: 		if (liveState == ALIVE) {
119: 			liveState = EXPLODING;
120: 			explodingCount = 0;
121: 			BSound.play("sound/explode_player.mp3");
122: 		}
123: 	}
124: 
125: 	/**
126: 	 * 描画する(オーバーライド)
127: 	 */
128: 	public void draw(BCanvas canvas) {
129: 		if (liveState == ALIVE) {
130: 			//自機を書く
131: 			drawAircraft(canvas);
132: 
133: 			//オプションを書く
134: 			for (int i = 0; i < options.size(); i++) {
135: 				Option option = (Option) options.get(i);
136: 				option.draw(canvas);
137: 			}
138: 		} else if (liveState == EXPLODING) {
139: 			drawExplosion(canvas);
140: 		}
141: 	}
142: 
143: 	/**
144: 	 * 飛行機を描画する
145: 	 */
146: 	private void drawAircraft(BCanvas canvas) {
147: 		canvas.drawImage("img/player.png", getX(), getY(), getWidth(),
148: 				getHeight());
149: 	}
150: 
151: 	/**
152: 	 * 爆発を描画する
153: 	 */
154: 	private void drawExplosion(BCanvas canvas) {
155: 		canvas.drawImage("img/explode" + (explodingCount + 1) + ".gif",
156: 				getX(), getY(), getWidth(), getHeight());
157: 	}
158: 
159: 	/**
160: 	 * 弾を出す
161: 	 */
162: 	private void fire() {
163: 		if (liveState == ALIVE) {
164: 			BSound.play("sound/fire.mp3");
165: 
166: 			//自機の弾を出す
167: 			fire(this);
168: 
169: 			//オプションの弾を出す
170: 			for (int i = 0; i < options.size(); i++) {
171: 				Option option = (Option) options.get(i);
172: 				fire(option);
173: 			}
174: 		}
175: 	}
176: 
177: 	/**
178: 	 * (オプション一つごとの)弾を出す
179: 	 */
180: 	private void fire(Character shooter) {
181: 		Bullet bullet = new Bullet(0, 0, 20, 10, game);
182: 		int x = shooter.getX() + shooter.getWidth() / 2 - bullet.getWidth() / 2;
183: 		int y = shooter.getY() + shooter.getHeight() / 2 - bullet.getHeight()
184: 				/ 2;
185: 		bullet.setLocation(x, y);
186: 		game.addBullet(bullet);
187: 	}
188: }

6.3.6 敵機を表現するクラス

リスト 6.3.6.1 EnemyAircraft.java
  1: import obpro.gui.BCanvas;
  2: import obpro.sound.BSound;
  3: 
  4: /**
  5:  * 敵機を表現するクラス
  6:  */
  7: public class EnemyAircraft extends Character {
  8: 
  9: 	//定数
 10: 	private final int ALIVE = 1;
 11: 	private final int EXPLODING = 2;
 12: 	private final int DEAD = 3;
 13: 
 14: 	private final int EXPLODING_ANIMATION_SIZE = 11;
 15: 
 16: 	//状態
 17: 	private int liveState = ALIVE;
 18: 	private int explodingCount = 0;
 19: 
 20: 	//関連参照
 21: 	private ShootingGame6 game;
 22: 
 23: 	/**
 24: 	 * コンストラクタ
 25: 	 */
 26: 	public EnemyAircraft(int x, int y, ShootingGame6 game) {
 27: 		super(x, y, 100, 50);
 28: 		this.game = game;
 29: 	}
 30: 
 31: 	/**
 32: 	 * 1ステップの処理をする(オーバーライド)
 33: 	 */
 34: 	public void processOneStep(BCanvas canvas) {
 35: 		if (liveState == ALIVE) {
 36: 			//動く
 37: 			move(-5, 0);
 38: 
 39: 			//画面(左)外に出たら消滅
 40: 			if (getX() < -100) {
 41: 				destroy();
 42: 			}
 43: 		} else if (liveState == EXPLODING) {
 44: 			processExplode();
 45: 		}
 46: 	}
 47: 
 48: 	/**
 49: 	 * 活きているかどうか調べる
 50: 	 */
 51: 	public boolean isAlive() {
 52: 		return liveState == ALIVE;
 53: 	}
 54: 
 55: 	/**
 56: 	 * 消滅する
 57: 	 */
 58: 	public void destroy() {
 59: 		game.removeEnemy(this);
 60: 		liveState = DEAD;
 61: 	}
 62: 
 63: 	/**
 64: 	 * 爆発の処理をする
 65: 	 */
 66: 	private void processExplode() {
 67: 		explodingCount++;
 68: 		if (explodingCount >= EXPLODING_ANIMATION_SIZE) {
 69: 			destroy();
 70: 		}
 71: 	}
 72: 
 73: 	/**
 74: 	 * 爆発する(爆発状態に遷移する)
 75: 	 */
 76: 	public void explode() {
 77: 		if (liveState == ALIVE) {
 78: 			liveState = EXPLODING;
 79: 			explodingCount = 0;
 80: 			BSound.play("sound/explode_enemy.mp3");
 81: 		}
 82: 	}
 83: 
 84: 	/**
 85: 	 * 描画する(オーバーライド)
 86: 	 */
 87: 	public void draw(BCanvas canvas) {
 88: 		if (liveState == ALIVE) {
 89: 			drawAircraft(canvas);
 90: 		} else if (liveState == EXPLODING) {
 91: 			drawExplosion(canvas);
 92: 		}
 93: 	}
 94: 
 95: 	/**
 96: 	 * 飛行機を描画する
 97: 	 */
 98: 	private void drawAircraft(BCanvas canvas) {
 99: 		canvas.drawImage("img/enemy.png", getX(), getY(), getWidth(),
100: 				getHeight());
101: 	}
102: 
103: 	/**
104: 	 * 爆発を描画する
105: 	 */
106: 	private void drawExplosion(BCanvas canvas) {
107: 		canvas.drawImage("img/explode" + (explodingCount + 1) + ".gif",
108: 				getX(), getY(), getWidth(), getHeight());
109: 	}
110: 
111: }

6.3.7 弾を表現するクラス

リスト 6.3.7.1 Bullet.java
  1: import java.awt.Color;
  2: 
  3: import obpro.gui.BCanvas;
  4: 
  5: /**
  6:  * 弾を表現するクラス
  7:  */
  8: public class Bullet extends Character {
  9: 
 10: 	//定数
 11: 	private final int ALIVE = 1;
 12: 	private final int DEAD = 2;
 13: 
 14: 	//状態
 15: 	private int liveState = ALIVE;
 16: 
 17: 	//関連参照
 18: 	private ShootingGame6 game;
 19: 
 20: 	//属性
 21: 	private Color color = new Color(0, 0, 255);
 22: 
 23: 	/**
 24: 	 * コンストラクタ
 25: 	 */
 26: 	public Bullet(int x, int y, int width, int height, ShootingGame6 game) {
 27: 		super(x, y, width, height);
 28: 		this.game = game;
 29: 	}
 30: 
 31: 	/**
 32: 	 * 1ステップの処理をする(オーバーライド)
 33: 	 */
 34: 	public void processOneStep(BCanvas canvas) {
 35: 		if (liveState == ALIVE) {
 36: 			//動かす
 37: 			move(15, 0);
 38: 
 39: 			//画面外に出た場合の処理
 40: 			if (getX() > canvas.getCanvasWidth()) {
 41: 				destroy();
 42: 			}
 43: 		}
 44: 	}
 45: 
 46: 	/**
 47: 	 * 弾を消滅させる(無効化する)
 48: 	 */
 49: 	public void destroy() {
 50: 		if (liveState == ALIVE) {
 51: 			liveState = DEAD;
 52: 			game.removeBullet(this);
 53: 		}
 54: 	}
 55: 
 56: 	/**
 57: 	 * 弾が有効かどうか調べる
 58: 	 */
 59: 	public boolean isAlive() {
 60: 		return liveState == ALIVE;
 61: 	}
 62: 
 63: 	/**
 64: 	 * 描画する(オーバーライド)
 65: 	 */
 66: 	public void draw(BCanvas canvas) {
 67: 		if (liveState == ALIVE) {
 68: 			canvas.drawFillTriangle(color, getX(), getY(), getX() + getWidth(),
 69: 					getY(), getX(), getY() + getHeight());
 70: 			canvas.drawFillTriangle(color, getX(), getY() + getHeight(), getX()
 71: 					+ getWidth(), getY() + getHeight(), getX() + getWidth(),
 72: 					getY());
 73: 		}
 74: 	}
 75: 
 76: }

6.3.8 オプションを表現するクラス

リスト 6.3.8.1 Option.java
  1: import java.util.LinkedList;
  2: 
  3: import obpro.gui.BCanvas;
  4: 
  5: /**
  6:  * オプションを表現するクラス
  7:  */
  8: public class Option extends Character {
  9: 
 10: 	//定数
 11: 	private final int HISTORY_INTERVAL = 15;
 12: 	private final int SCALE_UP = 1;
 13: 	private final int SCALE_DOWN = 2;
 14: 
 15: 	//アニメーション状態
 16: 	private int animationState = SCALE_UP;
 17: 	private int animationCount = 0;
 18: 
 19: 	//プレイヤーの動きの履歴
 20: 	private LinkedList playerMoveHistories = new LinkedList();
 21: 
 22: 	/**
 23: 	 * コンストラクタ
 24: 	 */
 25: 	public Option(int x, int y, int width, int height, int index) {
 26: 		super(x, y, width, height);
 27: 		initializeHistories(index);
 28: 	}
 29: 
 30: 	/**
 31: 	 * 履歴を初期化する
 32: 	 */
 33: 	private void initializeHistories(int index) {
 34: 		for (int i = 0; i < HISTORY_INTERVAL * index; i++) {
 35: 			playerMoveHistories.add(new MoveData());
 36: 		}
 37: 	}
 38: 
 39: 	/**
 40: 	 * 動く
 41: 	 * (playerMoveHistoriesを履歴キューとして使っています)
 42: 	 */
 43: 	public void move(int moveX, int moveY) {
 44: 		//履歴の最後のデータを取得し,動く
 45: 		MoveData moveData = (MoveData) playerMoveHistories.removeFirst();
 46: 		super.move(moveData.dx, moveData.dy);
 47: 
 48: 		//今回の動きを履歴に加える
 49: 		moveData.dx = moveX;
 50: 		moveData.dy = moveY;
 51: 		playerMoveHistories.addLast(moveData);
 52: 	}
 53: 
 54: 	/**
 55: 	 * 1ステップの処理を行なう
 56: 	 */
 57: 	public void processOneStep(BCanvas canvas) {
 58: 		//アニメーションカウンターを増やす
 59: 		if (animationState == SCALE_UP) {
 60: 			animationCount++;
 61: 		} else if (animationState == SCALE_DOWN) {
 62: 			animationCount--;
 63: 		}
 64: 
 65: 		//状態遷移をする
 66: 		if (animationState == SCALE_UP && animationCount >= 10) {
 67: 			animationState = SCALE_DOWN;
 68: 		} else if (animationState == SCALE_DOWN && animationCount <= 0) {
 69: 			animationState = SCALE_UP;
 70: 		}
 71: 	}
 72: 
 73: 	/**
 74: 	 * 描画処理を行なう
 75: 	 */
 76: 	public void draw(BCanvas canvas) {
 77: 		int w = getWidth() / 3 + animationCount;
 78: 		int h = getHeight() / 3 + animationCount;
 79: 		int x = getX() + (getWidth() - w) / 2;
 80: 		int y = getY() + (getHeight() - h) / 2;
 81: 		canvas.drawImage("img/option.png", x, y, w, h);
 82: 	}
 83: 
 84: 	/**
 85: 	 * 移動を表現する内部クラス
 86: 	 * このクラス内でのみ使うので,ここで定義している
 87: 	 */
 88: 	class MoveData {
 89: 		int dx = 0;
 90: 		int dy = 0;
 91: 	}
 92: }

6.3.9 得点板を表現するクラス

リスト 6.3.9.1 ScoreBoard.java
  1: import java.awt.Color;
  2: import java.awt.Font;
  3: 
  4: import obpro.gui.BCanvas;
  5: 
  6: /**
  7:  * スコア掲示板を表現するクラス
  8:  */
  9: public class ScoreBoard extends Character {
 10: 
 11: 	private Font font = new Font("Dialog", Font.PLAIN, 24);
 12: 	private Color color = new Color(255, 255, 255);
 13: 	private int score;
 14: 
 15: 	/**
 16: 	 * コンストラクタ
 17: 	 */
 18: 	public ScoreBoard(int x, int y, int width, int height) {
 19: 		super(x, y, width, height);
 20: 	}
 21: 
 22: 	/**
 23: 	 * 得点を加える
 24: 	 */
 25: 	public void addScore(int score) {
 26: 		this.score += score;
 27: 	}
 28: 
 29: 	/**
 30: 	 * 得点を消去する(現在は使われていない)
 31: 	 */
 32: 	public void resetScore() {
 33: 		this.score = 0;
 34: 	}
 35: 
 36: 	/**
 37: 	 * 描画する
 38: 	 */
 39: 	public void draw(BCanvas canvas) {
 40: 		canvas.drawText(color, "SCORE  " + score, getX(), getY(), font);
 41: 	}
 42: 
 43: }