What is a Java snake cookie clicker?

784    Asked by JosephSlater in Java , Asked on Oct 11, 2022

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.



Your Answer

Interviews

Parent Categories