Coding 5: Hit the moles
Be prepared as this coding lesson will be a lot more challenging than the previous ones.
Before diving into the next part, let's first organise the code we have written so far.
We will group our code into separate functions (methods) and call them when we need to use them.
Recall that in our constructor: public Game(){..} we he have the following lines of code:
for(int i = 0; i < 16; i++){
holes[i].setIcon(loadImage("/moleIn.png"));
board[i] = 0;
}
which initialises the icons and board array to display empty holes on all 16 labels.
It is a better idea to create a separate function for this, as we may need to use it more than once.
So go ahead and make a function and copy-paste the code in there like this:
private void clearBoard(){
for(int i = 0; i < 16; i++){
holes[i].setIcon(loadImage("/moleIn.png"));
board[i] = 0;
}
}
Let's also group all the code in the constructor that is related to initialising the GUI (Swing components) and call the function: initGUI:
private void initGUI(){
setTitle("Whack A Mole");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 608, 720);
JPanel contentPane = new JPanel();
contentPane = new JPanel();
contentPane.setBackground(new Color(0, 51, 0));
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(null);
JLabel lblTitle = new JLabel("Whack A Mole");
lblTitle.setForeground(new Color(153, 204, 0));
lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
lblTitle.setFont(new Font("Century Gothic", Font.BOLD, 20));
lblTitle.setBounds(0, 0, 602, 47);
contentPane.add(lblTitle);
panel = new JPanel();
panel.setBackground(new Color(0, 102, 0));
panel.setBounds(32, 105, 535, 546);
panel.setLayout(null);
contentPane.add(panel);
holes[0] = new JLabel("0");
holes[0].setName("0");
holes[0].setBounds(0, 396, 132, 132);
panel.add(holes[0]);
holes[1] = new JLabel("1");
holes[1].setName("1");
holes[1].setBounds(132, 396, 132, 132);
panel.add(holes[1]);
holes[2] = new JLabel("2");
holes[2].setName("2");
holes[2].setBounds(264, 396, 132, 132);
panel.add(holes[2]);
holes[3] = new JLabel("3");
holes[3].setName("3");
holes[3].setBounds(396, 396, 132, 132);
panel.add(holes[3]);
holes[4] = new JLabel("4");
holes[4].setName("4");
holes[4].setBounds(0, 264, 132, 132);
panel.add(holes[4]);
holes[5] = new JLabel("5");
holes[5].setName("5");
holes[5].setBounds(132, 264, 132, 132);
panel.add(holes[5]);
holes[6] = new JLabel("6");
holes[6].setName("6");
holes[6].setBounds(264, 264, 132, 132);
panel.add(holes[6]);
holes[7] = new JLabel("7");
holes[7].setName("7");
holes[7].setBounds(396, 264, 132, 132);
panel.add(holes[7]);
holes[8] = new JLabel("8");
holes[8].setName("8");
holes[8].setBounds(0, 132, 132, 132);
panel.add(holes[8]);
holes[9] = new JLabel("9");
holes[9].setName("9");
holes[9].setBounds(132, 132, 132, 132);
panel.add(holes[9]);
holes[10] = new JLabel("10");
holes[10].setName("10");
holes[10].setBounds(264, 132, 132, 132);
panel.add(holes[10]);
holes[11] = new JLabel("11");
holes[11].setName("11");
holes[11].setBounds(396, 132, 132, 132);
panel.add(holes[11]);
holes[12] = new JLabel("12");
holes[12].setName("12");
holes[12].setBounds(0, 0, 132, 132);
panel.add(holes[12]);
holes[13] = new JLabel("13");
holes[13].setName("13");
holes[13].setBounds(132, 0, 132, 132);
panel.add(holes[13]);
holes[14] = new JLabel("14");
holes[14].setName("14");
holes[14].setBounds(264, 0, 132, 132);
panel.add(holes[14]);
holes[15] = new JLabel("15");
holes[15].setName("15");
holes[15].setBounds(396, 0, 132, 132);
panel.add(holes[15]);
setContentPane(contentPane);
}
Finally, in the constructor we can call the two functions we just created:
public Game() {
initGUI();
clearBoard();
}
Make sure to call: initGUI() first, so the label array is initialised. Then we can call clearBoard() to set the values to 0 and set the imageicons to 'moleIn.png'
Mouse Events - detecting mouse click on JLabel
For each label (representing a hole or mole) we need to add a Mouse Click Event Listener, which basically executes certain code when the corresponding label detects a mouse click.
To do this, we must first loop through each label in the array.
Then, add a mouse listener for each label.
As this is beyond the scope of this tutorial, how the Mouse Listener Event works will not be explained in detail.
We can now create a function: initEvents() which will contain all the code that adds event listeners. For now, let's add the mouse click event listener to each label.
private void initEvents(){
for(int i = 0; i < holes.length; i++){
holes[i].addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e){
JLabel lbl = (JLabel)e.getSource();
int id = Integer.parseInt(lbl.getName());
pressedButton(id);
}
});
}
}
Don't forget to call this function in the constructor:
public Game() {
initGUI();
clearBoard();
initEvents();
}
As you can see, we now need to implement the pressedButton() function..
This function should do the following:
(1) check whether the pressed button (label) is a mole or an empty hole
(2) if it is a mole, increase the score by 1
(3) if it is an empty hole, decrease the score by 1 (this is the penalty for missing)
(4) update the score label
(5) clear the board (reset it)
(6) generate another random mole
So first, let's create a global variable to store the score:
private int score = 0;
Now we can create the pressedButton function..
private void pressedButton(int id){
int val = board[id];
//if val is 1 = mole
//if val is 0 = empty hole
if(val==1){
score++;
}else{ //val==0
score--;
}
lblScore.setText("Score: " + score); //update the score
clearBoard();
genRandMole();
}
Note that we are calling the functions: clearBoard() and genRandMole() which we created earlier.
Now try running the game, you should be able to click on a hole/mole, and see a random mole appear.
Coding 5: Source Code
import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
public class Game extends JFrame{
private JPanel panel;
private JLabel[] holes = new JLabel[16];
private int[] board = new int[16];
private int score = 0;
private void pressedButton(int id){
int val = board[id];
//if val is 1 = mole
//if val is 0 = empty hole
if(val==1){
score++;
}else{ //val==0
score--;
}
lblScore.setText("Score: " + score); //update the score
clearBoard();
genRandMole();
}
private void initEvents(){
for(int i = 0; i < holes.length; i++){
holes[i].addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e){
JLabel lbl = (JLabel)e.getSource();
int id = Integer.parseInt(lbl.getName());
pressedButton(id);
}
});
}
}
private void initGUI(){
setTitle("Whack A Mole");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 608, 720);
JPanel contentPane = new JPanel();
contentPane = new JPanel();
contentPane.setBackground(new Color(0, 51, 0));
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(null);
JLabel lblTitle = new JLabel("Whack A Mole");
lblTitle.setForeground(new Color(153, 204, 0));
lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
lblTitle.setFont(new Font("Century Gothic", Font.BOLD, 20));
lblTitle.setBounds(0, 0, 602, 47);
contentPane.add(lblTitle);
panel = new JPanel();
panel.setBackground(new Color(0, 102, 0));
panel.setBounds(32, 105, 535, 546);
panel.setLayout(null);
contentPane.add(panel);
holes[0] = new JLabel("0");
holes[0].setName("0");
holes[0].setBounds(0, 396, 132, 132);
panel.add(holes[0]);
holes[1] = new JLabel("1");
holes[1].setName("1");
holes[1].setBounds(132, 396, 132, 132);
panel.add(holes[1]);
holes[2] = new JLabel("2");
holes[2].setName("2");
holes[2].setBounds(264, 396, 132, 132);
panel.add(holes[2]);
holes[3] = new JLabel("3");
holes[3].setName("3");
holes[3].setBounds(396, 396, 132, 132);
panel.add(holes[3]);
holes[4] = new JLabel("4");
holes[4].setName("4");
holes[4].setBounds(0, 264, 132, 132);
panel.add(holes[4]);
holes[5] = new JLabel("5");
holes[5].setName("5");
holes[5].setBounds(132, 264, 132, 132);
panel.add(holes[5]);
holes[6] = new JLabel("6");
holes[6].setName("6");
holes[6].setBounds(264, 264, 132, 132);
panel.add(holes[6]);
holes[7] = new JLabel("7");
holes[7].setName("7");
holes[7].setBounds(396, 264, 132, 132);
panel.add(holes[7]);
holes[8] = new JLabel("8");
holes[8].setName("8");
holes[8].setBounds(0, 132, 132, 132);
panel.add(holes[8]);
holes[9] = new JLabel("9");
holes[9].setName("9");
holes[9].setBounds(132, 132, 132, 132);
panel.add(holes[9]);
holes[10] = new JLabel("10");
holes[10].setName("10");
holes[10].setBounds(264, 132, 132, 132);
panel.add(holes[10]);
holes[11] = new JLabel("11");
holes[11].setName("11");
holes[11].setBounds(396, 132, 132, 132);
panel.add(holes[11]);
holes[12] = new JLabel("12");
holes[12].setName("12");
holes[12].setBounds(0, 0, 132, 132);
panel.add(holes[12]);
holes[13] = new JLabel("13");
holes[13].setName("13");
holes[13].setBounds(132, 0, 132, 132);
panel.add(holes[13]);
holes[14] = new JLabel("14");
holes[14].setName("14");
holes[14].setBounds(264, 0, 132, 132);
panel.add(holes[14]);
holes[15] = new JLabel("15");
holes[15].setName("15");
holes[15].setBounds(396, 0, 132, 132);
panel.add(holes[15]);
setContentPane(contentPane);
}
private void clearBoard(){
for(int i = 0; i < 16; i++){
holes[i].setIcon(loadImage("/moleIn.png"));
board[i] = 0;
}
}
private void genRandMole(){
Random rnd = new Random(System.currentTimeMillis()); //seeding random with current time
int moleID = rnd.nextInt(16);
board[moleID] = 1;
holes[moleID].setIcon(loadImage("/moleOut.png"));
}
private ImageIcon loadImage(String path){
Image image = new ImageIcon(this.getClass().getResource(path)).getImage();
Image scaledImage = image.getScaledInstance(132, 132, java.awt.Image.SCALE_SMOOTH);
return new ImageIcon(scaledImage);
}
public Game() {
initGUI();
clearBoard();
initEvents();
}
public static void main(String[] args) {
Game frame = new Game();
frame.setVisible(true);
}
}