如何在java中缓慢移动子弹?

如何在java中缓慢移动子弹?,java,move,Java,Move,嗨,我正在开发一个游戏,一个战士左右移动并射击。对于射击部分,我尝试使用For循环来降低速度,用户可以看到子弹。但这还不够。我也用睡眠,但不是一个好答案。现在我不知道该怎么办。 这是我的油漆组件: package game; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.KeyEvent; import java.awt.event.KeyLi

嗨,我正在开发一个游戏,一个战士左右移动并射击。对于射击部分,我尝试使用For循环来降低速度,用户可以看到子弹。但这还不够。我也用睡眠,但不是一个好答案。现在我不知道该怎么办。 这是我的油漆组件:

package game;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.JPanel;



public class PaintComponent extends JPanel implements KeyListener {
    int dx = 200-15;
    int dy = 450;
    int my = 450;

    ArrayList<Bullet> bullets = new ArrayList<>();
    public Rectangle2D rec =new Rectangle2D.Double(dx , dy, 30, 10);
    Rectangle2D recB = new Rectangle2D.Double(dx+13 , my, 6, 6);

//    public Polygon pol = new Polygon
    private BufferedImage imageBg, imageFi, imageBu;


    public PaintComponent() {
        this.addKeyListener(this);
        this.setFocusable(true);
        this.setBackground(Color.white);

        try {                
          imageBg = ImageIO.read(new File("C:\\Java\\NetbeansProjects\\Game\\bg.jpg"));
          imageBu = ImageIO.read(new File("C:\\Java\\NetbeansProjects\\Game\\bul.png"));
          imageFi = ImageIO.read(new File("C:\\Java\\NetbeansProjects\\Game\\fi.png"));
       } catch (IOException ex) {
            System.out.println("No background image is available!");
       }
    }

    public void shoot(){
        if(bullets != null){
            for(int i=0; i<bullets.size(); i++){
                for(int j=0; j<200; j++){
                    bullets.get(i).setdy(my-j);
                }
                System.out.println(bullets.get(i).getdy());
            }
        }
    }
    public void moveRec(KeyEvent evt){
        switch(evt.getKeyCode()){
            case KeyEvent.VK_LEFT:
            dx -= 5;
            rec.setRect(dx, dy, 30, 10);
            recB.setRect(dx+13, dy, 6, 6);
            repaint();
            break;
        case KeyEvent.VK_RIGHT:
            dx += 5;
            rec.setRect(dx, dy, 30, 10);
            recB.setRect(dx+13, dy, 6, 6);
            repaint();
            break;
        case KeyEvent.VK_SPACE:
            Bullet b = new Bullet(dx, dy);
            bullets.add(b);
            shoot();
            break;

    }
}

        @Override
        public void paintComponent(Graphics grphcs)
            {super.paintComponent(grphcs);
            Graphics2D gr = (Graphics2D) grphcs;
                int X = (int) rec.getCenterX();
                int Y = (int) rec.getCenterY();
                gr.drawImage(imageBg, 0, 0, null);
                gr.drawImage(imageFi, X-50, Y-75, null);
                gr.setColor(Color.GRAY);
                if(bullets != null){
                    for(int i=0;i<bullets.size();i++){
                   gr.drawImage(imageBu, null, bullets.get(i).getdx(), bullets.get(i).getdy());
                   repaint();
                    }
                }
                gr.draw(recB);
            }

    @Override
    public void keyTyped(KeyEvent e) {
    }
    @Override
    public void keyPressed(KeyEvent e) 
    {moveRec(e);}
    @Override
    public void keyReleased(KeyEvent e) 
    {}
}

在你的游戏循环中,让它每隔这么多次更新子弹。你很可能永远都不想用睡眠来减缓游戏中的某些事情,因为它需要一个新的线程,否则它会使整个游戏处于睡眠状态

如果你不知道什么是游戏循环,游戏循环基本上是一个循环,它不断地接受输入,更新游戏,如子弹,渲染所有内容,然后暂停整个程序,你可以使用睡眠来维持循环所剩余的预期时间。您还需要根据上次更新后经过的滴答声或毫秒数来更新游戏。这将防止游戏在不同的计算机上运行得更快或更慢

我还没读完这本书,但可能会有所帮助

另外,我不确定这是否正确,我认为使用Canvas而不是JPanel会更好地制作游戏。这是我在第一个java游戏中使用的

编辑:

如果您想使用JPanel而不使用游戏循环,您可以让shot方法创建一个新线程,并使用sleep来减慢它的速度。此外,如果发射多个项目符号,则使用“发射方法”设置的方式可能会导致问题,因为它将在两个单独的循环中循环通过每个项目符号;如果使用单独的线程,则可以在一个线程中循环时修改项目符号数组,从而导致错误

试试这个:

public void shoot(Bullet bullet){
      new Thread(new Runnable(){
            for(int j=0; j<200; j++){
                bullet.setdy(my-j);
                try{
                  Thread.sleep(time);//set the time
                catch(Exception e){
                  e.printStackTrace();
                }
            }
            System.out.println(bullet.getdy());
            getBullets().remove(bullet);
        }).start();
    }
创建一个名为getBullets的方法。确保它具有同步修改器

protected synchronized ArrayList<Bullet> getBullets(){
  return bullets;
}
这将确保一次只能由一个线程修改它


最后,在玩家按下空格键的地方,更改bullets.addb;获取bullets.addb

我认为你放慢循环的速度是错误的。你最不想做的事情就是放慢游戏循环的速度或者让游戏循环休眠。这将影响游戏中的所有对象

有多种方法可以做到这一点:

每刻度的较小增量

你能做的最明显的一件事就是减小子弹的增量。让我们看看你的拍摄;方法:

  public void shoot(){
    if(bullets != null){
        for(int i=0; i<bullets.size(); i++){
            for(int j=0; j<200; j++){
                bullets.get(i).setdy(my-j);
            }
            System.out.println(bullets.get(i).getdy());
        }
    }
}
代码现在所做的是,它根据生存时间变量计算速度,子弹的生存时间越长,速度就越小。调整速度变量可以更好地控制子弹。我自己也这么说,拍摄方法看起来更整洁:

public void shoot(){
    if(bullets != null){
        for(int i=0; i<bullets.size(); i++){
            bullets.get(i).Move();
        }
    }
}
当然还有很多,比如检查生活的速度和时间是否超出界限之类的,但我认为你足够聪明,能够弄清楚这一点

用定时器运行它


正如ControlAltDel所说,你可以实现一个定时器,我不是java方面的专家,所以我不会深入讨论这个问题。但这肯定是有可能的。它只不过是在计时器的tick函数中实现当前的shot方法。当然,删除for i最后我在bullet类中添加了一个计时器,并在paintcomponent方法中重新绘制

    package game;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

public class Bullet {
    private int x, y;
    private int speed, ttl;
    public final Timer timer1;

    public Bullet(int x, int y, int speed){

        this.x = x;
        this.y = y;
        this.speed= speed;
        this.ttl = 250;

        ActionListener actListener = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                Move();
            }
        };
        this.timer1 = new Timer(50, actListener);
        timer1.start();
    }

    public int getdy(){
        return y;
    }
    public void setdy(int newy){
        y = newy;
    }
    public int getdx(){
        return x;
    }
    public int Move(){
    //Do some calculation to perform loss of velocity within a reasonable range. Because these number might be overkill
    this.speed -= (ttl / 100);
    y += this.speed;
    ttl--;
    return y;
    }
}

您应该为动画使用javax.swing.Timer请参见:。另外,不要从paintComponent方法调用repaint。@ControlAltDel Thx,但是您能解释一下有关计时器的更多信息吗?我应该如何使用计时器?@camickr Thx,为什么不调用重绘?你是说在我的for循环中吗?!太多了!我不想写专业的东西!所以我决定使用JPanel。链接很有用!你完全忽略了一个事实,那就是问题是关于如何在摇摆中进行的,因此你的答案在这里是完全错误的。在Swing这样的事件驱动系统中,经典的游戏循环是个坏主意。您关于Cancas vs JPanel的信息不完整且不正确,而且它没有解决根本问题。我添加了一个编辑,以便@Ebola知道如何使用JPanel或Canvas。如果他使用你所展示的速度修改器,那么每次他们调用shot方法时,它只会使子弹移动一次。他们需要一种让子弹不断移动的方式。嗨,谢谢!很好,但是有个问题!当我开枪时,第一颗子弹在下一颗子弹发射之前不会移动!你也能帮我吗?!我用了你写的代码!您应该将bullet类引用存储在数组列表中。在主游戏循环中,您应该调用shot函数。这将解决问题。@Syntasu我使用了一个arraylist来存储子弹,但它不起作用!在页面顶部查看我的代码!在paintcomponent类中!我做错了吗?在当前帖子下添加了一个新的更新部分。希望这能回答您的问题:
public void shoot(){
    if(bullets != null){
        for(int i=0; i<bullets.size(); i++){
            bullets.get(i).Move();
        }
    }
}
@Override
public void paintComponent(Graphics grphcs)
{
    super.paintComponent(grphcs);

    Graphics2D gr = (Graphics2D) grphcs;
    int X = (int) rec.getCenterX();
    int Y = (int) rec.getCenterY();
            
    gr.drawImage(imageBg, 0, 0, null);
    gr.drawImage(imageFi, X-50, Y-75, null);
    gr.setColor(Color.GRAY);
            
    if(bullets != null)
    {
        for(int i=0;i<bullets.size();i++)
        {
            //Here is were we loop over the bullet list, lets add the move method
            bullets.get(i).Move();

            gr.drawImage(imageBu, null, bullets.get(i).getdx(), bullets.get(i).getdy());
            repaint();
        }
    }
    
    gr.draw(recB);
}
for(int i=0;i<bullets.size();i++)
{
    Bullet b = bullets.get(i);
    if(b.ttl >= 1)
    {
        bullets.get(i).Move();
        gr.drawImage(imageBu, null, b.getdx(), b.getdy());
    }
    else
    {
        //Remove the bullet from the list
        //In C# its bullets.Remove(b);
    }

    repaint();
}
    package game;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

public class Bullet {
    private int x, y;
    private int speed, ttl;
    public final Timer timer1;

    public Bullet(int x, int y, int speed){

        this.x = x;
        this.y = y;
        this.speed= speed;
        this.ttl = 250;

        ActionListener actListener = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                Move();
            }
        };
        this.timer1 = new Timer(50, actListener);
        timer1.start();
    }

    public int getdy(){
        return y;
    }
    public void setdy(int newy){
        y = newy;
    }
    public int getdx(){
        return x;
    }
    public int Move(){
    //Do some calculation to perform loss of velocity within a reasonable range. Because these number might be overkill
    this.speed -= (ttl / 100);
    y += this.speed;
    ttl--;
    return y;
    }
}