繁体   English   中英

如何使用计时器重画一些摆动组件

[英]How to use a timer to repaint some swing components

介绍

大家好,我正在学习如何制作一个球拍(矩形)而所有小行星(敌人)掉落在屏幕上的小游戏,您必须避免它们

问题

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

这是代码:主类:

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. 您的游戏“滴答”时间为5毫秒,这不是很合理的时间。 我建议
    • 您可以改用常数来摆脱“魔术”数,
    • 并增加tic的大小,例如12至15毫秒。
    • 也最好使用Swing计时器,或者至少确保您在定义的后台线程中执行while循环。
  2. 最重要的是,您要在游戏循环的每一刻创建一个新敌人,这太快了。 代替:
    • 不要在每次打勾时都创建一个新的敌人,
    • 而是节省了在田间创建最后一个敌人的时间,
    • 在游戏循环中检查时间增量, current system time - lastEnemyCreationTime
    • 仅当增量时间大于合理值(恒定值或字段(不是幻数))时,才创建新敌人。
    • 创建新敌人时,将lastEnemyCreationTime重置为当前系统时间。

不相关的记录:

  1. 重写JPanel的paintComponent ,而不是paint方法,因为默认情况下,这将为您提供双缓冲,这可以使图形更流畅。
  2. 支持在KeyListener上使用Key Bindings,因为这将有助于轻松消除使用KeyListeners固有的焦点问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM