[Next] [Prev] [Back] [Home]

■ UpperHand Gameを作る


ボタンとメニューを追加する

初期画面 今回は右の図のように プレーヤーを選択するメニュー、 音声の出力を制御するチェックボックス、 ゲームを開始/中断するボタンを追加します。
初期状態では、メニューと「Start」ボタンを表示します。 ゲーム中は、メニューを隠し、「Stop」ボタンを表示します。

JDK1.0.2のGUIコンポーネント

JDK1.0.2には以下のGUIコンポーネントが用意されています。 これらのコンポーネントは操作したときにイベントを発生します。

Buttonクラス
文字列のラベルを持つ押しボタンを表現したクラス。 ボタンが押されたときにACTION_EVENTが発生する。
Checkboxクラス
文字列のラベルを持つ「チェックボックス」を表現したクラス。 現在選択されているかどうかを示すboolenの値を持っている。 選択状態が変化したときにACTION_EVENTが発生する。 複数のチェックボックスを排他的に選択状態にするためには CheckboxGroupクラスを使用する。
Choiceクラス
「オプションメニュー」(ボタンにぶら下がっているメニュー)を表現したクラス。 選択状態が変化したときにACTION_EVENTが発生する。
Listクラス
文字列のリストを表示するクラス。 要素をダブルクリックしたときにACTION_EVENTが発生する。
TextFieldクラス
1行の文字列を入力するクラス。 リターンキーを入力したときにACTION_EVENTが発生する。

他にもMenuBarScrollBar などのクラスがあります。詳細はJDKのドキュメントを参照して下さい。 今回はChoiceCheckboxButton を使用します。

GUIコンポーネントを配置する

下の図の階層でコンポーネントを配置します。
今までUpperHandPlayerViewを配置していた部分に Panelを配置し、 CradLayoutクラスを使ってChoiceUpperHnadPlayerViewを切り替えられるようにします。
右下の空いていた部分には、Checkboxと、 2つのButtonを切り替えるPanelを配置します。

コンポーネントの階層

まず、UpperHandクラスのインスタンス変数に GUIコンポーネントを示す変数を追加します。

//-----------------------------------------------------------------------------
//  インスタンス変数定義
//-----------------------------------------------------------------------------
        ...

//  プレーヤー選択メニュー
private Choice              playerChoice[] = new Choice[2];

//  プレーヤー/メニュー表示切り替え用パネル
private Panel               playerPanel[] = new Panel[2];

//  音声モード切り替えチェックボックス
private Checkbox            soundBox;

//  ゲーム開始ボタン
private Button              startButton;

//  ゲーム中断ボタン
private Button              stopButton;

//  ボタン切り替え用パネル
private Panel               buttonPanel;

次に、コンポーネントを作成します。 プレーヤーの名前はクラス変数playerNameに あらかじめ定義しておきました。

//-----------------------------------------------------------------------------
//  private void createComponent()
//      コンポーネントを作成する。
//-----------------------------------------------------------------------------
private void createComponent()
{
    //  すべてのコンポーネントを取り除く。
    removeAll();

    //  ゲーム盤を表示するコンポーネントを作成する。
    boardView = new UpperHandBoardView(game, this);

    for (int p = UpperHandGame.FIRST; p <= UpperHandGame.SECOND; p++)
    {
        //  プレーヤーを表示するコンポーネントを作成する。
        playerView[p] = new UpperHandPlayerView(game, p);

        //  持ち玉を表示するコンポーネントを作成する。
        ballView[p] = new UpperHandBallView(game, p, this);

        //  プレーヤー選択メニューを作成する。
        playerChoice[p] = new Choice();
        for (int i = 0; i < playerName.length; i++)
        {
            //  プレーヤーの名前をメニューに追加する。
            playerChoice[p].addItem(playerName[i]);
        }

        //  プレーヤー/メニュー切り替え用パネルを作成する。
        playerPanel[p] = new Panel();
    }
    //  プレーヤー選択メニューの選択肢を初期状態にする。
    playerChoice[UpperHandGame.FIRST].select(0);
    playerChoice[UpperHandGame.SECOND].select(1);

    //  音声モード切り替えチェックボックスを作成する。
    soundBox = new Checkbox("Sound");
    soundBox.setState(true);        //  チェックされた状態にする。

    //  ゲーム開始ボタンを作成する。
    startButton = new Button("Start");

    //  ゲーム中断ボタンを作成する。
    stopButton = new Button("Stop");

    //  ボタン切り替え用パネルを作成する。
    buttonPanel = new Panel();
}

最後に、コンポーネントを配置します。

//-----------------------------------------------------------------------------
//  private void layoutComponent()
//      コンポーネントを配置する。
//-----------------------------------------------------------------------------
private void layoutComponent()
{
    GridBagLayout       layout  = new GridBagLayout();
    GridBagConstraints  c       = new GridBagConstraints();

    //  レイアウトマネージャを設定する。
    setLayout(layout);

    //  ゲーム盤を表示するコンポーネントを配置する。
    c.gridheight = GridBagConstraints.REMAINDER;
    c.fill = GridBagConstraints.NONE;
    layout.setConstraints(boardView, c);
    add(boardView);

    //  以降のコンポーネントの配置方法を設定する。
    c.gridheight = 1;
    c.gridwidth = GridBagConstraints.REMAINDER;
    c.anchor = GridBagConstraints.NORTH;


    for (int p = UpperHandGame.FIRST; p <= UpperHandGame.SECOND; p++)
    {
        //  プレーヤー/メニュー表示切り替えパネルに、プレーヤーを表示する
        //  コンポーネント、プレーヤー選択メニューを配置する。
        playerPanel[p].setLayout(new CardLayout());
        playerPanel[p].add("MENU", playerChoice[p]);
        playerPanel[p].add("VIEW", playerView[p]);

        //  プレーヤー/メニュー表示切り替えパネルを配置する。
        c.fill = GridBagConstraints.HORIZONTAL;
        layout.setConstraints(playerPanel[p], c);
        add(playerPanel[p]);

        //  持ち玉を表示するコンポーネントを配置する。
        c.fill = GridBagConstraints.NONE;
        layout.setConstraints(ballView[p], c);
        add(ballView[p]);
    }

    //  以降のコンポーネントの配置方法を設定する。
    c.gridheight = GridBagConstraints.REMAINDER;
    c.gridwidth = 1;

    //  音声モード切り替えチェックボックスを配置する。
    c.anchor = GridBagConstraints.NORTHWEST;
    layout.setConstraints(soundBox, c);
    add(soundBox);

    //  ボタン切り替えパネルに、ゲーム開始ボタン、ゲーム中断ボタンを配置する。
    buttonPanel.setLayout(new CardLayout());
    buttonPanel.add("START", startButton);
    buttonPanel.add("STOP",  stopButton);

    //  ボタン切り替えパネルを配置する。
    c.anchor = GridBagConstraints.NORTHEAST;
    layout.setConstraints(buttonPanel, c);
    add(buttonPanel);
}

GUIコンポーネントからのイベントを処理する

ボタンが押されるとACTION_EVEVTが発生し、 action()メソッドが呼び出されます。 Buttonクラス、Panelクラスには action()メソッドが定義されていないので、 イベントはコンテナに伝播します。 UpperHandクラスにaction()メソッドを定義し、 イベントを処理することにします。

//-----------------------------------------------------------------------------
//  public boolean action(Event evt, Object arg)
//      他のボタンからのイベントを処理する。
//-----------------------------------------------------------------------------
public boolean action(Event evt, Object arg)
{
    if (evt.target == startButton)
    {                       //  ゲーム開始ボタンが押されたとき
        playSound(START_GAME_SOUND);
        startGame();    //  ゲームを開始する。
        return true;
    }
    else
    if (evt.target == stopButton)
    {                       //  ゲーム中断ボタンが押されたとき
        playSound(STOP_GAME_SOUND);
        stopGame();     //  ゲームを終了状態にする。
        return true;
    }
    return super.action(evt, arg);  //  スーパークラスに処理を任せる。
}

UpperHandクラスのmouseDown()メソッドで ゲームを再開していた処理は不要になったので削除しました。

//-----------------------------------------------------------------------------
//  public boolean mouseDown(Event evt, int x, int y)
//      マウスのボタンが押されたときの処理を行う。
//-----------------------------------------------------------------------------
public boolean mouseDown(Event evt, int x, int y)
{
    playSound(BAD_MOVE_SOUND);  //  不正な着手のときの音を出す。
    return true;
}

UpperHandクラスに、現在ゲーム中か否かを示すインスタンス変数 isStopGameを追加し、 startGame()stopGame()で コンポーネントとともに切り替えます。

//-----------------------------------------------------------------------------
//  インスタンス変数定義
//-----------------------------------------------------------------------------
        ...

//  ゲームが終了状態のときtrue
private boolean             isStopGame;
//-----------------------------------------------------------------------------
//  public void startGame()
//      ゲームを開始する。
//-----------------------------------------------------------------------------
public void startGame()
{
    //  ゲーム中の表示に切り替える。
    for (int p = UpperHandGame.FIRST; p <= UpperHandGame.SECOND; p++)
    {
        Panel   panel =  playerPanel[p];
        ((CardLayout)panel.getLayout()).show(panel, "VIEW");
                                        //  プレーヤー選択メニューを隠す。
    }
    ((CardLayout)buttonPanel.getLayout()).show(buttonPanel, "STOP");
                                        //  ゲーム中断ボタンを表示する。

    initPlayer();           //  プレーヤーを初期化する。
    game.init();            //  ゲームを初期化する。
    isStopGame = false;     //  ゲーム中にする。

    nextMove();             //  次の一手に進む。
}
//-----------------------------------------------------------------------------
//  public void stopGame()
//      ゲームを終了状態にする。
//-----------------------------------------------------------------------------
public void stopGame()
{
    isStopGame = true;      //  ゲーム終了状態にする。

    //  ゲーム終了状態の表示に切り替える。
    for (int p = UpperHandGame.FIRST; p <= UpperHandGame.SECOND; p++)
    {
        Panel   panel =  playerPanel[p];
        ((CardLayout)panel.getLayout()).show(panel, "MENU");
                                        //  プレーヤー選択メニューを表示する。
    }
    ((CardLayout)buttonPanel.getLayout()).show(buttonPanel, "START");
                                        //  ゲーム開始ボタンを表示する。
}

initPlayer()では、 プレーヤー選択メニューの状態にしたがいプレーヤーを初期化するようにしました。 人間同士、コンピュータ同士の対戦も可能です。

//-----------------------------------------------------------------------------
//  private void initPlayer()
//      プレーヤー選択メニューの状態にしたがいプレーヤーを初期化する。
//-----------------------------------------------------------------------------
private void initPlayer()
{
    for (int p = UpperHandGame.FIRST; p <= UpperHandGame.SECOND; p++)
    {
        //  プレーヤーを初期化する。
        if (playerChoice[p].getSelectedIndex() == 0)
        {                       //  人間が選択されているとき
            player[p] = null;
        }
        else
        {                       //  コンピュータが選択されているとき
            //  コンピュータのプレーヤーを生成する。
            player[p] = new UpperHandPlayer();
        }

        //  プレーヤーの名前を初期化する。
        playerView[p].playerName(playerChoice[p].getSelectedItem());
    }
}

Appletがロードされたときはゲームが終了状態になっている必要があるので、 init()の最後でstopGame()を呼び出すようにしました。

//-----------------------------------------------------------------------------
//  public void init()
//      Appletの初期化処理を行う。
//-----------------------------------------------------------------------------
public void init()
{
        ...

    //  ゲームを終了状態にする。
    stopGame();
}

コンピュータ同士の対戦のとき、目に見えないくらいの早さで着手してしまうので、 nextMove()に0.5秒休む処理を追加しました。

//-----------------------------------------------------------------------------
//  private void nextMove()
//      次の一手に進む。
//      次のプレーヤーがコンピュータのときは、次に一手をコンピュータに選択
//      させ、着手する。次のプレーヤーが人間のときは何もせずにリターンし、
//      マウスの入力を待つ。
//-----------------------------------------------------------------------------
private void nextMove()
{
    int p = game.nextPlayer();
    if (player[p] != null)
    {               //  次のプレーヤーがコンピュータのとき
        try
        {
            Thread.sleep(500);      //  0.5秒休止する。
        }
        catch (InterruptedException e) {}

        //  次の一手をコンピュータに選択させ、着手する。
        makeMove(player[p].selectMove(game));
    }
}

makeMove()に ゲームが終了状態のときは着手を行わないようにする処理を追加しました。

//-----------------------------------------------------------------------------
//  public void makeMove(int p)
//      位置pに着手する。
//-----------------------------------------------------------------------------
public void makeMove(int p)
{
    if (isStopGame)
    {                   //  ゲームが終了状態のとき
        playSound(BAD_MOVE_SOUND);  //  不正な着手のときの音を出す。
        return;                     //  着手は行わない。
    }

    game.makeMove(p);               //  着手する。

    if (game.isFinish())
    {                   //  ゲームが終わったとき
        finishGame();               //  終局時の処理を行う。
        stopGame();                 //  ゲームを終了状態にする。
    }
    else
    {
        playSound(PUT_BALL_SOUND);  //  玉を置いた音を出す。
        nextMove();                 //  次の一手に進む。
    }
}

finishGame()には、 コンピュータ同士、人間同士の対戦の場合の処理を追加しました。

//-----------------------------------------------------------------------------
//  private void finishGame()
//      終局時の処理を行う。
//-----------------------------------------------------------------------------
private void finishGame()
{
    if (player[UpperHandGame.FIRST]  == null &&     //  コンピュータ同士の
        player[UpperHandGame.SECOND] == null        //  対戦のとき
            ||
        player[UpperHandGame.FIRST]  != null &&     //  人間同士の
        player[UpperHandGame.SECOND] != null)       //  対戦のとき
    {
        playSound(PUT_BALL_SOUND);
    }
    else
    {
        // コンピュータの手番を取得する。
        int p = (player[UpperHandGame.FIRST] != null) ?
                        UpperHandGame.FIRST :
                        UpperHandGame.SECOND;

        // ゲームの勝者を取得する。
        int winner = game.winner();

        if (winner == UpperHandGame.NUTRAL)
        {                       // 引き分け
            playSound(PUT_BALL_SOUND);
        }
        else
        if (winner == p)
        {                       // コンピュータの勝ち
            playSound(APP_WIN_SOUND);
        }
        else
        {                       // コンピュータの負け
            playSound(APP_LOST_SOUND);
        }
    }
}

playSound()ではチェックボックスの状態を参照し、 音声を出力する状態のときのみ音声を出力するようにしました。

//-----------------------------------------------------------------------------
//  private void playSound(int id)
//      idで指定された音声を出力する。
//-----------------------------------------------------------------------------
private void playSound(int id)
{
    if (soundBox.getState())
    {           //  音声を出力する状態のとき
        sound[id].play();   //  音声を出力する。
    }
}

ここまでにできあがったもの

あなたのブラウザはJavaに対応していません。

Javaソースコード (Ver. 1.1a10)



[Next] [Prev] [Back] [Home]
Satoshi Kobayashi (koba@yk.rim.or.jp)