【问题标题】:Java Space Invader bullet movementJava Space Invader 子弹运动
【发布时间】:2013-03-12 01:03:40
【问题描述】:

我正在尝试编写一个 Space Invader 游戏,以提高我在 AP 计算机科学中学到的技能。我遇到了一个问题。当我按下空格键(发射按钮)时,子弹移动到顶部的动画不可见。相反,子弹只是出现在您开火的屏幕顶部。这是包含子弹发射的代码:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;

public class AlienInvader extends JPanel implements KeyListener, ActionListener {

    Constants constant = new Constants();
    Timer timer = new Timer(5, this);
    Sprite images = new Sprite();

    public void update() {
        timer.start();
        images.loadImage();
        addKeyListener(this);
        setFocusable(true);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, 500, 500);
        g.drawImage(images.spaceship, constant.x, constant.y, null);
        g.drawImage(images.bullet, constant.bulletx, constant.bullety, null);
    }

    @Override
    public void keyPressed(KeyEvent e) {
        System.out.println(constant.x);
        switch (e.getKeyCode()) {
        case KeyEvent.VK_LEFT:
            constant.xvel = -1 * constant.STEP;
            repaint();
            break;
        case KeyEvent.VK_RIGHT:
            constant.xvel = 1 * constant.STEP;
            repaint();
            break;
        case KeyEvent.VK_SPACE:
            constant.xvel = 0;
            constant.bulletx = constant.x;
            constant.bullety = constant.y;
            while (constant.bullety > 0) {
                constant.bullety = constant.bullety - 1;
                repaint();
            }
        }
        constant.x += constant.xvel;
    }

    @Override
    public void keyReleased(KeyEvent e) {
        switch (e.getKeyCode()) {
        case KeyEvent.VK_LEFT:
            constant.xvel = -1;
            break;
        case KeyEvent.VK_RIGHT:
            constant.xvel = 1;
            break;
        }
    }

    @Override
    public void keyTyped(KeyEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        // TODO Auto-generated method stub

    }

}

我将如何做到这一点,以便用户可以看到子弹在你开火时在屏幕上移动?

【问题讨论】:

    标签: java swing animation user-interface jpanel


    【解决方案1】:

    你遇到了“阻塞事件调度线程”的问题,这似乎是一个很常见的问题......

    基本上在这段代码执行的时候......

    while (constant.bullety > 0) {
        constant.bullety = constant.bullety - 1;
        repaint();
    }
    

    无法绘制任何内容,因为您阻塞了负责处理重绘的线程。

    repaint 是向重绘管理器发出的更新屏幕上一部分的请求。重绘管理器是为提高性能而设计的,因此它会尝试将所有各种重绘请求合并到尽可能少的调用中,然后将重绘请求添加到事件调度线程......

    因此,当您阻止 EDT 时,无法重新绘制任何内容。

    查看Concurrency in SwingPainting in AWT and Swing 了解更多详情。

    现在,来一个解决方案。

    有很多方法可以实现这一点。一般来说,您需要某种“引擎”或“控制器”来运行后台,更新游戏中的各种对象并将结果渲染到屏幕上。

    这带来了许多重大问题。首先,与 UI 的所有交互都必须在 EDT 的上下文中执行。这意味着,您永远不应从 EDT 外部创建或更新任何 UI 组件。

    第二个是确保您不会改变渲染器所依赖的游戏模型的任何部分(因为您实际上并不控制重绘过程)。

    这个最简单的解决方案是使用BufferedImage,您可以将其绘制到它上面(在背景Thread 中)。

    这将允许您更新游戏模型,将结果渲染到后备缓冲区,将该缓冲区重新同步到 UI,然后稍作等待以让 UI 有时间赶上。简单:D

    【讨论】:

    • 您是说我需要使用 BufferedImage 才能将图像添加到控制台吗?我已经这样做了。这是代码: import java.awt.image.BufferedImage;导入java.io.File;导入 java.io.IOException;导入 javax.imageio.ImageIO;公共类 Sprite { BufferedImage 飞船,子弹; public void loadImage() { try { spaceship = ImageIO.read(new File("spaceship.png")); bullet = ImageIO.read(new File("bullet.png")); } catch (IOException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } }
    • 不,我是说你需要至少使用两个BufferedImages 来渲染你的整个游戏状态。一个将用于渲染到屏幕(通过paint 方法之一),另一个将由游戏线程引擎用于更新世界上所有对象的状态。然后,您将交换引用,这意味着当您更新游戏状态时,Swing 绘制的任何内容都不会过早渲染。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多