This is actually an old 'problem' that I never really knew how to improve, but I'm wondering now if there is a better approach for this problem.
I'm creating MineSweeper with Java and struggling with an OOP aspect of the game. Basically I have a class Square.java
, SquareBoms
(extends Square
) and Field.java
. My approach on the Square
is that it should only be aware of itself and should not communicate in any way or form with the Field
.
However, the Field
should check the surrounding SquaresBombs
for bombs once a Square has been clicked. So the Square
SHOULD message the Field
that it has been clicked, but I don't think this is the right way of using OOP.
import java.awt.Color;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
public class Square extends JButton {
Field owner; //This is not OOP as the Square should only be aware of itself and what is in it.
int coords;
boolean isChecked = false;
boolean isMarked = false;
int bombsAround;
public Square(Field owner, int coords) {
this.owner = owner;
this.coords = coords;
this.setSize(400, 400);
this.setMargin(new Insets(0, 0, 0, 0));
this.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
if (e.getButton() == MouseEvent.BUTTON1) {
Clicked();
}
else if(e.getButton() == MouseEvent.BUTTON3) {
Mark();
}
}
});
}
public void Clicked() {
if(!isChecked) {
this.setBackground(new Color(238, 238, 238)); // Reset when it had been marked
isChecked = true;
this.setEnabled(false);
owner.checkSquare(this); //This is not OOP as the Square should only be aware of itself and what is in it.
}
}
public void Mark() {
if(!isChecked) {
if(!isMarked)
this.setBackground(Color.GREEN);
else
this.setBackground(null);
isMarked = !isMarked; // toggle on every click
}
}
}
UPDATE
My original question was if it was 'allowed' to let a child object know about its parent. After doing some research i've come to the conclusion that this is not wrong in pure OOP-terms.
1 Answer 1
Separation of Logic and Rendering
The Square
object is essentially a button that also contains some information for display, such as the number of surrounding bombs.
The problem you are having is that this GUI element is communicating directly with the game board of your minesweeper game model. When Square
gets clicked, it tells the board to check the amount of bombs.
I'm not very familiar with Swing, but typically I would expect there to be a Scene or Window at the top level of the hierarchy. Once clicked, the button would tell the controller to tell the game model to perform the necessary action, and then the controller would update the view based on changes to the model.
In this approach you could possibly have a Game
object, Board
object, and Square
object in the game model. On a button click, the coordinates of the Square
button object in the view would be passed into the Game
, and the appropriate changes would be made to the Board
and to the game state. For example, the coordinates have a bomb, and so the state of the Game
is set to GameState.LOSS.
In this approach, you could make the Board
object available to the view.
After each move, the view could update based on the new state of the board, marking the squares that have flags, have been uncovered, etc.
You could also do something such as compute the positions of the nearby Square
objects at the start of the game, and then you could check for bombs like this:
int bombCount = 0;
for (Position position : square.neighbors) {
Square neighbor = board.get(position);
if (neighbor.hasBomb) {
bombCount++;
}
}
Or alternatively store a reference to the actual Square
objects, if you want.
The advantage of all of this is that if you some day want to use a different graphical representation other than Swing, you could easily take the code for the game model and use a different controller and view. You would still use the model in the same way, passing in the coordinates of the location on the board that is clicked.
-
\$\begingroup\$ Thank you for this insightful post! I see now by creating a controller(logic) for the
Squares
theSquare
itself isn't aware of theField
anymore, which is good. However, do you mean to instantiate the controller for everySquare
or use oneController
for all theSquares
which communicates fromSquare -> Controller -> Field
. \$\endgroup\$nkmol– nkmol2015年09月12日 08:18:47 +00:00Commented Sep 12, 2015 at 8:18 -
\$\begingroup\$ What I am suggesting is that the
Controller
would have an array ofButtons
that make up the GUI and correspond to theSquare
objects in the model, and then theController
would also have aGame
object which has aBoard
object which contains theSquare
objects. Pressing aButton
would cause theController
to pass a command to theGame
. \$\endgroup\$bazola– bazola2015年09月12日 14:32:10 +00:00Commented Sep 12, 2015 at 14:32
Explore related questions
See similar questions with these tags.
Field
? How is aField
different from aSquare
? \$\endgroup\$Field
is the playing board which containsSquares
as in playing tiles. \$\endgroup\$