What is a Java snake cookie clicker?
This is my first graphical application I have made in my life (except HTML and Javascript-Applications, if that counts). It's a simple implementation of Cookie Clicker, the famous browser game. Unfortunately the size of the buttons equals the size of columns. That does not look good. I have seen a solution that uses two layouts. A GridLayout, and an additional FlotLayout. But the code looks so ugly, that I don't want to use this way of programming.
I would be very thankful if you have tips for me on how to improve the code quality! Programming a graphical application is much harder and more complex than writing textual applications.
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CookieClicker extends JFrame {
// non graphical variables
private int cookies = 0;
private int clicker = 1;
private int clickerPrice = 20;
// graphical variables
int numberOfColumns = 5;
Container container;
JLabel cookieLabel;
JButton increaseCookiesButton;
JLabel clickerLabel;
JButton increaseClickerButton;
// buildings
Building bakery;
boolean bakeryUnlocked;
Building robot;
boolean robotUnlocked;
Building factory;
boolean factoryUnlocked;
public CookieClicker() {
container = getContentPane();
container.setLayout(new GridLayout(5, 1));
bakery = new Building("Bakery", 0, 1, 20);
bakeryUnlocked = false;
robot = new Building("Robot", 0, 5, 100);
robotUnlocked = false;
factory = new Building("Factory", 0, 10, 200);
factoryUnlocked = false;
// produce cookies by hand
cookieLabel = new JLabel("Cookies: " + cookies);
increaseCookiesButton = new JButton("Increase Cookies");
increaseCookiesButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cookies += clicker;
}
});
// improve clicking production rate
clickerLabel = new JLabel("Clicker Level: " + clicker);
increaseClickerButton = new JButton("Improve Clicker (Costs: " + clickerPrice + ")");
increaseClickerButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
increaseClicker();
}
private void increaseClicker() {
if(cookies >= clickerPrice) {
clicker++;
cookies -= clickerPrice;
clickerPrice *= 2;
JOptionPane.showMessageDialog(null, "You have improved your clicker!");
} else {
JOptionPane.showMessageDialog(null, "You have not enough money!");
}
}
});
java.util.Timer actualizeProgress = new java.util.Timer();
actualizeProgress.scheduleAtFixedRate(new TimerTask() {
public void run() {
cookieLabel.setText("Cookies: " + cookies);
clickerLabel.setText("Clicker Level: " + clicker);
increaseClickerButton.setText("Improve Clicker (Costs: " + clickerPrice + ")");
}
}, 0, 25);
java.util.Timer getMoreBuildings = new java.util.Timer();
getMoreBuildings.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (bakeryUnlocked == false && clicker >= 2) {
bakery.unlock();
bakeryUnlocked = true;
}
if (robotUnlocked == false && bakery.getLevel() >= 2) {
robot.unlock();
robotUnlocked = true;
}
if (factoryUnlocked == false && robot.getLevel() >= 2) {
factory.unlock();
factoryUnlocked = true;
}
}
}, 0, 2000);
java.util.Timer produceWithBuildings = new java.util.Timer();
produceWithBuildings.scheduleAtFixedRate(new TimerTask() {
public void run() {
cookies += bakery.getProductionRate() + robot.getProductionRate() + factory.getProductionRate();
}
}, 0, 1000);
container.add(cookieLabel);
container.add(increaseCookiesButton);
container.add(new JLabel("")); // blank label
container.add(clickerLabel);
container.add(increaseClickerButton);
}
public class Building {
// non graphical variables
private String name;
private int level;
private int productionRate;
private int costs;
// graphical variables
JLabel label;
JButton button;
public Building(String name, int level, int productionRate, int costs) {
// non graphical variables
this.name = name;
this.level = level;
this.productionRate = productionRate;
this.costs = costs;
// graphical variables
label = new JLabel();
button = new JButton();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
improve();
}
});
}
public int getLevel() {
return level;
}
public void unlock() {
numberOfColumns += 3;
container.setLayout(new GridLayout(numberOfColumns, 1));
container.add(new JLabel(""));
container.add(label);
container.add(button);
setSize(210, getHeight() + 120);
actualize();
}
public void improve() {
if(cookies >= costs) {
level++;
cookies -= costs;
costs *= 2;
JOptionPane.showMessageDialog(null, "You have improved the " + name + "!");
} else {
JOptionPane.showMessageDialog(null, "You have not enough money!");
}
actualize();
}
public int getProductionRate() {
return productionRate * level;
}
public void actualize() {
label.setText(name + " Prod. Rate: " + getProductionRate());
button.setText("Improve (costs: " + costs + ")");
}
}
public static void main(String[] args) {
CookieClicker cookieClicker = new CookieClicker();
cookieClicker.setTitle("Cookie Clicker");
cookieClicker.setSize(210, 200);
cookieClicker.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cookieClicker.setVisible(true);
}
}
I made some edits to your code for fun!
Check this link: https://drive.google.com/file/d/1BBblZPIUScPtr5kTHi0YAjA3phoeR2Gj/view?usp=sharing
The above link contains the whole project folder for the game. Note that this game needs images in a folder called Images and an audio file in a folder called Audio. The code for the game Java Snake Cookie Clicker is written below.
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File; //This library is used to search for the audio file in the game
import java.io.IOException; //This library is used when exceptions or errors occur while using the File library.
import javax.sound.sampled.*; //This library is especially needed when dealing with audio in this program.
//The above three libraries have to be imported for the music in the game.
import javax.swing.*;
public class CookieClicker extends JFrame {
// non graphical variables
private int cookies = 0;
private int clicker = 1;
private int clickerPrice = 20;
//These two variables are used to dictate the size of the JFrame.
private static int screenWidth=420;
private static int screenHeight=400;
private final static Font FONT=new Font("Serif", Font.BOLD, 14); //The fonts of most texts are set to this font. This is a bold Serif 14 font.
private final static Colour WINDOW_COLOR=new Colour(125,125,125); //This grey colour is applied to the windows in the game.
private final static Colour LABEL_COLOR= new Colour(0, 102, 0) ; //This green colour is applied to the labels.
private final static Colour BUTTON_COLOR=new Colour(153,0,0); //This red colour is applied to the buttons.
// graphical variables
int numberOfColumns = 7;
Container container;
JLabel cookieLabel;
JButton increaseCookiesButton;
JLabel clickerLabel;
JButton increaseClickerButton;
// buildings
Building bakery;
boolean bakeryUnlocked;
Building robot;
boolean robotUnlocked;
Building factory;
boolean factoryUnlocked;
//This image of a notification is used
public static ImageIcon notification=new ImageIcon("Images/notification.jpg");
public CookieClicker() {
container = getContentPane();
/**The first parameter of GridLayout is set to the variable numberOfColumns, which is equal to 7.
* 7 columns is needed for the beginning of the game.
*/
container.setLayout(new GridLayout(numberOfColumns, 1));
container.setBackground(WINDOW_COLOR); //The container's background colour is set to the window colour.
bakery = new Building("Bakery", 0, 1, 20, "Images/bakery.jpg");
bakeryUnlocked = false;
robot = new Building("Robot", 0, 5, 100, "Images/robot.jpg");
robotUnlocked = false;
factory = new Building("Factory", 0, 10, 200, "Images/factory.jpg");
factoryUnlocked = false;
// produce cookies by hand
cookieLabel = new JLabel("Cookies: " + cookies);
cookieLabel.setForeground(LABEL_COLOR);//The label's colour is set to the variable LABEL_COLOR.
cookieLabel.setFont(FONT); //The label's font is set to the variable FONT.
increaseCookiesButton=new JButton(new ImageIcon("Images/cookie.jpg"));
/**The button's foreground colour is set to the variable BUTTON_COLOR.
* Due to this, the button's text is the same as the colour of BUTTON_COLOR.
* BUTTON_COLOR is a red colour, so the button's text is red.
*/
increaseCookiesButton.setForeground(BUTTON_COLOR);
//The text of the button is set to "Increase cookies".
increaseCookiesButton.setText("Increase cookies");
//The button's font is set to the variable FONT.
increaseCookiesButton.setFont(FONT);
//By putting the increaseCookiesButton into the first parameter of the function, this button's background aspects will be hidden.
transparentBackground(increaseCookiesButton);
increaseCookiesButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cookies += clicker;
}
});
// improve clicking production rate
clickerLabel = new JLabel("Clicker Level: " + clicker);
clickerLabel.setForeground(LABEL_COLOR);
ImageIcon clickerIcon=new ImageIcon("Images/clicker.jpg");
//The label's font is set to the variable FONT.
clickerLabel.setFont(FONT);
increaseClickerButton = new JButton(clickerIcon);
/**The button's foreground colour is set to the variable BUTTON_COLOR.
* Due to this, the button's text is the same as the colour of BUTTON_COLOR.
* BUTTON_COLOR is a red colour, so the button's text is red.
*/
increaseClickerButton.setForeground(BUTTON_COLOR);
//By putting the increaseClickerButton into the first parameter of the function, this button's background aspects will be hidden.
transparentBackground(increaseClickerButton);
//The button's font is set to the variable FONT.
increaseClickerButton.setFont(FONT);
increaseClickerButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
increaseClicker();
}
private void increaseClicker() {
/** This label is used to display a message to the user in the JOptionPane.
* The label's font is set to the variable FONT and the text colour, or foreground colour, of the label is set to the
* variable LABEL_COLOR.
*/
JLabel notificationLabel=new JLabel("");
notificationLabel.setFont(FONT);
notificationLabel.setForeground(LABEL_COLOR);
if(cookies >= clickerPrice) {
clicker+;
cookies -= clickerPrice;
clickerPrice *= 2;
//The label's text is set to "You have improved your clicker!".
notificationLabel.setText("You have improved your clicker!");
/**The JOptionPane displays the notificationLabel in a plain message format.
*The title of the window is Notification and an image of a notification is shown.
*/
JOptionPane.showMessageDialog(null, notificationLabel, "Notification", JOptionPane.PLAIN_MESSAGE, notification);
} else {
//The label's text is set to "You do not have enough money!".
notificationLabel.setText("You do not have enough money!");
/**The JOptionPane displays the notificationLabel in a plain message format.
*The title of the window is Notification and an image of a notification is shown.
*/
JOptionPane.showMessageDialog(null, notificationLabel, "Notification", JOptionPane.PLAIN_MESSAGE, notification);
}
}
});
java.util.Timer actualize Progress = new java.util.Timer();
actualizeProgress.scheduleAtFixedRate(new TimerTask() {
public void run() {
cookieLabel.setText("Cookies: " + cookies);
clickerLabel.setText("Clicker Level: " + clicker);
increaseClickerButton.setText("Improve Clicker (Costs: " + clickerPrice + ")");
}
}, 0, 25);
java.util.Timer getMoreBuildings = new java.util.Timer();
getMoreBuildings.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (bakeryUnlocked == false && clicker >= 2) {
bakery.unlock();
bakeryUnlocked = true;
}
if (robotUnlocked == false && bakery.getLevel() >= 2) {
robot.unlock();
robotUnlocked = true;
}
if (factoryUnlocked == false && robot.getLevel() >= 2) {
factory.unlock();
factoryUnlocked = true;
}
}
}, 0, 2000);
java.util.Timer produceWithBuildings = new java.util.Timer();
produceWithBuildings.scheduleAtFixedRate(new TimerTask() {
public void run() {
cookies += bakery.getProductionRate() + robot.getProductionRate() + factory.getProductionRate();
}
}, 0, 1000);
container.add(cookieLabel);
container.add(increaseCookiesButton);
container.add(new JLabel("")); // blank label
container.add(clickerLabel);
container.add(increaseClickerButton);
}
public class Building {
// non graphical variables
private String name;
private int level;
private int productionRate;
private int costs;
// graphical variables
JLabel label;
JButton button;
ImageIcon icon; //This icon is applied to the button
//The parameter iconName is equal to the location of an image in the files.
public Building(String name, int level, int productionRate, int costs, String iconName) {
// non graphical variables
this.name = name;
this.level = level;
this.productionRate = productionRate;
this.costs = costs;
// graphical variables
label = new JLabel();
icon=new ImageIcon(iconName);
button = new JButton(icon); //The button displays an icon image
/** Here, the label's and button's fonts are both set to
* the variable FONT. The button's colour is set to BUTTON_COLOR
* and the label's colour is set to LABEL_COLOR.
*/
label.setForeground(LABEL_COLOR);
button.setForeground(BUTTON_COLOR);
label.setFont(FONT);
button.setFont(FONT);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
improve();
}
});
/**By adding the variable button as an argument for transparentBackground,
* the background aspects of the button are hidden.
*/
transparentBackground(button);
}
public int getLevel() {
return level;
}
public void unlock() {
numberOfColumns += 3;
container.setLayout(new GridLayout(numberOfColumns, 1));
container.add(new JLabel(""));
container.add(label);
container.add(button);
setSize(screenWidth, getHeight() + 120);
actualize();
}
public void improve() {
/** This label is used to display a message to the user in the JOptionPane.
* The label's font is set to the variable FONT and the text colour, or foreground colour, of the label is set to the
* variable LABEL_COLOR.
*/
JLabel notificationLabel=new JLabel("");
notificationLabel.setFont(FONT);
notificationLabel.setForeground(LABEL_COLOR);
if(cookies >= costs) {
level++;
cookies -= costs;
costs *= 2;
//The label's text is changed to tell the user what has been improved.
notificationLabel.setText("You have improved the " + name + "!");
/**The JOptionPane displays the notificationLabel in a plain message format.
*The title of the window is Notification and an image of a notification is shown.
*/
JOptionPane.showMessageDialog(null, notificationLabel, "Notification", JOptionPane.PLAIN_MESSAGE, notification);
} else {
//The label's text is changed to tell the user what has been improved.
notificationLabel.setText("You have not enough money!");
/**The JOptionPane displays the notificationLabel in a plain message format.
*The title of the window is Notification and an image of a notification is shown.
*/
JOptionPane.showMessageDialog(null, notificationLabel, "Notification", JOptionPane.PLAIN_MESSAGE, notification);
}
actualize();
}
public int getProductionRate() {
return productionRate * level;
}
public void actualize() {
label.setText(name + " Prod. Rate: " + getProductionRate());
button.setText("Improve (costs: " + costs + ")");
}
}
public static void main(String[] args) {
CookieClicker cookieClicker = new CookieClicker();
cookieClicker.setTitle("Cookie Clicker");
/**The width of the JFrame is set to screenWidth.
* The height of the JFrame is set to screenHeight.
*/
cookieClicker.setSize(screenWidth, screenHeight);
//The background of the JFrame is set to the variable WINDOW_COLOR
cookieClicker.setBackground(WINDOW_COLOR);
cookieClicker.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cookieClicker.setVisible(true);
//Resizable is set to false so the user is prevented from changing the size of the JFrame.
cookieClicker.setResizable(false);
//This function is called to customise UI related to panes.
optionPaneCustomization();
//This function is called to play the music of the game.
music();
}
//This function takes in a button as a parameter and makes the background hidden.
public static void transparentBackground(JButton button) {
button.setBorderPainted(false); //The border of the button is not painted.
}
//This function customises UI related to panes.
public static void optionPaneCustomization() {
//The background colour of JOptionPanes is set to the variable WINDOW_COLOR.
UIManager.put("OptionPane.background", WINDOW_COLOR);
//The background colour of JPanels are set to the variable WINDOW_COLOR.
UIManager.put("Panel.background", WINDOW_COLOR);
}
//This function is used to play the music in the game.
public static void music() {
/**The try and catch method is used to avoid compiler errors.
* In the try method, the program tries to play music.
*/
try {
/**The variable audio is set to a .wav file.
* The .wav file is accessed so that this music file can be played.
*/
AudioInputStream audio=AudioSystem.getAudioInputStream(new File("Audio/CookieClicker.wav"));
Clip soundClip=AudioSystem.getClip();
soundClip.open(audio);
//The music will loop endlessly until the program stops
soundClip.loop(Clip.LOOP_CONTINUOUSLY);
}
/**In the catch method, the function audioError is called.
* This function is only called when there has been an error
* while playing the audio.
*/
catch (UnsupportedAudioFileException e) {
audioError();
}
catch (IOException e) {
audioError();
}
catch (LineUnavailableException e) {
audioError();
}
}
/**In this function, a pop-up displays if an error with the audio in the game occurred.
* The pop-up informs the user that an error with the audio in the game occurred.
*/
public static void audioError() {
ImageIcon errorIcon=new ImageIcon("Images/error.jpg"); //This variable stores an error icon, which is a .jpg.
/** This label is used to display a message to the user in the JOptionPane.
* The label's font is set to the variable FONT and the text colour, or foreground colour, of the label is set to the
* variable LABEL_COLOR.
*/
JLabel notificationLabel=new JLabel("");
notificationLabel.setFont(FONT);
notificationLabel.setForeground(LABEL_COLOR);
notificationLabel.setText("There has been an error with the audio!");
/**The JOptionPane displays the notificationLabel in a plain message format.
*The title of the window is Error and an image of an error is shown.
*/
JOptionPane.showMessageDialog(null, notificationLabel, "Error!", JOptionPane.PLAIN_MESSAGE, errorIcon);
}
}Edit: What I added to the original code is images for the buttons, stylized colours for all the elements in the GUI, and music. I also made other smaller edits as well.