-2

I'm writing a simple pikachu game in Java, and I use swing.Timer with JProgress Bar, my code is like this:

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);
}

The "src" here is a class which extends JFrame to display the game I wrote, and 'n' is the number of pikachu pieces on a level. It works perfectly but after I add "timer", there are lots of problems occured:

  1. I set the variable 't' change by level, but seems like it doesn't work ( I test the value, it was the right value but seems like 'timer' could'n get it). The time ran out too fast, faster if I click more on the pieces, and even if I set it longer it didn't change anything.

  2. When I clicked "New Game" the second times, timer ran out even faster. But if I close the programs and then run again, the time return normal.

  3. If the time ran out and then I click the "New Game" button again, It appears for 1 second then return to the "Game Over screen". Sometimes it works, but "IndexArrayOutOfBounds" Ecception appears.

  4. I want to use the "Pause" button, which means that timer must pause and then continue to run, too. Is there anyway that I can do it?

I guess my problems are based on the code

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

which makes the Game Over screen appears if the timer run out. But I'm new to this and I cant understand how I works, so I can't think of any solutions myself, or maybe it's not the problem.

Hope that I'll get some helps from you guys. Thanks a lot :)

Fuuka Adachi
  • 23
  • 1
  • 7
  • 2
    I can't figure out the source of your errors based on your code snippets, but several features of this code worries me greatly including your direct manipulation of class fields from other classes, something that you should avoid in almost all cases. Also why is this method static? That too is a sign of a bad program design. For better help though, consider creating and posting an [sscce](http://sscce.org) – Hovercraft Full Of Eels Oct 18 '13 at 03:02
  • I know I'm doing bad code, because I changed all "private" of objects on View to "public" and use directly on Controller. But my code is having bugs, 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(), so I changed it @@ I must be dumb, right :( – Fuuka Adachi Oct 18 '13 at 03:28
  • `"so can it be easier if I fix it after i fixed all bugs?"` -- no. It's much easier to write it well the first time. Wash this plan out of your system. `"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(),..."` -- no. Eclipse did not tell you that at all. It said not to use an instance field in a static context, or something similar. The correct fix is just the opposite -- get all that stuff out of the main method and into the class proper. – Hovercraft Full Of Eels Oct 18 '13 at 03:30
  • Consider going through an introductory Java textbook or the Java tutorials as the concepts learned will be directly applicable to your GUI application, and will make the coding of this much easier. – Hovercraft Full Of Eels Oct 18 '13 at 03:39
  • got it :) I'll try to fix the bad code and then ask again. Well, my country doesn't speak English, so it's a little hard to find suitable text book. If there is any good ebook or good tutorial sites, please recommend me about that. Thanks a lot for your help :D – Fuuka Adachi Oct 18 '13 at 04:09
  • The best tutorial I know is unfortunately in English: [The Java Tutorials](http://docs.oracle.com/javase/tutorial/reallybigindex.html). – Hovercraft Full Of Eels Oct 18 '13 at 04:10

1 Answers1

2

Your problem is that you don't use correct architecture pattern. You should separate your business logic from your presentation. Also you should store variables (like time_left) in model, not in the controller (i.e. ActionListener). Please read about: Model View Controller pattern. It's a basic pattern and it'll solve most of yours problems.

Basic Example

mvc

Editor.java - main class

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 - implements 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
    }

}

As you can see I have the one place (Controller.java) where I create listeners and add
these to components in view. You created multiple instances of the same listeners and lost control.

Also my ActionListener (ViewControlListener.java) holds instances of model and view, so it can update variables in model and refresh view.

Your application

And now something more about your application. You need thread (not realy action listener) that would decrement time variable and update view to show actual state (but only when game is active).

So you could create in model leftTime and isActive variables with setters and getters:

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;
}

And create thread that decrement time every second and repaint the view:

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();
            }
        }
    }
}

Then create and start that thread in Controller:

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

In view you would add some component that shows left time from model and that's it.

PS do not forget set leftTime on game start.

rebeliagamer
  • 1,257
  • 17
  • 33
  • 1
    Related examples may be found [here](http://stackoverflow.com/a/2687871/230513) and [here](http://stackoverflow.com/a/3072979/230513). – trashgod Oct 18 '13 at 09:47