Comments
Description
Transcript
Animals_step3 - Infty Project
【Animals サンプル Step3】 張り付けた動物の上をクリックすると、それぞれの鳴き声で鳴く。 その鳴く間、一定時間(ここでは 1 秒間)画像が別のものに変わる <アニメーションの基礎:タイマーについて> アニメーションは、アプリケーションが指定する間、一定間隔でどんどん画像をおきかえていくもの である。 このサンプルでは、動物画像の上をクリックすると画像を切り替え、1 秒後、もとの画像に戻す操作を する。これは、1 秒間隔で2回の操作が必要となり、間隔も長いし操作回数が少ないが、ある意味アニメ ーションの一種となる。 Swing でアニメーションを簡単に実現するには、 javax.swing パッケージの Timer クラスを使う。 Timer によって一定間隔でイベントを発生させ、イベント処理をするメソッド(関数)に画像を描画しなおす 処理を記述すると、アニメーションになる。タイマーの作成方法は一般に以下のようになる。 Timer timer = new Timer(イベント発生間隔, アクションリスナ); timer.start(); // タイマーが発動する 具体的にはアクションイベント(ActionEvent)という種類のイベントが発生する。このイベントを処理 するのはアクションリスナ(ActionListener)というインターフェースを実装(implements)したクラスで、 必ず actionPerformed というメソッドをもつ。このメソッドにイベント処理の記述を行う。 <作成手順> 今回は MainPanel.java に必要な部分を書きたすだけでよい。 -1- MainPanel.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package animals; import import import import import import import import import import java.awt.Graphics; java.awt.Graphics2D; java.awt.SystemColor; java.awt.event.ActionEvent; java.awt.event.ActionListener; java.awt.event.MouseEvent; java.awt.event.MouseListener; java.io.File; java.util.ArrayList; java.util.List; import import import import import import import import import import javax.sound.sampled.AudioFormat; javax.sound.sampled.AudioInputStream; javax.sound.sampled.AudioSystem; javax.sound.sampled.Clip; javax.sound.sampled.DataLine; javax.swing.ImageIcon; javax.swing.JOptionPane; javax.swing.JPanel; javax.swing.SwingUtilities; javax.swing.Timer; public class MainPanel extends JPanel private private private private private private implements MouseListener, ActionListener{ int animalType = 0; // 動物の種類 Animal clickedAnimal = null; // List<ImageIcon> images; // List<ImageIcon> images2; // File[] audioFiles; // List<Animal> animals; // private int imgWidth = 100; private int imgHeight = 100; クリックされた動物 動物の画像リスト 画像2のリスト 音声ファイル 動物のリスト // 画像幅 // 画像高さ private int x,y; // クリックされた座標の一時保管用フィールド private private private private final String IMG = "img"; // 描画モードその1 final String IMG2 = "img2"; // 描画モードその2 String imgType = IMG; // 描画する画像の種類 int や boolean でも実装可能 Timer timer; /** * コンストラクタ */ public MainPanel() { super(); // マウスイベントを受け取れるようにする addMouseListener(this); // 初期化 /* List は直接 new できず、リストの種類を指定する必要がある。 * 普通に使う List は ArrayList で new すれば問題ない。*/ images = new ArrayList<ImageIcon>(); images2 = new ArrayList<ImageIcon>(); animals = new ArrayList<Animal>(); // タイマー生成 new Timer(ミリ秒でイベント発生間隔, アクションリスナ) /* 新たに ActionListener を implements したので * 自分自身をアクションリスナとして登録できる */ timer = new Timer(1000, this); // タイマーが発動するまでの遅延時間を設定(ミリ秒) timer.setInitialDelay(100); } -2- MainPanel.java 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 /** * ファイル数に応じて各インスタンスを初期化 * new したあと必ず呼ぶ * @throws MyException */ public void init() throws MyException { // img ディレクトリ、img2 ディレクトリを取得 /* File クラスはディレクトリを含むファイルの概念を表す * 相対パスで書くことができる */ File imgDir = new File("img"); File img2Dir = new File("img2"); // img ディレクトリにあるファイルを配列にして全て取り出す File imgFiles[] = imgDir.listFiles(); File img2Files[] = img2Dir.listFiles(); // ファイルの数が合わなかったら Exception if (imgFiles.length != img2Files.length) throw new MyException("画像ファイルの数が合いません"); // List に画像オブジェクトを追加 /* getAbsolutePath 関数:ファイルの絶対パスを String で返す*/ for (int i=0; i<imgFiles.length; i++) { images.add(new ImageIcon(imgFiles[i].getAbsolutePath())); images2.add(new ImageIcon(img2Files[i].getAbsolutePath())); } // サウンドファイルを sounds ディレクトリから取り出す audioFiles = (new File("sounds")).listFiles(); // 画像ファイルとサウンドファイルの数が合わなかったら Exception を発生させる if (imgFiles.length != audioFiles.length) throw new MyException("音声ファイルの数が合いません"); } /** * 描画メソッド<br> * repaint 関数から呼ばれる */ @Override public void paintComponent(Graphics g) { /* パネルにボタンなどが配置されているときのため * 今回は実際に意味はないが、慣例として忘れないよう書いておく*/ super.paintComponents(g); // より様々な描画方法が可能になるようにキャスト Graphics2D g2d = (Graphics2D)g; // システムカラー(背景色)を設定 g2d.setColor(SystemColor.control); // 画面をいったんクリア g2d.fillRect(0, 0, this.getWidth(), this.getHeight()); // 動物描画 /* Java5 からは可変長配列 List のループを以下ように書くことができる * animal には animals リストから順にとった Animal オブジェクトがはいる */ for (Animal animal : animals) { // 画像を描画 /* drawImage(画像オブジェクト, x 座標, y 座標, 幅, 高さ, ImageObserver) * ImageObserver は画像のロードを通知するもの。たいていは this でよい */ g2d.drawImage(images.get(animal.getAnimalType()).getImage(), animal.getCenterPoint().x-animal.getSize().width/2, animal.getCenterPoint().y-animal.getSize().height/2, animal.getSize().width, animal.getSize().height, this); } // 描画モードが"img"だったらタイマーで画像切り替えの必要はなくなる if (imgType.equals(IMG)) { // タイマーが動いていたらストップ if (timer.isRunning()) timer.stop(); -3- MainPanel.java 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 } // 描画モードが"img2"だったら鳴いてる動物の画像を描画しなおす else { // 画像その2を描画 g2d.drawImage(images2.get(clickedAnimal.getAnimalType()).getImage(), clickedAnimal.getCenterPoint().x-clickedAnimal.getSize().width/2, clickedAnimal.getCenterPoint().y-clickedAnimal.getSize().height/2, clickedAnimal.getSize().width, clickedAnimal.getSize().height, this); } } /** * マウスクリックで呼ばれる関数 */ @Override public void mouseClicked(MouseEvent e) { // クリックされた座標を取得 x = e.getX(); y = e.getY(); int onImageIndex = 0; // 画像上クリックなら index(動物の種類),そうでなければ ListSize /* animals の中の Animal オブジェクトを順に見て、クリックされた場所が * 動物画像の中に含まれるかどうかをみていく*/ for (Animal animal : animals) { // 動物画像の中でクリックされていたらループから抜ける if (animal.contains(x, y)) break; onImageIndex ++; } // 動物画像の中でクリックされていたら鳴き声を再生 if (onImageIndex < animals.size()) { try { // クリックされた動物を取得 clickedAnimal = animals.get(onImageIndex); // タイマーをスタートしてアクションイベントを発生させる // すると、actionPerformed メソッドが呼ばれる timer.start(); // 動物の種類に応じた鳴き声を再生 play(clickedAnimal.getAnimalType()); } catch (MyException ex) { // タイマーをとめて画像の描画モードを初期化 timer.stop(); imgType = IMG; // エラーをダイアログ表示 // JOptionPane.showMessageDialog(フレーム,メッセージ,タイトル,アイコンの種類) JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(this), ex.getMessage(), "再生エラー発生", JOptionPane.ERROR_MESSAGE); // 上と合わせて 1 行 } } // 動物画像の外でクリックされていたら画像を表示 else { // Animal オブジェクトを生成 Animal animal = new Animal(animalType, imgWidth, imgHeight); // 中心座標を設定 animal.setCenterPoint(x, y); // リストに追加 animals.add(animal); // 再描画 repaint(); } } -4- MainPanel.java 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 /** * 音声再生メソッド * @param index * @throws Exception */ private void play(int index) throws MyException { try { // オーディオ入力ストリームを取得 AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFiles[index]); // オーディオ形式を取得 // AU、AIFF、WAVE 形式に対応している AudioFormat format = audioStream.getFormat(); // データラインの情報(フォーマットなど)を作成 DataLine.Info di = new DataLine.Info(Clip.class, format); // 情報に基づいてラインを取得 // Clip はデータをメモリ上に読み込んでおいてから再生する Clip clip = (Clip) AudioSystem.getLine(di); // ラインを開く clip.open(audioStream); // ラインでのデータ入出力を可能にする clip.start(); // ラインからキューに入っているデータを排出 clip.drain(); } catch (Exception e) { throw new MyException("再生失敗:"+e.getMessage(), e); } } /* * * * MouseListener を implements しているため、 mouseClicked・mouseEntered・mouseExited・mousePressed・mouseReleased の 4つとも記述しなければならないが、このサンプルで使うのは mouseClicked だけなので後は空でよい。 */ @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } /** * Timer によるイベント発生時の実行メソッド */ @Override public void actionPerformed(ActionEvent e) { // 画像の描画モード"img"と"img2"をきりかえ if (imgType.equals(IMG)) { imgType = IMG2; } else { imgType = IMG; } // 描画 repaint(); } -5- MainPanel.java 253 254 255 256 257 258 259 260 261 /** * 動物の種類 setter * @param aimalType */ public void setAnimalType(int animalType) { this.animalType = animalType; } } -6-