如何使用计时器重绘某些挥杆组件

时间:2016-05-18 19:19:07

标签: java swing timer

引言

大家好,我正在学习如何制作一个小型游戏,你是一个球拍(长方形),所有的小行星(敌人)都在屏幕上掉下来,你必须避开它们

问题

当游戏开始时,敌人(小行星)以非常高的速度在屏幕上绘画,并且它们占据屏幕的所有大小,因此无法避免它们(尝试游戏),我只是想要那个在绘制敌人和下一个敌人之间有一个最短的延迟时间(例如0.5秒)。 但我只是不知道该怎么做,我试图使用Thread.sleep()和TimeUnit,但他们只是让游戏变慢。 在stackoverflow上冲浪我发现我可能会尝试使用Swing计时器,我已经在网上阅读了一些内容,但我想知道如何在我的代码中使用摆动计时器(如果它们可以解决我的问题)。 / p>

这是代码: 主要课程:

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

@SuppressWarnings("serial")
public class Game extends JPanel {

    Racquet racquet = new Racquet(this);
    Enemy Enemy = new Enemy(this);

    static ArrayList<Enemy> enemyList = new ArrayList<Enemy>();


    public Game() {
        addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
            }

            @Override
            public void keyReleased(KeyEvent e) {
                racquet.keyReleased(e);
            }

            @Override
            public void keyPressed(KeyEvent e) {
                racquet.keyPressed(e);
            }
        });
        setFocusable(true);
    }

    /** TO SET THE RANDOM POSITION ON WHERE THE ENEMIES HAVE TO APPEAR ON THE SCREEN **/
    public int random(int x, int y, ArrayList<Enemy> pa){ 
        int r = 0;

        for(int i = 0; i<pa.size(); i++){
            Random rand = new Random();
            r = rand.nextInt(x+y)-1;                
            return r;
        }

        return r;
    }

    /** letting the enemies move on the screen **/
    private void move() { 
        for(int i = 0; i < enemyList.size(); i++){
            enemyList.get(i).move();
        }

        racquet.move();         
    }

    /**  Painting on the screen enemies and the racquet **/
@Override
    public void paint(Graphics g) { 
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 

        for(int i = 0; i < enemyList.size(); i++){
            enemyList.get(i).paint(g2d);
        }
        racquet.paint(g2d); 
    }

    public void gameOver() {
        JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
        System.exit(ABORT);
    }

    public void createEnemy(){
        enemyList.add(new Enemy(this));
    }

    public static void main(String[] args) throws InterruptedException {
        JFrame frame = new JFrame("Asteroids");
        Game game = new Game();
        frame.add(game);
        frame.setSize(300, 400);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        game.random(200, 300, enemyList);

        while (true) {
            game.createEnemy();
            game.move();
            game.repaint();
            Thread.sleep(5);
        }
    }
}

球拍班:

import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;

public class Racquet {
    private static final int Y = 330;
    private static final int WIDTH = 30;
    private static final int HEIGHT = 6 ;
    int x = 0;
    int xa = 0;
    private Game game;

    public Racquet(Game game) {
        this.game = game;
    }

    /** letting the racquet moves on the screen **/
    public void move() { 
        if (x + xa > 0 && x + xa < game.getWidth() - WIDTH)
            x = x + xa;
    }

    /** Creating the rectangle racquet **/
    public void paint(Graphics2D g) { 
        g.fillRect(x, Y, WIDTH, HEIGHT);
    }

    /** // Setting xa everytime to 0, if we don't do this it just takes a single pression to go to a direction until we press the other key **/
    public void keyReleased(KeyEvent e) {  
        xa = 0;
    }

    /** Choosing the direction **/
    public void keyPressed(KeyEvent e) { 
        if (e.getKeyCode() == KeyEvent.VK_LEFT)
            xa = -1;
        if (e.getKeyCode() == KeyEvent.VK_RIGHT)
            xa = 1;
    }


    public Rectangle getBounds() {
        return new Rectangle(x, Y, WIDTH, HEIGHT);
    }

    public int getTopY() {
        return Y;
    }
}

敌人阶级:

import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.*;

public class Enemy {

    private Game game;
    int x = 0;
    int y = 0;
    int xa = 1;
    int ya = 1;

    /** Generating a random position where the enemies have to appear **/
    public Enemy(Game game){
        this.game = game;
        x = game.random(0, 320, game.enemyList); 
    }

    /** Paint the enemies **/
    public void paint(Graphics2D g) {
        g.fillRect(x, y, 20, 20);
    }

    /** move the enemies and detect collisions **/
    public void move(){
        y += ya;
        if(collision()){
            game.gameOver();
        }
    }

    /** returns true if the enemy rectangle touch the racquet **/
    public boolean collision(){
        return game.racquet.getBounds().intersects(getBounds()); 
    }

    public Rectangle getBounds() {
        return new Rectangle(x, y, 20, 20);
    }
}

1 个答案:

答案 0 :(得分:2)

建议:

  1. 你的游戏&#34; tick&#34;时间是5 mSecs,一个不太合理的时间。我建议
    • 你摆脱了魔法&#34;数字,使用常数代替,
    • 并使抽搐变大一点,比如12到15毫秒。
    • 最好使用Swing Timer或者至少确保在定义的后台线程中执行while循环。
  2. 最重要的是,你在游戏循环的每个刻度线上创造了一个新的敌人,而且速度太快了。代替:
    • 每次打勾都不要创造新的敌人
    • 而是节省在字段中创建最后一个敌人的时间,
    • 检查游戏循环中的增量时间current system time - lastEnemyCreationTime
    • 如果增量时间大于合理值(常数值或字段(不是幻数)),则只创建新的敌人。
    • 在创建新敌人时,将lastEnemyCreationTime重置为当前系统时间。
  3. 无关的记录:

    1. 覆盖JPanel的paintComponent,而不是paint方法,因为默认情况下会为您提供双缓冲,这样可以使图像更加流畅。
    2. 支持在KeyListener上使用键绑定,因为这有助于轻松消除使用KeyListeners时固有的焦点问题。