如何在游戏过程中改变Timer()的速度?

时间:2014-04-10 18:35:31

标签: java swing graphics timer illegalstateexception

我做了一个游戏,计算你可以在空中举行一个球(矩形)的次数。问题是我想让球每次都移动得更快。初始速度为10,我希望每次球再次上升时倒计时(“速度”越低 - 实际速度越快)。

但是当球需要加快时,我会在我执行此操作的行上获得IllegalStateException:“spelTimer.schedule(panel.spelTask​​,0,speed);”我该如何解决这个问题?

    import java.util.*;
    import java.awt.*;
    import java.awt.event.*;

    import javax.swing.*;

    public class Spel extends JPanel implements KeyListener {

    public Rectangle screen, ball, block;
    public Rectangle bounds;
    public JFrame frame;
    public SpelTimerTask spelTask;
    public boolean down, right, starten = false;
    public JButton start;
    public int counter = 0;
    public JLabel score;
    public static int speed = 10;
    public static java.util.Timer spelTimer;
    public static Spel panel;

    public Spel(){
        super();
        screen = new Rectangle(0, 0, 600, 400);
        ball   = new Rectangle(0, 0, 20, 20);
        bounds = new Rectangle(0, 0, 600, 400);
        block = new Rectangle(bounds.width/2, bounds.height-50, 40, 10);
        frame = new JFrame("Super tof spel van Stan \u00a9");
        spelTask = new SpelTimerTask();
        score = new JLabel("0");
        score.hide();
        add(score);
        addKeyListener(this);
        setFocusable(true);
        start = new JButton("Start");
        start.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                starten = true;
                ball   = new Rectangle(0, 0, 20, 20);
                start.setFocusable(false);
                start.hide();
                score.show();
            }
        });
        add(start);
    }

    class SpelTimerTask extends TimerTask{
        public void run(){
            repaint();

            if(starten){
            moveBall();
            frame.repaint();
            }
        }
      }

      public void paintComponent(Graphics g){
        bounds = g.getClipBounds();
        g.clearRect(screen.x, screen.y, screen.width, screen.height);
        g.fillRect(ball.x, ball.y, ball.width, ball.height);
        g.fillRect(block.x, block.y, block.width, block.height);
      }

      public void moveBall(){
        if (right) ball.x+=1;
        else ball.x-=1;
        if (down)  ball.y+=1;
        else ball.y-=1;
        if (ball.x > (bounds.width - ball.width)) {
            right = false; 
            ball.x = bounds.width -  ball.width; 
        }
        if (ball.y == (bounds.height - ball.height - 10) && ball.x > block.x-20 && ball.x < block.x+40) { 
            down  = false; 
            ball.y = bounds.height - ball.height - 10;
            counter++;
            if(speed > 2){
                speed -= 1;
                spelTimer.schedule(panel.spelTask, 0, speed);
            }
        }
        if (ball.y > (bounds.height - ball.height)) {
            start.show();
            score.hide();
            counter = 0;
        }
        if (ball.x < 0) { 
            right = true; 
            ball.x = 0; 
        }
        if (ball.y == 0){ 
            down  = true; ball.y = 0; 
        }
        block.y = bounds.height-10;
        score.setText(Integer.toString(counter));
      }

      public void keyPressed(KeyEvent evt) {
          if(evt.getKeyCode() == KeyEvent.VK_LEFT && block.x > 0) {
              block.x -= 20;
          }

          if(evt.getKeyCode() == KeyEvent.VK_RIGHT && block.x < (bounds.width - block.width - 20)) {
              block.x += 20;
          }
      }

      public void keyTyped(KeyEvent evt){  }
      public void keyReleased(KeyEvent evt){ }

      public void startActionPerformed(java.awt.event.ActionEvent evt) {
          starten = true;
      }

      public static void main(String arg[]){
        spelTimer = new java.util.Timer();
        panel = new Spel();

        panel.down = true;
        panel.right = true;

        panel.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        panel.frame.setSize(panel.screen.width, panel.screen.height);
        panel.frame.setContentPane(panel); 
        panel.frame.setVisible(true);

        spelTimer.schedule(panel.spelTask, 0, speed);
      }
}

1 个答案:

答案 0 :(得分:0)

最后进入Java环境。

首先,您收到的错误表示您正在尝试安排已安排的任务。所以你需要取消它。这带来了一个小问题,即在取消某些东西之后,它就无法重新启动。因此,您需要创建一个新任务,并安排它。

您的代码在这里:

if(speed > 2){
    speed -= 1;
    spelTimer.schedule(panel.spelTask, 0, speed);
}

我将其修改为:

if(speed > 2){
    speed -= 1;
    panel.spelTask.cancel();
    panel.spelTask = new SpelTimerTask();
    spelTimer.schedule(panel.spelTask, 0, speed);
}

在我修复问题的测试中。

正如对此主题的进一步扩展一样,为了防止每次想要改变速度时都必须执行新任务,您可以改为将您的移动速度乘以速度。

编辑:根据要求,此处是使用速度倍增器而不是更改定时器计划速度的修改。我最终以1 +(1 *速度)而不是1 *速度运行,允许更加渐进的速度变化。

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Spel extends JPanel implements KeyListener {
    public Rectangle screen, ball, block;
    public Rectangle bounds;
    public JFrame frame;
    public SpelTimerTask spelTask;
    public boolean down, right, starten = false;
    public JButton start;
    public int counter = 0;
    public JLabel score;
    private final static int interval = 1000/60;
    public static int speed = 0;
    public static java.util.Timer spelTimer;
    public static Spel panel;

    public Spel() {
        super();
        screen = new Rectangle(0, 0, 600, 400);
        ball   = new Rectangle(0, 0, 20, 20);
        bounds = new Rectangle(0, 0, 600, 400);
        block = new Rectangle(bounds.width/2, bounds.height-50, 40, 10);
        frame = new JFrame("Super tof spel van Stan \u00a9");
        spelTask = new SpelTimerTask();
        score = new JLabel("0");
        score.setVisible(false);
        add(score);
        addKeyListener(this);
        setFocusable(true);
        start = new JButton("Start");
        start.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                speed = 0;
                starten = true;
                ball   = new Rectangle(0, 0, 20, 20);
                start.setFocusable(false);
                start.setVisible(false);
                score.setVisible(true);
            }
        });
        add(start);
    }

    class SpelTimerTask extends TimerTask {
        public void run(){
            repaint();

            if(starten){
                moveBall();
                frame.repaint();
            }
        }
    }

    public void paintComponent(Graphics g) {
        bounds = g.getClipBounds();
        g.clearRect(screen.x, screen.y, screen.width, screen.height);
        g.fillRect(ball.x, ball.y, ball.width, ball.height);
        g.fillRect(block.x, block.y, block.width, block.height);
    }

    public synchronized void moveBall() {
        if (right) ball.x+=(1 + 1 * speed);
        else ball.x-=(1 + 1 * speed);
        if (down)  ball.y+=(1 + 1 * speed);
        else ball.y-=(1 + 1 * speed);
        if (ball.x >= bounds.width) {
            right = false;
        }
        if (ball.y >= (bounds.height - ball.height - 10)) {
            if  (ball.x > block.x-20 && ball.x < block.x+40) {
                down  = false; 
                ball.y = bounds.height - ball.height - 10;
                counter++;
                if(speed < 10){
                    speed += 1;
                }
            } else {
                start.setVisible(true);
                score.setVisible(false);
                starten = false;
                counter = 0;
            }
        }
        if (ball.x <= 0) { 
            right = true;
        }
        if (ball.y <= 0){ 
            down  = true;
        }
        block.y = bounds.height-10;
        score.setText(Integer.toString(counter));
    }

    public void keyPressed(KeyEvent evt) {
        if(evt.getKeyCode() == KeyEvent.VK_LEFT && block.x > 0) {
            block.x -= 20;
        }

        if(evt.getKeyCode() == KeyEvent.VK_RIGHT && block.x < (bounds.width - block.width - 20)) {
            block.x += 20;
        }
    }

    public void keyTyped(KeyEvent evt) {}
    public void keyReleased(KeyEvent evt) {}

    public void startActionPerformed(java.awt.event.ActionEvent evt) {
        starten = true;
    }

    public static void main(String arg[]) {
        spelTimer = new java.util.Timer();
        panel = new Spel();

        panel.down = true;
        panel.right = true;

        panel.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        panel.frame.setSize(panel.screen.width, panel.screen.height);
        panel.frame.setContentPane(panel); 
        panel.frame.setVisible(true);

        spelTimer.schedule(panel.spelTask, 0, interval);
    }
}

这里的一些重要说明:

  1. 我改变了你所有的边界检查。由于球不是一次一次1 x和1 y,所以每次都不会完美地击中屏幕的两侧。所以改变是检查块是否在边界或超出边界。您可以返回并更改它,以便在超出界限时重新调整位置,但这可能会导致其他问题。
  2. 我将moveBall更改为同步方法,因为我有一个奇怪的情况,即moveBall似乎同时被调用了两次。
  3. 我将计时器间隔更改为1000/60。我这样做是因为典型的人眼只能跟踪低于60Hz的运动(每秒60次变化)。因此,这个时间应该是人们无法看到变化的门槛;让球顺利运动。
  4. 如果您不了解我的更改,我很乐意在评论中讨论这些内容。