为了更加熟悉线程,我一直在从事 Java 的一个辅助项目。它是一个 cookie clicker 克隆,它使用不同的线程用于 clicker、counter 和其他所有内容。在尝试运行最终构建时,我得到一个无限递归错误,导致我的一个类初始化时堆栈溢出。我已经尝试将类移动到它自己的文件中,但这似乎并没有改变任何东西。这是代码:
游戏.java
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.BorderLayout;
import java.awt.Dimension;
public class Game { // main class
// Integer
int total = 0;
int perSec = 0;
int perClick = 1;
int upgradeIndex = 0;
// Boolean
boolean running = false;
// JFrame
JFrame window;
// JTextField
JTextField totalDisplay;
// JButton
JButton clickArea;
JButton upgrade1;
JButton upgrade2;
JButton upgrade3;
JButton nextPage;
JButton prevPage;
// JPanel
JPanel clickWindow;
JPanel upgrades;
JPanel navigation;
// Upgrades
// Click upgrade
PerClickUpgrade exclamation; // amount 1 cost 10
PerClickUpgrade at; // amount 10 cost 100
PerClickUpgrade hashtag; // amount 100 cost 1000
PerClickUpgrade dollar; // amount 1000 cost 10000
// Sec upgrade
PerSecUpgrade percent; // amount 10 cost 1000
PerSecUpgrade carrot; // amount 100 cost 10000
PerSecUpgrade and; // amount 1000 cost 100000
// Click multiplier
PerClickMultiplier asterisk; // amount 2x cost 1000000
// Sec multiplier
PerSecMultiplier tilde; // amount 2x cost 10000000
Game() {
window = new JFrame(); // main window
clickWindow = new JPanel(); // panel for click button
upgrades = new JPanel(); // panel for upgrades
upgrade1 = new JButton();
upgrade2 = new JButton();
upgrade3 = new JButton();
navigation = new JPanel(); // navigate upgrade menu
nextPage = new JButton();
prevPage = new JButton();
exclamation = new PerClickUpgrade("!", 1, 10, upgrade1);
at = new PerClickUpgrade("@", 10, 100, upgrade2);
hashtag = new PerClickUpgrade("#",100,1000,upgrade3);
dollar = new PerClickUpgrade("$",1000,10000,upgrade1);
percent = new PerSecUpgrade("%",10,1000,upgrade2);
carrot = new PerSecUpgrade("^",100,10000, upgrade3);
and = new PerSecUpgrade("&", 1000,100000, upgrade1);
asterisk = new PerClickMultiplier("*",2,1000000, upgrade2);
tilde = new PerSecMultiplier("~", 2, 10000000, upgrade3);
window.setSize(new Dimension(800, 600));
window.setResizable(false);
window.setLocationRelativeTo(null);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setTitle("ASCII Clicker");
window.setLayout(new BorderLayout());
clickWindow.setPreferredSize(new Dimension((800 / 2), 600));
upgrades.setPreferredSize(new Dimension((800 / 2), 600));
navigation.setPreferredSize(new Dimension((800 / 2), (600 / 4)));
clickWindow.setLayout(new BorderLayout());
navigation.setLayout(new BorderLayout());
window.add(clickWindow, BorderLayout.WEST);
window.add(upgrades, BorderLayout.EAST);
clickWindow.add(totalDisplay, BorderLayout.PAGE_START);
clickWindow.add(clickArea, BorderLayout.CENTER);
upgrades.add(upgrade1);
upgrades.add(upgrade2);
upgrades.add(upgrade3);
upgrades.add(navigation);
navigation.add(nextPage, BorderLayout.EAST);
navigation.add(prevPage, BorderLayout.WEST);
window.pack();
Thread clickDetection = new Thread(new Clicker()); // detects clicks
Thread counter = new Thread(new Counter()); // counts total
clickDetection.start();
counter.start();
window.setVisible(true);
exclamation.update(); // sets exclamation, at, and hashtag as displayed upgrades
at.update();
hashtag.update();
upgrade1.addActionListener(e -> {
switch (upgradeIndex) {
case 0 -> exclamation.buy();
case 1 -> dollar.buy();
case 2 -> and.buy();
}
});
upgrade2.addActionListener(e -> {
switch (upgradeIndex) {
case 0 -> at.buy();
case 1 -> percent.buy();
case 2 -> asterisk.buy();
}
});
upgrade3.addActionListener(e -> {
switch (upgradeIndex) {
case 0 -> hashtag.buy();
case 1 -> carrot.buy();
case 2 -> tilde.buy();
}
});
prevPage.addActionListener(e -> {
if (upgradeIndex != 0) {
upgradeIndex--;
switch (upgradeIndex) {
case 0 -> {
exclamation.update();
at.update();
hashtag.update();
}
case 1 -> {
dollar.update();
percent.update();
carrot.update();
}
case 2 -> {
and.update();
asterisk.update();
tilde.update();
}
}
}
});
nextPage.addActionListener(e -> {
if (upgradeIndex != 2) {
upgradeIndex++;
switch (upgradeIndex) {
case 0 -> {
exclamation.update();
at.update();
hashtag.update();
}
case 1 -> {
dollar.update();
percent.update();
carrot.update();
}
case 2 -> {
and.update();
asterisk.update();
tilde.update();
}
}
}
});
}
public static void main(String[] args) {
new Game();
}
}
class Counter extends Game implements Runnable { // Updates counter
@Override
public void run() {
running = true;
while (running) {
total += (perSec / 10);
totalDisplay.setText(String.valueOf(total));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Clicker extends Game implements Runnable { // Records clicks
@Override
public void run() {
clickArea.setText("()");
clickArea.addActionListener(e -> total += perClick);
}
}
PerClickUpgrade.java
class PerClickUpgrade extends Game {
private int totalUpgrade = 0;
private int totalCost;
private final int upgradeAmount;
private final int cost;
private int timesBought = 0;
private final JButton display;
private final String symbol;
PerClickUpgrade(String symbol, int upgradeAmount, int cost, JButton display) {
this.symbol = symbol;
this.totalCost = cost;
this.cost = cost;
this.upgradeAmount = upgradeAmount;
this.display = display;
}
public void update() {
this.display.setText(
this.symbol +
"\nOwned: " +
this.timesBought +
"\nPer Click Increase: " +
this.totalUpgrade +
"\nCost: " +
this.totalCost
);
}
public void buy() {
if (total >= this.totalCost) {
this.timesBought++;
this.totalUpgrade += this.upgradeAmount;
perClick = this.totalUpgrade;
total -= this.cost;
this.totalCost += (this.cost / 2);
this.update();
}
}
}
PerSecUpgrade.java
class PerSecUpgrade extends Game {
private int totalUpgrade = 0;
private int totalCost;
private final int upgradeAmount;
private final int cost;
private int timesBought = 0;
private final JButton display;
private final String symbol;
PerSecUpgrade(String symbol, int upgradeAmount, int cost, JButton display) {
this.symbol = symbol;
this.totalCost = cost;
this.cost = cost;
this.upgradeAmount = upgradeAmount;
this.display = display;
}
void update() {
this.display.setText(
this.symbol +
"\nOwned: " +
this.timesBought +
"\nPer Click Increase: " +
this.totalUpgrade +
"\nCost: " +
this.totalCost
);
}
void buy() {
if (total >= this.totalCost) {
this.timesBought++;
this.totalUpgrade += this.upgradeAmount;
perSec = this.totalUpgrade;
total -= this.cost;
this.totalCost += (this.cost / 2);
this.update();
}
}
}
PerSecMultiplier.java
class PerSecMultiplier extends Game {
private int totalCost;
private final int upgradeAmount;
private final int cost;
private int timesBought = 0;
private final JButton display;
private final String symbol;
PerSecMultiplier(String symbol, int upgradeAmount, int cost, JButton display) {
this.symbol = symbol;
this.totalCost = cost;
this.cost = cost;
this.upgradeAmount = upgradeAmount;
this.display = display;
}
void update() {
this.display.setText(
this.symbol +
"\nOwned: " +
this.timesBought +
"\n" +
this.upgradeAmount +
"x Per Sec\nCost: " +
this.cost
);
}
void buy() {
if (total >= this.totalCost) {
this.timesBought++;
perSec *= this.upgradeAmount;
total -= this.totalCost;
this.totalCost += (this.cost / 2);
this.update();
}
}
}
每次点击乘数
public class PerClickMultiplier extends Game {
private final int upgradeAmount;
private final int cost;
private final JButton display;
private final String symbol;
private int totalCost;
private int timesBought = 0;
PerClickMultiplier(String symbol, int upgradeAmount, int cost, JButton display) {
this.totalCost = cost;
this.upgradeAmount = upgradeAmount;
this.cost = cost;
this.display = display;
this.symbol = symbol;
}
void update() {
this.display.setText(
this.symbol +
"\nOwned: " +
this.timesBought +
"\n" +
this.upgradeAmount +
"x Per Click\nCost: " +
this.cost
);
}
void buy() {
if (total >= this.totalCost) {
this.timesBought++;
perClick *= this.upgradeAmount;
total -= this.totalCost;
this.totalCost += (this.cost / 2);
this.update();
}
}
}
任何其他一般性批评也值得赞赏。