JButton ArrayList 没有在滴答时正确更新?

JButton ArrayList not updating correctly on tick?

我正在使用默认的 JFrame gui 开发一个简单的闲置游戏(想想 CookieClicker)。货币单位是 'clicks',赚取足够的 'clicks' 后,玩家应该能够点击与他们可以购买的自动点击器相对应的 JButton。但是,只有添加到自动点击器 ArrayList 的最后一个 'autoclicker' 在正确的时间变得可用,并且如果单击它,所有其他 JButton 将采用其属性。如果可能的话,你能帮我找出问题吗?免责声明:可能是一堆故障排除。

这是我的主要内容 class: (我将额外的 JButtons 和 AutoClickers 注释掉了,所以它按预期工作)

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;

import javax.swing.*;

public class Main extends JFrame /*implements Runnable*/{

    static double clickCount = 0D;
    static double cpst = 0D;
    static JFrame frameMain = new JFrame("Clicker - Evan");
    static JLabel labelCount = new JLabel("Click Count: " + clickCount);
    static JLabel labelcps = new JLabel("Click Per Second: " + cpst);
    static ArrayList<AutoClicker> clickers = new ArrayList<AutoClicker>(/*Arrays.asList(AutoClicker("Mouse", 1, 10))*/);
    static ArrayList<JButton> buttonAuto = new ArrayList<JButton>();

    static JButton buttonMain = new JButton("Click");

    private static boolean running = false;
    //private Thread thread;

    public static void main(String[] args){
        init();
        run();
    }

    static long lastTime2 = System.nanoTime();
    final static double amountOfTicks2 = 2D;
    static double ns2 = 1000000000 / amountOfTicks2;
    double delta2 = 0;

    //Reference: https://www.youtube.com/watch?v=jEXxaPQ_fQo
    static class buttonMainAction implements ActionListener{
        public void actionPerformed(ActionEvent e){
            clickCount++;

            System.out.println("refresh?");


        }
    }
    static class buttonBuyAction implements ActionListener{
        public void actionPerformed(ActionEvent e){
            int fromNumber = Integer.parseInt(e.getActionCommand());

            clickCount -= (int)clickers.get( fromNumber ).getCost();
            clickers.get( fromNumber ).buy();
            buttonAuto.get( fromNumber ).setText(clickers.get( fromNumber ).getNumberOwned() 
                    + " " + clickers.get( fromNumber ).getName() + "(s) - Cost: " + (int)clickers.get( fromNumber ).getCost() + " Clicks");

            System.out.println("+1 " + clickers.get( fromNumber ).getName());
        }
    }


    //Source: https://www.youtube.com/watch?v=qSdKBQMdlLM
    //Source 2: https://www.youtube.com/watch?v=vFRuEgEdO9Q&list=PLah6faXAgguMnTBs3JnEJY0shAc18XYQZ&index=4
    public static void run(){

        long lastTime = System.nanoTime();
        final double amountOfTicks = 60D;
        double ns = 1000000000 / amountOfTicks;
        double delta = 0;

        //init();

        while(running){
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            if(delta >= 1){
                tick();
                delta--;
            }

            render();
        }
    }

    private static void init(){
        clickers.add(new AutoClicker("Mouse", .1, 10));
//      clickers.add(new AutoClicker("Monkey", .36, 50));
//      clickers.add(new AutoClicker("Toddler", .5, 250));
//      clickers.add(new AutoClicker("Pre-Teen", 1, 700));
//      clickers.add(new AutoClicker("Angsty Teen", 1.5, 1500));
//      clickers.add(new AutoClicker("Intern", 2.5, 2000));
//      clickers.add(new AutoClicker("Newbie", 5, 4000));
//      clickers.add(new AutoClicker("HR Staffer", 10, 10000));
//      clickers.add(new AutoClicker("Misc. Staffer", 15, 12000));
//      clickers.add(new AutoClicker("Media Analyst", 30, 100000));
//      clickers.add(new AutoClicker("CEO", 50, 800000));
//      clickers.add(new AutoClicker("Researcher", 80, 2000000));
//      
//      
//      clickers.add(new AutoClicker("Sacrifice Leader", 500, 99999999));

        System.out.println("clickers.size()=\t" + clickers.size());

        frameMain.setVisible(true);

        frameMain.setSize(800, 600);
        frameMain.setResizable(false);
        frameMain.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frameMain.setLayout(new FlowLayout());


        frameMain.add(buttonMain);
        buttonMain.addActionListener(new buttonMainAction() );


        buttonAuto.add(new JButton("0 Mouse(s) - Cost: 10 Clicks"));
//      buttonAuto.add(new JButton("0 Monkey(s) - Cost: 50 Clicks"));
//      buttonAuto.add(new JButton("0 Toddler(s) - Cost: 250 Clicks"));
//      buttonAuto.add(new JButton("0 Pre-Teen(s) - Cost: 700 Clicks"));
//      buttonAuto.add(new JButton("0 Angsty Teen(s) - Cost: 1500 Clicks"));
//      buttonAuto.add(new JButton("0 Intern(s) - Cost: 2000 Clicks"));
//      buttonAuto.add(new JButton("0 Newbie(s) - Cost: 4000 Clicks"));
//      buttonAuto.add(new JButton("0 HR Staffer(s) - Cost: 10000 Clicks"));
//      buttonAuto.add(new JButton("0 Misc. Staffer(s) - Cost: 12000 Clicks"));
//      buttonAuto.add(new JButton("0 Media Analyst(s) - Cost: 100000 Clicks"));
//      buttonAuto.add(new JButton("0 CEO(s) - Cost: 800000 Clicks"));
//      buttonAuto.add(new JButton("0 Researcher(s) - Cost: 2000000 Clicks"));
//      buttonAuto.add(new JButton("0 Sacrafice Leader(s) - Cost: 99999999 Clicks"));

        frameMain.add(labelcps);
        frameMain.add(labelCount);

        for(int i = 0; i<buttonAuto.size(); i++){
            buttonAuto.get(i).addActionListener(new buttonBuyAction() );
        buttonAuto.get(i).setActionCommand(Integer.toString(i));
        frameMain.add(buttonAuto.get(i));
        }


        running = true;
    }

    /*
    public synchronized void start(){
        if(running)
            return;
        running = true;
        thread = new Thread(this);
        thread.start();
    }

    public synchronized void stop(){
        if(!running)
            return;
        running = false;

        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    */

    static void tick(){
        //do stuff
        for(AutoClicker clicker: clickers){
            clickCount += (clicker.getCPS() / 60)* clicker.getNumberOwned();
            System.out.println("added " + (clicker.getCPS() / 60)* clicker.getNumberOwned()
                    + " from " + clicker.getNumberOwned() + " " + clicker.getName() +"'s");
        }
    }
    static void render(){
        double cpst = 0;
        for(AutoClicker clicker: clickers){
            cpst += (clicker.getCPS())* clicker.getNumberOwned();
        }
        labelCount.setText("[ Click Count: " + (int)clickCount + " ]");
        labelcps.setText("[ Click Per Second: " + ((int)(cpst*10))/10.0 + " ]");

        for(int i = 0; i < clickers.size(); i++){
            if((int)clickers.get(i).getCost()>clickCount){
                if(buttonAuto.get(i).isEnabled())
                    buttonAuto.get(i).setEnabled(false);
            }else{
                if(!buttonAuto.get(i).isEnabled())
                    buttonAuto.get(i).setEnabled(true);
            }

        }
    }

}

这是我的 AutoClicker class:

public class AutoClicker {
    private static String name;
    private static double cps;
    private static double cost;
    private static int numberOwned;

    public AutoClicker(String nameIn, double cpsIn, int costIn){
        name = nameIn;
        cps = cpsIn;
        cost = costIn;
        numberOwned = 0;
    }

    public String getName(){
        return name;
    }
    public double getCPS(){
        return cps;
    }
    public double getCost(){
        return cost;
    }
    public int getNumberOwned(){
        return numberOwned;
    }

    public void buy(){
        numberOwned++;
        cost*=1.174;
    }
}

非常感谢! ^_^

  1. 去掉大部分静态修饰符。尤其是 AutoClicker class 中的所有内容。当这些字段是静态的时,它们成为 class 而不是对象的字段,因此每个 AutoClicker 对象与所​​有其他对象共享相同的字段 -- 这不是您想要的。

事实上,可能唯一应该是静态的应该是 main 方法,仅此而已。然后你可以改变这个:

public static void main(String[] args){
    init();
    run();
}

对此:

public static void main(String[] args){
    Main main = new Main();
    main.init();
    main.run();
}

还有

  • 您已经声明了 cpst 变量两次,一次是 class 的一个字段,一次是 render() 方法的局部变量,最后一个隐藏了 class 字段 --您确定要这样做吗?
  • 如评论中所述,您正在主线程中调用 run() 方法中的代码。如果您的代码启动得当,这将在 Swing 事件线程中调用,并会完全冻结您的程序。如果您随后更正此问题并将 Runnable 放置在线程中并对其调用 start(),那么现在您将在后台线程中改变 Swing 组件——所有这些都是危险的事情。请阅读:课程:Swing 中的并发,了解如何解决此问题。