---
# System prepended metadata

title: Project documentation template
tags: [Java, オブジェクト指向演習]

---

---
title: 'Project documentation template'
disqus: hackmd
---

## もぐもぐフェスティバル（再インストールガチ勢）
===

## 目次

[TOC]

## 遊び方

15秒間でどれだけモグラを叩けたかを競うゲームです。
1人プレイの際は10回以上たたくとゲームクリアです。


工夫点・改造内容
---

もぐもぐフェスティバルはモグラたたきをモチーフにしたゲームです。
モグラたたきは今から約40年前に登場したゲームで、ストレスという言葉が世の中に
浸透したころにストレスの発散を要因として流行しました。
なので、本ゲームもストレスの発散を促すように愛らしいモグラをたたくことによって
まるで、子供と遊んでいるかのような体験を提供できるゲームを目指しました。

改造前のプログラムでは、出現するモグラがただの黄色の丸い図形でした。音楽もなく、時間制限の表示もなかったので、ゲームとして全く楽しめるものではありませんでした。なので、BGMとモグラのイラストをつけ、ゲームの楽しさを表現し、SCORE目標を設定することでゲーム性をもたせました。


![](https://i.imgur.com/hS6dYXw.jpg)　　　→→→　　![](https://i.imgur.com/VMG0QYz.jpg)

変更前　　　　　　　　　　　　　　　　　　　　　　　　　　変更後

jarファイルダウンロード
---
https://drive.google.com/file/d/1DrGFvJ__10PlhlZI6ECC7HUTdpiIEO4w/view?usp=sharing

分担
---
・19T005  太田  来夢：企画・進行および現場監督兼リーダー。ゲーム調整。
・19T007  大本  航　：モグラの作成。ゲーム調整。web作成。
・19T019  小林  直矢：BGMの挿入。ゲーム調整。
・19T037  野上  遼太：jarファイルへの変換、アップロード。web作成。

改造前のプログラム
---
```gherkin=
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.JFrame;

public class MainClass extends JFrame {
private final static int WINDOW_SIZE = 300;
private final static int MOLE_SIZE = 50;
private final static int GAME_END_COUNT = 20;

private int score = 0;
private int counter = 0;
private int mole_x;
private int mole_y;
private boolean mole_hit = false;

public static void main(String[] args) {
new MainClass();
}

public MainClass() {
setSize(WINDOW_SIZE, WINDOW_SIZE);

// リスナー
GameMouseAdapter adapter = new GameMouseAdapter();
addMouseListener(adapter);

setVisible(true);

Timer t = new Timer();
t.schedule(new GameTimeTask(), 1000l, 1000l);
}

private class GameTimeTask extends TimerTask {
@Override
public void run() {
if (counter++ <= GAME_END_COUNT) return; // ゲームオーバー
mole_hit = false; // 新しいモグラなのでヒット前
mole_x = (int)(Math.random() * (WINDOW_SIZE-MOLE_SIZE));
mole_y = (int)(Math.random() * (WINDOW_SIZE-MOLE_SIZE));
repaint();
}

}

private class GameMouseAdapter extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
if (mole_hit) return; // モグラがやられている時は判定しない
int x = e.getPoint().x;
int y = e.getPoint().y;
int hankei = MOLE_SIZE/2;
int mx = mole_x+hankei;
int my = mole_y+hankei;
int x_kyori = x-mx;
int y_kyori = y-my;
if (x_kyori*x_kyori+y_kyori*y_kyori < hankei*hankei) {
score++;
mole_hit = true;
}
// 描画する
repaint();
}
}

public void paint(Graphics g) {
g.drawImage(drawScreen(), 0, 0, this);
}

private Image drawScreen() {
Image screen = createImage(WINDOW_SIZE, WINDOW_SIZE);
Graphics2D g = (Graphics2D)screen.getGraphics();

// スコア表示
g.setColor(Color.BLACK);
g.drawString(“”SCORE：”” + score, 50, 50);

if (counter<=GAME_END_COUNT) {
g.drawString(“”GAME OVER””, 100, 100);
return screen;
}

// モグラ描画
if (mole_hit)
g.setColor(Color.RED);
else
g.setColor(Color.YELLOW);
g.fillOval(mole_x, mole_y, MOLE_SIZE, MOLE_SIZE);
g.setColor(Color.BLACK);
g.drawOval(mole_x, mole_y, MOLE_SIZE, MOLE_SIZE);

return screen;
}
}
```

> ソースプログラムが掲載されたサイトはこちらから: https://www.fenet.jp/java/column/java_tips/6175/


ソースプログラム（改造後）
---

```gherkin=
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
import java.util.*;
import javax.swing.JFrame;
import java.io.*;
import javax.imageio.*;//ファイルからの画像読込、画像のファイル書き出し、といった機能が用意されている
//add5
import java.net.MalformedURLException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
//add5_end

public class Mole extends JFrame {

    // 様々な要素の初期値を設定↓
    private final static int WINDOW_SIZE = 300;// 画面サイズ（初期値300）
    private final static int MOLE_SIZE = 50;// モグラ当たり判定のサイズ（初期値50）
    private int GAME_END_COUNT = 16;// モグラ登場回数の設定（この回数出たらゲームオーバー）
    private int score = 0;// モグラをたたいた数
    private int counter = 1;// モグラ登場回数
    private int time = 15;// 制限時間（モグラの登場回数と同じ数値に設定）
    private int mole_x;// モグラ出現位置のX座標
    private int mole_y;// モグラ出現位置のY座標
    private boolean mole_hit = false;// 当たり判定（当たったらtrueになって条件分岐する）
    private final Toolkit tk = Toolkit.getDefaultToolkit();

    public static void main(String[] args) throws Exception {
        new Mole();
        // add5
        URL bgm = Mole.class.getClassLoader().getResource("mogurabgm.midi");
        Clip clip = AudioSystem.getClip();
        clip.open(AudioSystem.getAudioInputStream(bgm));
        clip.loop(Clip.LOOP_CONTINUOUSLY);
        Thread.sleep(9000);
        // add5_end
    }

    public Mole() {
        setSize(WINDOW_SIZE, WINDOW_SIZE);// ゲーム画面の作成（初期値は300*300px）
        // リスナー
        GameMouseAdapter adapter = new GameMouseAdapter();
        addMouseListener(adapter);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//ゲームの終了

        // Timerのscheduleで自身のインナークラスのGameTimeTaskの処理を定期的に実行
        setVisible(true);// setVisible（true）でモグラ（〇）が見える

        Timer t = new Timer();
        t.schedule(new GameTimeTask(), 1000l, 1000l);// 1200ミリ秒毎にGameTimeTaskの処理を実行
    }

    private class GameTimeTask extends TimerTask {// runが1200ミリ秒毎に繰り返し実行
        @Override
        public void run() {// 新しいモグラを登場
            if (counter++ % GAME_END_COUNT == 0)
                return; // GAME_END_COUNT(〇〇)回登場したらゲーム終了（ゲームオーバー）
            // このif文の条件だと、起動時にも”GAME OVER”と表示されてしまう→初回だけ異なるメッセージの表示or非表示にできる？
            mole_hit = false; // 新しいモグラなのでヒット前
            time--;
            mole_x = (int) (Math.random() * (WINDOW_SIZE - MOLE_SIZE));// mole_xとmole_yはモグラの座標
            mole_y = (int) (Math.random() * (WINDOW_SIZE - MOLE_SIZE));// Math.random()でランダムな場所に登場
            repaint();// ウィンドウを再描画することで新しいモグラが出現
        }
    }

    private class GameMouseAdapter extends MouseAdapter {
        @Override
        public void mouseClicked(MouseEvent e) {// 当たり判定の処理？
            if (mole_hit)
                return; // モグラがやられている時は判定しない
            int x = e.getPoint().x;
            int y = e.getPoint().y;
            int hankei = MOLE_SIZE / 2;
            int mx = mole_x + hankei;
            int my = mole_y + hankei;
            int x_kyori = x - mx;
            int y_kyori = y - my;
            if (x_kyori * x_kyori + y_kyori * y_kyori < hankei * hankei) {
                score++;
                mole_hit = true;
            }
            repaint();
        }
    }

    /*
     * 描画処理 paintというメソッドはrepaintが呼ばれた時に実行されます。
     * drawScreenメソッドが返したImageクラスのインタンスを、drawImageで描画しています。
     * drawScreenではまずスコアを表示して、ゲームオーバーであればGAME OVERと表示してそれで終わります。
     * ゲーム中であればモグラを描画します。mole_hitがtrueならばモグラがやられているので赤く、そうでなければ黄色にします
     * fillOvalで黄色く塗った円を描いて、黒い線の円を描くdrawOvalで黒縁を付けて見栄えを良くします。
     */

    public void paint(Graphics g) {
        g.drawImage(drawScreen(), 0, 0, this);
    }

    private Image drawScreen() {
        Image screen = createImage(WINDOW_SIZE, WINDOW_SIZE);
        Graphics2D g = (Graphics2D) screen.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WINDOW_SIZE, WINDOW_SIZE);
        // スコア表示
        g.setColor(Color.BLACK);
        g.drawString("SCORE：" + score, 20, 50);
        g.drawString("残り時間：" + time, 100, 50);
        g.drawString("10 回以上でCLEAR", 170, 280);
        if (counter % GAME_END_COUNT == 0) {
            if(score <= 9){
                g.drawString("”GAME OVER”", 112, 150);
            }else{
                g.drawString("”CLEAR”", 112, 150);
            }
            // ゲームのリスタート
            counter = 0;
            time = 16;
            score = 0;
            GAME_END_COUNT = 17;
            return screen;
        }
        // モグラ描画
        if (mole_hit == true) {
            // g.setColor(Color.RED);
            // g.fillOval(mole_x, mole_y, MOLE_SIZE, MOLE_SIZE);
            try {
                Image img2 = tk.getImage(getClass().getResource("mole2.png"));
                g.drawImage(img2, mole_x, mole_y, null);
            } catch (Exception e) {
                System.out.println(e);
            }
            return screen;
        } else {
            // g.setColor(Color.YELLOW);
            // g.fillOval(mole_x, mole_y, MOLE_SIZE, MOLE_SIZE);
            // g.setColor(Color.BLACK);
            // g.drawOval(mole_x, mole_y, MOLE_SIZE, MOLE_SIZE);
            try {
//
                Image img1 = tk.getImage(getClass().getResource("mole1.png"));
                g.drawImage(img1, mole_x, mole_y, null);
            } catch (Exception e) {
                System.out.println(e);
            }
            return screen;
        }
    }

    // add5
    public static Clip createClip(File path) {
        // 指定されたURLのオーディオ入力ストリームを取得
        try (AudioInputStream ais = AudioSystem.getAudioInputStream(path)) {

            // ファイルの形式取得
            AudioFormat af = ais.getFormat();

            // 単一のオーディオ形式を含む指定した情報からデータラインの情報オブジェクトを構築
            DataLine.Info dataLine = new DataLine.Info(Clip.class, af);

            // 指定された Line.Info オブジェクトの記述に一致するラインを取得
            Clip c = (Clip) AudioSystem.getLine(dataLine);

            // 再生準備完了
            c.open(ais);

            return c;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (UnsupportedAudioFileException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
        return null;
    }
    // add5_end
}

/*
 * 初期処理について MainClassはSwingのJFrameのサブクラスになっています。
 * こうすることでAWT/Swingの描画処理やマウス入力機能を使うことができます。
 * 最初にmainメソッドで自分自身をnewで生成すると、MainClassのコンストラクタの処理が行われます。
 * コンストラクタではまずsetSizeでウィンドウのサイズを決めています。
 * その後、GameMouseAdapterという自身のインナークラスをリスナーにセットしています。
 * こうすることでマウスをクリックした時にGameMouseAdapterの処理を呼ばせることができます。
 */

/*
 * ImageIOクラスとは
 * javax.imageio.ImageIOクラスは標準で提供されているjavaのライブラリで、プログラムではimportを行ってから使用します。
 * ファイルからの画像読込、画像のファイル書き出し、といった機能が用意されています。書き出し時にjpg、gif、pngといった
 * 画像ファイル形式を指定することでその形式でファイルを出力する事が出来るためjpgファイルをpngファイルに変換する、といった処理も可能です。
 * ファイルから読み込んだ画像データはBufferedImageクラスのオブジェクトとして操作されます。
 */

/*
 * Mole4.javaからの変更点（add5） ・BGMの挿入（直矢担当 MainClass.javaを埋め込み） ・タイマーの時間変更（15秒）
 */
```




## 参考にした書籍・URL

:::info
**ゲームを作成するにあたり、参考にした書籍や記事のURLです。** 
:::
・【Java】ウィンドウに画像を描画する
https://nompor.com/2017/12/06/post-1665/
・Let'sプログラミング　ラベルに画像を表示する
https://www.javadrive.jp/tutorial/jlabel/index6.html
・Javaで手軽にゲームを作ろう！(参考ソースコード)
https://www.fenet.jp/java/column/java_tips/6175/
・JavaでRAW,WAV,MP3ファイルを再生
https://qiita.com/hexaforce/items/a02a178edf811cfbaf34
・ImageIO（Java Platform SE 8）
https://docs.oracle.com/javase/jp/8/docs/api/javax/imageio/ImageIO.html
・it-swam-ja
https://www.it-swarm-ja.com/ja/java/
・【Java】WAVファイルの再生｜のんぽぐ
https://nompor.com/2017/12/14/post-128/
・javax.sound.sampled (Java Platform SE 8) - Oracle
https://docs.oracle.com/javase/jp/8/docs/api/javax/sound/sampled/package-summary.html

###### tags: `オブジェクト指向演習` `Java`
