gpt4 book ai didi

java - 如何使用计时器重新绘制一些 Swing 组件

转载 作者:行者123 更新时间:2023-11-30 02:55:30 24 4
gpt4 key购买 nike

简介

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

问题

当游戏开始时,敌人(小行星)会以非常高的速度在屏幕上绘制,并且它们占据了屏幕的所有大小,因此无法避免它们(尝试一下游戏),我只是想要那样在绘制一个敌人和绘制下一个敌人之间有一个最短的延迟时间(例如 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);
}
}
}

Racket 类别:

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 毫秒,这是一个不太合理的时间。我建议
    • 您摆脱了“神奇”数字,而是使用常量,
    • 并将抽动调大一点,例如 12 到 15 毫秒。
    • 最好还是使用 Swing 计时器,或者至少确保在定义的后台线程中执行 while 循环。
  2. 最重要的是,游戏循环的每一次循环都会创造一个新的敌人,这速度太快了。反而:
    • 不要在每次勾选时创建一个新的敌人,
    • 而是节省在 field 中创建最后一个敌人的时间,
    • 检查游戏循环内的增量时间,即当前系统时间 - lastEnemyCreationTime
    • 仅当增量时间大于合理值(常量值或字段(不是魔数(Magic Number)))时才创建新敌人。
    • 创建新敌人时,将 lastEnemyCreationTime 重置为当前系统时间。

不相关的建议:

  • 重写 JPanel 的 paintComponent,而不是 paint 方法,因为这会默认为您提供双缓冲,从而获得更平滑的感知图形。
  • 优先使用按键绑定(bind)而不是 KeyListener,因为这有助于轻松消除使用 KeyListener 所固有的焦点问题。
  • 关于java - 如何使用计时器重新绘制一些 Swing 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37308368/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com