0

MVC デザインを使用してゲームを実装しようとしています。ただし、いくつかの問題が発生しています。MVC について多くの助けを求めるのではなく (多くは失敗に終わりますが、私は実験を楽しんでいます!)、私は今、リスナーと少し苦労しています。

次のような抽象グリッド クラスがあります。

public abstract class ViewAbstractGrid extends JPanel {

    private final int GRID_SIZE = 10;
    private ViewCell[][] cellArray = new ViewCell[GRID_SIZE][GRID_SIZE];
    private ViewCell currentCell;

    public ViewAbstractGrid() {
        setPreferredSize(new Dimension(300, 300));
        setLayout(new GridLayout(GRID_SIZE, GRID_SIZE));
        for (int x = 0; x < GRID_SIZE; x++)
            for (int y = 0; y < GRID_SIZE; y++) {
                currentCell = new ViewCell(x, y);
                cellArray[x][y] = currentCell;
                add(currentCell);
            }
        }

    public ViewCell[][] getCellArray() {
        return cellArray;
    }

    public abstract void addListener(MouseListener listener);
}

ゲームの最初の設計では、ViewCells が実装されていたため、それらの MouseListener を作成したため、各 ViewCell には独自のパネルがありました。ただし、各 ViewCell が独自のリスナーを持つのではなく、グリッド全体が単一のリスナーを持つように、このロジックを Controller クラスに削除しようとしました。これは ViewCell クラスです:

public class ViewCell extends JPanel {
    private final int CELL_SIZE = 1;
    public static Color backgroundColor = new Color(105, 120, 105);
    private int xPos;
    private int yPos;

    public ViewCell(int xPos, int yPos) {
        setOpaque (true);
        setBorder(BorderFactory.createBevelBorder(CELL_SIZE));
        setBackground(backgroundColor);
        setPreferredSize(new Dimension(CELL_SIZE, CELL_SIZE));
        this.xPos = xPos;
        this.yPos = yPos;   
    }

    public Color getCellGUIColor() {
        return backgroundColor;
    }

    public int getXPos() {
        return xPos;
    }

    public int getYPos() {
        return yPos;
    }
}

ご覧のとおり、これは JPanel を拡張します。つまり、作成したグリッドは 100 個の JPanel で効果的に満たされます。人々 (このフォーラムを含む) は、代わりに JButton を使用することを検討できると私に言いましたが、最初は、少なくとも JPanels を使用する方が簡単であることがわかりました。
次に、ViewAbstractGrid を拡張する具体的な Player Grid クラスを作成します。

public class ViewPlayerGrid extends ViewAbstractGrid {
    private LogicGrid playerGridLogic;
    private ViewAbstractGrid playerGrid;
    private int xPos;
    private int yPos;
    private int numberOfPlayerShipsPlaced = 0;

    public ViewPlayerGrid(LogicGrid playerGridLogic) {
        this.playerGridLogic = playerGridLogic;
    }

    public void addListener(MouseListener listener) {
        this.addMouseListener(listener);
    }

これらの具体的なサブクラスは 2 つあります。1 つはコンピュータ用、もう 1 つはプレーヤー用です。簡潔にするために、プレーヤー 1 つだけを含めました。

最後に、次のような Controller クラスがあります。

public class GameController {
    private LogicGrid playerGridLogic;
    private ViewAbstractGrid playerGrid;
    private int xPos;
    private int yPos;
    private int numberOfPlayerShipsPlaced = 0;
    private int numberOfComputerShipsPlaced = 0;

    public GameController(LogicGrid playerGridLogic, ViewAbstractGrid playerGrid) {
        this.playerGridLogic = playerGridLogic;
        this.playerGrid = playerGrid;
        playerGrid.addListener(new PlayerGridListener());
    }

    class PlayerGridListener implements MouseListener {
        @Override
        public void mouseEntered(MouseEvent e) {
        //I know this looks wrong, but I forgot that the x and y axis on a Java grid start at the top left, not bottom left. Just go with it for now!
        // Dividing by 30 as dimensions are 300 by 300. This returns results that that are between 0 and 9.
        yPos = e.getX()/30;
        xPos = e.getY()/30;

        switch(numberOfPlayerShipsPlaced) {
        case 0:
            if ((yPos + 5) <= 10) {
                for (int y = yPos; y < yPos + 5; y++) {
                    playerGrid.getCellArray()[xPos][y].setBackground(Color.GREEN);
                }
            }
            else {
                for (int y = yPos; y < 10; y++) {
                    playerGrid.getCellArray()[xPos][y].setBackground(Color.RED);
            }
        }
        break;
    }
}

ご覧のとおり、このクラスは最後に少し乱雑になります。コードを短くするために多くのロジックを削除しました。このゲームは戦艦用であり、上記の小さなコード スニペットの理由は、ユーザーが 5 セルの長さの水平な船を収容できるグリッド上のセルを選択したかどうかを検出しようとすることでした。できれば四角は緑に、できなければ赤に変わります。

「モデル」もありますが、GUI の設計には必要ないため含めていません。

基本的に、問題は次のとおりです。最初にこのすべてのコードを作成し、リスナーをビューに直接組み込んだとき、2 つのボードが相互に通信できませんでした。また、適切なコーディング プラクティスに従っていないことに気付き、コードを MVC パターンに分解しようとしました。

これに続く問題は、グリッド全体のリスナーができたことです。これに関する問題は、マウスを四角形に置くと、マウスがグリッド内のどこかにある間、一度色が変わることです。最初の四角形 (または四角形) の色が変わると、マウスがグリッドから離れて再び戻ってくるまで、グリッド内の他の四角形の色は変わりません。

これは私には良くありません - マウスが四角形を横切って移動するにつれて四角形の色を変える必要があります。現在の設計を考えると、これを行う方法を誰かが提案できますか? パネルごとにリスナーを持つことに戻る唯一の方法はありますか? もしそうなら、それは私のリスナーが Controller クラスではなくビュークラスになければならないということですか? さらに、コード設計を改善する (または質問を短くする) こと以外に、私へのポインタを投げたい人がいる場合は、お気軽に!

4

1 に答える 1