【问题标题】:How can I use Program a game after swing.Timer stopped?swing.Timer停止后如何使用Program a game?
【发布时间】:2013-10-18 03:00:09
【问题描述】:

我正在用Java编写一个简单的皮卡丘游戏,我使用swing.Timer和JProgress Bar,我的代码是这样的:

public static void TimeBarListener(final View scr){
    ActionListener updateProBar = new ActionListener() {
        @Override
            public void actionPerformed(ActionEvent actionEvent) {
            int val = scr.timeBar.getValue();
            if (val <= 0) {
                scr.gameOver();
                scr.timer = null;
                return;
            }
            scr.timeBar.setValue(--val);
        }
    };
    int t = n*400;
    scr.timer = new Timer(t, updateProBar);
}

这里的“src”是一个扩展JFrame的类来显示我写的游戏,“n”是一个关卡上皮卡丘的数量。它工作得很好,但是在我添加“计时器”之后,出现了很多问题:

  1. 我将变量“t”设置为按级别更改,但似乎不起作用(我测试了该值,它是正确的值,但似乎“计时器”无法获得它)。时间用得太快了,如果我点击更多的碎片,时间会更快,即使我设置得更长,它也没有改变任何东西。

  2. 当我第二次点击“新游戏”时,计时器跑得更快了。但是如果我关闭程序然后再次运行,时间就会恢复正常。

  3. 如果时间用完,然后我再次单击“新游戏”按钮,它会出现 1 秒钟,然后返回“游戏结束屏幕”。有时它有效,但出现“IndexArrayOutOfBounds”Ecception。

  4. 我想使用“暂停”按钮,这意味着计时器也必须暂停然后继续运行。反正我能做到吗?

我猜我的问题是基于代码

            if (val <= 0) {
                scr.gameOver();
                scr.timer = null;
                return;
            }

如果计时器用完,则会出现 Game Over 屏幕。但是我是新手,我无法理解我的工作原理,所以我自己想不出任何解决方案,或者也许这不是问题。

希望我能从你们那里得到一些帮助。非常感谢:)

【问题讨论】:

  • 我无法根据您的代码 sn-ps 找出错误的来源,但该代码的几个功能让我非常担心,包括您直接操作其他类的类字段,您几乎在所有情况下都应该避免。另外为什么这种方法是静态的?这也是糟糕的程序设计的标志。不过,为了获得更好的帮助,请考虑创建并发布 sscce
  • 我知道我的代码很糟糕,因为我将 View 上的所有“私有”对象更改为“公共”并直接在 Controller 上使用。但是我的代码有错误,所以如果我在修复所有错误后修复它会更容易吗?关于静态,好吧,反正我是新手,如果我想在main()中使用那个方法,Eclipse告诉我把它改成静态,所以我改了@@我一定很笨,对吧:(跨度>
  • "so can it be easier if I fix it after i fixed all bugs?" -- 没有。第一次把它写好要容易得多。从你的系统中清除这个计划。 "and about static, well, I'm a newbie anyway, and Eclipse tell me to change it to static if I want to use that method in main(),..." -- 没有。 Eclipse 根本没有告诉你。它说不要在静态上下文中使用实例字段或类似的东西。正确的解决方法恰恰相反——把所有的东西从主方法中取出并放入适当的类中。
  • 考虑阅读介绍性的 Java 教科书或 Java 教程,因为学到的概念将直接适用于您的 GUI 应用程序,并且会使编码变得更加容易。
  • 知道了 :) 我会尝试修复错误的代码,然后再询问。嗯,我的国家不会说英语,所以找到合适的教科书有点困难。如果有任何好的电子书或好的教程网站,请向我推荐。非常感谢您的帮助:D

标签: java eclipse swing timer


【解决方案1】:

您的问题是您没有使用正确的架构模式。您应该将业务逻辑与演示文稿分开。此外,您应该将变量(如time_left)存储在模型中,而不是控制器中(即ActionListener)。请阅读:Model View Controller 模式。这是一个基本模式,它会解决你的大部分问题。

基本示例

Editor.java - 主类

public class Editor {
    public static void main(String[] args) {
        Model model = new Model();
        View view = new View(model);
        new Controller(model, view);
    }
}

View.java

public class View extends JFrame {

    private Model model;
    private JButton btn;

    public View(Model model) {
        this.model = model;
        this.btn = new JButton("Test");
    }

    public void addViewControlListener(ActionListener al){
        btn.addActionListener(al);
    }
}

Controller.java

public class Controller {
    public Controller(Model model, View view) {
        view.addViewControlListener(new ViewControlListener(model, view));
    }
}

ViewControlListener.java - 实现 ActionListener

public class ViewControlListener implements ActionListener {

    private Model model;
    private View view;

    public ViewControlListener(Model model, View view){
        this.model = model;
        this.view = view;
    }

    public void actionPerformed(ActionEvent e) {
        //update model
        //refresh view
    }

}

如您所见,我在一个地方 (Controller.java) 创建侦听器并添加
这些要组件在视图中。您创建了相同侦听器的多个实例并失去了控制。

我的ActionListener (ViewControlListener.java) 也持有模型和视图的实例,因此它可以更新模型中的变量并刷新视图。

您的应用程序

现在关于您的应用程序的更多信息。您需要减少时间变量并更新视图以显示实际状态的线程(不是真正的动作侦听器)(但仅在游戏处于活动状态时)。

所以你可以在模型中创建 leftTimeisActive 带有 setter 和 getter 的变量:

private int leftTime;
private boolean isActive;

public int getLeftTime() {
    return leftTime;
}

public void setLeftTime(int leftTime) {
    this.leftTime = leftTime;
}

public void decLeftTime() {
    this.leftTime--;
}

public boolean isActive() {
    return isActive;
}

public void setActive(boolean isActive) {
    this.isActive = isActive;
}

并创建每秒递减时间的线程并重新绘制视图:

public class Timer extends Thread {

    private Model model;
    private View view;

    public Timer(Model model, View view) {
        this.model = model;
        this.view = view;
    }

    public void run() {
        while(true) { //could be better
            if(model.isActive()) {
                model.decLeftTime();
                view.repaint();
            }
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

然后在 Controller 中创建并启动该线程:

public class Controller {
    public Controller(Model model, View view) {
        view.addViewControlListener(new ViewControlListener(model, view));
        ...
        Timer timer = new Timer(model, view);
        timer.start();
    }
}

在视图中,您将添加一些显示模型剩余时间的组件,仅此而已。

PS 不要忘记在游戏开始时设置leftTime

【讨论】:

  • 相关例子可以在herehere找到。
猜你喜欢
  • 2012-04-11
  • 1970-01-01
  • 2012-09-11
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多