当我创建另一个子弹对象时,如何连续移动这些“子弹”?

3
我刚开始学习Java,最近学习了Timer类。我正在尝试将我学到的东西应用到这个项目中,在这个项目中,一个“太空飞船”会发射“子弹”。我已经让所有的控件都能工作了,但是我在创建另一个子弹对象时,之前的“子弹”会停在中途。我从昨天就一直在搜索,但似乎找不到正确的关键词。我认为我明白为什么会停下来,但是我该如何让子弹继续移动呢?
我在我的JFrame中添加了这个GamePanel类。
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class GamePanel extends JPanel implements KeyListener, ActionListener {

    int panelWidth = 500;
    int panelHeight = 500;
    
    JLabel spaceship;
    int shipWidth = 50;
    int shipHeight = 50;
    int shipX = 0;
    int shipY = panelHeight - shipHeight; // BOTTOM of GamePanel
    int shipXVelocity = 5;
    
    JLabel bullet;
    int bulletWidth = 10;
    int bulletHeight = 25;
    int bulletX;
    int bulletY;
    int bulleyYVelocity = 7;
    
    boolean left,right = false;
    
    Timer timer;
    
    GamePanel() {
        
        timer = new Timer(10,this);
        timer.start();
        
        this.setPreferredSize(new Dimension(panelWidth,panelHeight));
        this.setLayout(null);
        this.setBackground(Color.black);
        this.setFocusable(true);
        this.addKeyListener(this);
        
        spaceship = new JLabel();
        spaceship.setBounds(shipX, shipY, shipWidth, shipHeight);
        spaceship.setBackground(Color.green);
        spaceship.setOpaque(true);
        
        this.add(spaceship);
        
    }

    void shoot() {
        
        bulletX = shipX + (shipWidth / 2) - (bulletWidth / 2); // CENTER-TOP of spaceship
        bulletY = shipY;
        
        bullet = new JLabel();
        bullet.setBounds(bulletX, bulletY, bulletWidth, bulletHeight);
        bullet.setBackground(Color.white);
        bullet.setOpaque(true);

        this.add(bullet);
        
    }
    
    @Override
    public void keyTyped(KeyEvent e) {
        
        switch(e.getKeyChar()) {
        case 'a' : left = true;
        break;
        case 'd' : right = true;
        break;
        }
        
    }

    @Override
    public void keyPressed(KeyEvent e) {
        
        switch(e.getKeyCode()) {
        case 10 : shoot();
        break;
        }
        
    }

    @Override
    public void keyReleased(KeyEvent e) {
        
        switch(e.getKeyChar()) {
        case 'a' : left = false;
        break;
        case 'd' : right = false;
        break;
        }
        
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        
        if(left == true && shipX > 0) shipX -= shipXVelocity;
        if(right == true && shipX < panelWidth - shipWidth) shipX += shipXVelocity;
        spaceship.setLocation(shipX, shipY);
        
        if(bullet != null) { // Move if a bullet exist
            bulletY -= bulleyYVelocity;
            bullet.setLocation(bulletX, bulletY);
        }
        
        if(bulletY < 0) this.remove(bullet);;
        
    }
    
}

输出:

当我射出另一颗子弹时,子弹停止运动


你需要进行多线程处理。 - seenukarthi
我目前还不知道那是什么,但我会去了解。 - Robomike
1
@KarthikeyanVaithilingam:那是完全错误的。对于大多数早期游戏开发,您希望所有处理都在一个专用线程上进行(例如使用单个计时器)。当单个 CPU 核心无法处理每个时钟周期内的所有对象更新时,才需要实际的多线程。 - Joachim Sauer
1个回答

2
有两种可能的解决方案:
  1. 多线程: 对于每个子弹,打开一个新的计时器,仅为该子弹工作,直到子弹停止,例如当它击中某物。
  2. 为所有子弹创建列表: 创建一个子弹列表,每次发射新子弹时将其添加到列表中,而不覆盖以前的子弹。 然后,在您的actionPerformed方法中,通过循环运行整个列表,更新其中的每个子弹,并从列表中删除应该消失的子弹。
我认为第二种解决方案更适合你的游戏,因为它的对象移动没有太多计算。

2
在这里,我认为选项#2实际上是更干净的解决方案。即使使用多个线程来更新游戏世界,也几乎不会有专用线程针对每个游戏对象(更像是一些对象组的一个线程)。 - Joachim Sauer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接