I have written a Cookie Clicker Game with JavaFX. I have not much experience so I guess that the code looks terrible to a person that is familar with JavaFX. So lets improve that!
Main.java
import javafx.application.Application;
import javafx.application.Platform;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.event.EventHandler;
import javafx.event.ActionEvent;
import java.util.Timer;
import java.util.TimerTask;
/* this class represents the main application.
* this application represents a game in which a player can produce cookies
* with the help of the clicker and some buildings.
* the clicker produces cookies by a button click.
* the buildings produce cookies automatically from time to time
*/
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
/* graphical stuff */
// container
private FlowPane root;
// this box contains general stats and klicker stuff
private VBox statsAndKlickerBox;
// this box contains the buildings - also here informations about them and
// the possibility to make them better
private VBox buildingsBox;
// graphic elements like labels and buttons
/* logical stuff: the player, the clicker and the buildings */
private Player player;
private Clicker clicker;
private Producer bakery;
private boolean bakeryEnabled;
private Producer factory;
private boolean factoryEnabled;
private Producer cookieSmithy;
private boolean cookieSmithyEnabled;
// these are graphical elements that are also needed outside of the start
// method
private Label cookiesLabel;
private Label cookiesEverProducedLabel;
private Label clickerLabel;
private Label clickerProductionValueLabel;
private Button levelUpClickerButton;
private Label bakeryLabel;
private Label bakeryProductionValueLabel;
private Button levelUpBakeryButton;
private Label factoryLabel;
private Label factoryProductionValueLabel;
private Button levelUpFactoryButton;
private Label cookieSmithyLabel;
private Label cookieSmithyProductionValueLabel;
private Button levelUpCookieSmithyButton;
public Main() {
player = new Player();
clicker = new Clicker();
bakery = new Producer("Bakery", 1, 100);
bakeryEnabled = false;
factory = new Producer("Factory", 5, 1000);
factoryEnabled = false;
cookieSmithy = new Producer("Cookie Smithy", 10, 10000);
cookieSmithyEnabled = false;
}
// tasks of this method: initialize all graphical elements and add
// functionality to the interactive elements (that are only buttons here)
@Override
public void start(Stage stage) {
// initialze and configure the basic containers and the information
// Label
root = new FlowPane();
statsAndKlickerBox = new VBox();
statsAndKlickerBox.setSpacing(5);
statsAndKlickerBox.setPrefWidth(200);
statsAndKlickerBox.setPrefHeight(230);
buildingsBox = new VBox();
buildingsBox.setSpacing(5);
buildingsBox.setPrefWidth(200);
buildingsBox.setPrefHeight(230);
Label informationLabel = new Label("Arthoria.de - A nice german on" +
"line game!");
// adding the containers and the label
root.getChildren().addAll(statsAndKlickerBox, buildingsBox,
informationLabel);
// is used for displaying information, for example when a building has
// been improved
// elements for the statsAndKlickerBox
Label headlineLabel = new Label("Statistics");
headlineLabel.setStyle("-fx-font-weight: bold;");
cookiesLabel = new Label("Cookies: " + player.getCookies());
cookiesEverProducedLabel = new Label("All Cookies: " +
player.getCookiesEverProduced());
Label producerProductivityLabel = new Label("Producers Productivity: "
+ Producer.getAlltogetherProductivity());
Button produceCookiesButton = new Button("Produce Cookies");
produceCookiesButton.setOnAction(event -> {
player.receiveCookies(clicker.getProductionValue());
actualizeCookieStats();
});
clickerLabel = new Label("Clicker Level " + clicker.getLevel());
clickerLabel.setStyle("-fx-font-weight: bold;");
clickerProductionValueLabel = new Label("Production Value: " +
clicker.getProductionValue());
levelUpClickerButton = new Button("Improve (Costs " +
clicker.getPrice() + ")");
levelUpClickerButton.setOnAction(event -> {
boolean hasImproved = clicker.levelUp(player);
if (hasImproved) {
actualizeCookieStats();
actualizeClickerStats();
informationLabel.setText("Clicker successfully improved");
} else {
informationLabel.setText("Not enough Cookies for improving" +
" Clicker");
}
});
bakeryLabel = new Label("Bakery Level " + bakery.getLevel());
bakeryLabel.setStyle("-fx-font-weight: bold;");
bakeryProductionValueLabel = new Label("Production Value: " +
bakery.getProductionValue());
levelUpBakeryButton = new Button("Improve (Costs " +
bakery.getPrice() + ")");
levelUpBakeryButton.setOnAction(event -> {
boolean hasImproved = bakery.levelUp(player);
if (hasImproved) {
actualizeCookieStats();
actualizeBakeryStats();
informationLabel.setText("Bakery successfully improved");
} else {
informationLabel.setText("Not enough Cookies for improving" +
" Baker");
}
});
factoryLabel = new Label("Factory Level " + factory.getLevel());
factoryLabel.setStyle("-fx-font-weight: bold;");
factoryProductionValueLabel = new Label("Production Value: " +
factory.getProductionValue());
levelUpFactoryButton = new Button("Improve (Costs " +
factory.getPrice() + ")");
levelUpFactoryButton.setOnAction(event -> {
boolean hasImproved = factory.levelUp(player);
if (hasImproved) {
actualizeCookieStats();
actualizeFactoryStats();
informationLabel.setText("Factory successfully improved");
} else {
informationLabel.setText("Not enough Cookies for improving" +
" Factory");
}
});
cookieSmithyLabel = new Label("Cookie Smithy Level " + cookieSmithy
.getLevel());
cookieSmithyLabel.setStyle("-fx-font-weight: bold;");
cookieSmithyProductionValueLabel = new Label("Production Value: " +
cookieSmithy.getProductionValue());
levelUpCookieSmithyButton = new Button("Improve (Costs " +
cookieSmithy.getPrice() + ")");
levelUpCookieSmithyButton.setOnAction(event -> {
boolean hasImproved = cookieSmithy.levelUp(player);
if (hasImproved) {
actualizeCookieStats();
actualizeCookieSmithyStats();
informationLabel.setText("Cookie Smithy successfully improved");
} else {
informationLabel.setText("Not enough Cookies for improving" +
" Cookie Smithy");
}
});
// adding all elements to the statsAndKlickerBox
statsAndKlickerBox.getChildren().add(headlineLabel);
statsAndKlickerBox.getChildren().add(cookiesLabel);
statsAndKlickerBox.getChildren().add(cookiesEverProducedLabel);
statsAndKlickerBox.getChildren().add(producerProductivityLabel);
statsAndKlickerBox.getChildren().add(clickerLabel);
statsAndKlickerBox.getChildren().add(produceCookiesButton);
statsAndKlickerBox.getChildren().add(clickerProductionValueLabel);
statsAndKlickerBox.getChildren().add(levelUpClickerButton);
// display window
stage.setTitle("Cookie Clicker");
stage.setScene(new Scene(root, 400, 250));
stage.show();
Timer producer = new Timer();
producer.scheduleAtFixedRate(new TimerTask() {
public void run() {
Platform.runLater(() -> {
checkIfnewBuildingAvailable();
player.receiveCookies(bakery.getProductionValue());
player.receiveCookies(factory.getProductionValue());
player.receiveCookies(cookieSmithy.getProductionValue());
actualizeCookieStats();
clickerProductionValueLabel.setText("Production Value: " +
clicker.getProductionValue());
producerProductivityLabel.setText("Producers Productivity: "
+ Producer.getAlltogetherProductivity());
});
}
}, 0, 1000);
}
private void checkIfnewBuildingAvailable() {
if (player.getCookiesEverProduced() >= 20 && !bakeryEnabled) {
buildingsBox.getChildren().add(bakeryLabel);
buildingsBox.getChildren().add(bakeryProductionValueLabel);
buildingsBox.getChildren().add(levelUpBakeryButton);
bakeryEnabled = true;
}
if (player.getCookiesEverProduced() >= 1000 && !factoryEnabled) {
buildingsBox.getChildren().add(factoryLabel);
buildingsBox.getChildren().add(factoryProductionValueLabel);
buildingsBox.getChildren().add(levelUpFactoryButton);
factoryEnabled = true;
}
if (player.getCookiesEverProduced() >= 10000 && !cookieSmithyEnabled) {
buildingsBox.getChildren().add(cookieSmithyLabel);
buildingsBox.getChildren().add(cookieSmithyProductionValueLabel);
buildingsBox.getChildren().add(levelUpCookieSmithyButton);
cookieSmithyEnabled = true;
}
}
/* the following methods have the task to actualize the informations
* displayed in the view
*/
private void actualizeCookieStats() {
cookiesLabel.setText("Cookies: " + player.getCookies());
cookiesEverProducedLabel.setText("All Cookies " +
player.getCookiesEverProduced());
}
private void actualizeClickerStats() {
clickerLabel.setText("Clicker Level " + clicker.getLevel());
clickerProductionValueLabel.setText("Production Value: " +
clicker.getProductionValue());
levelUpClickerButton.setText("Improve (Costs " + clicker.getPrice() +
")");
}
private void actualizeBakeryStats() {
bakeryLabel.setText("Bakery Level " + bakery.getLevel());
bakeryProductionValueLabel.setText("Production Value: " +
bakery.getProductionValue());
levelUpBakeryButton.setText("Improve (Costs " + bakery.getPrice() +
")");
}
private void actualizeFactoryStats() {
factoryLabel.setText("Factory Level " + factory.getLevel());
factoryProductionValueLabel.setText("Production Value: " +
factory.getProductionValue());
levelUpFactoryButton.setText("Improve (Costs " + factory.
getPrice() + ")");
}
private void actualizeCookieSmithyStats() {
cookieSmithyLabel.setText("Cookie Smithy Level " + cookieSmithy
.getLevel());
cookieSmithyProductionValueLabel.setText("Production Value: " +
cookieSmithy.getProductionValue());
levelUpCookieSmithyButton.setText("Improve (Costs " + cookieSmithy.
getPrice() + ")");
}
}
Player.java
public class Player {
private int cookies;
private int cookiesEverProduced;
public Player() {
cookies = 0;
cookiesEverProduced = 0;
}
public int getCookies() {
return cookies;
}
public int getCookiesEverProduced() {
return cookiesEverProduced;
}
public void receiveCookies(int value) {
cookies += value;
cookiesEverProduced += value;
}
public boolean pay(int value) {
if (value <= cookies) {
cookies -= value;
return true;
} else {
return false;
}
}
}
Producer.java
public class Producer {
static protected int alltogetherProductivity;
protected String name;
protected int level;
protected int basicProductionValue;
protected int basicPrice;
// this is needed for the compiler (otherwise Clicker cant be compiled, dont
// aks me why)
public Producer() {
}
public Producer(String name, int basicProductionValue, int basicPrice) {
this.name = name;
level = 0;
this.basicProductionValue = basicProductionValue;
this.basicPrice = basicPrice;
}
public int getLevel() {
return level;
}
static public int getAlltogetherProductivity() {
return alltogetherProductivity;
}
public int getProductionValue() {
return basicProductionValue * level;
}
public boolean levelUp(Player player) {
if(player.pay(getPrice())) {
level++;
alltogetherProductivity += basicProductionValue;
return true;
} else {
return false;
}
}
protected int getPrice() {
return (int)(0.5 * basicPrice * (level * level + 1) + 0.5 * basicPrice *
(level + 1));
}
}
Clicker.java
public class Clicker extends Producer {
public Clicker() {
name = "Klicker";
level = 1;
// the value productionValue is not needed
basicPrice = 500;
}
@Override
public int getProductionValue() {
return (int)(level + 0.01 * level * alltogetherProductivity);
}
@Override
public int getPrice() {
return basicPrice;
}
// works very different from the super class method
@Override
public boolean levelUp(Player player) {
if(player.pay(basicPrice)) {
level++;
increasePrice();
return true;
} else {
return false;
}
}
// is used instead of getPrice
private void increasePrice() {
basicPrice *= 2;
}
}