使绘制的对象在JPanel上随机移动

时间:2023-02-04 15:43:12

This is my frog class which is being called by a GUI class.

这是我的青蛙类,由GUI类调用。

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

public class Frog implements Runnable {
    private int x, y, dx, dy;
    private int coordinates[]=new int[2];
    private boolean hungry;
    private JLabel jLabel;
    private ImageIcon image;
    private String name;

    public Frog() {

    }

    public  Frog(String name, boolean hungry) {
        image = new ImageIcon("images/frog.jpeg");
        jLabel = new JLabel(image);
        setName(name);
        setHungry(hungry);
        setCoordinates();
    }

    private void setName(String name) {
        this.name=name;
    }

    public int[] getCoordinates() {
        return coordinates;
    }

    public boolean isHungry() {
        return hungry;
    }

    public void setHungry(boolean hungry) {
        this.hungry = hungry;
    }

    public void display(Graphics paper) {
        paper.setColor(Color.black);
        paper.drawOval(x, y, dx, dx);
    }

    public void setCoordinates() {
        for(int i = 0; i < 2; i++) {
            Random rand = new Random();
            int p = rand.nextInt(100);
            coordinates[i] = p;
        }

        setX(coordinates[0]);
        setY(coordinates[1]);
    }

    public void move() {
        x = (int)Math.random() * 350;
        y = (int)Math.random() * 350;
        dx=20;
        dx=20;
        x += dx;
        y += dy;

        if (x > 800 || x < 0)
            dx=-dx;

        if (y > 600 || y < 0)
             dy=-dy;
    }

    public void setDx(int dx) {
        this.dx = dx;
    }

    public void setDy(int dy) {
        this.dy = dy;
    }

    public void setX(int x){
        this.x = x;
    }

    public void setY(int y){
        this.y = y;
    }

    public void run() {
        while(!hungry) {
            move(); 

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }   
    }
}

I have created this class to move a frog object randomly but when I call the move method nothing is happening. I want the frog on a JPanel to randomly move around the screen. I have another class which uses the frog object.

我创建了这个类来随机移动一个青蛙对象,但是当我调用移动方法时,没有任何事情发生。我希望JPanel上的青蛙在屏幕上随机移动。我有另一个使用青蛙对象的类。

It is used from a main class containing the following:

它用于包含以下内容的主类:

public void actionPerformed(ActionEvent event) {
    if (event.getSource() == MakePet) {
        String petName = namePlace.getText();
        frog = new Frog(petName,false);
        panel.add(pet);
        panel.add(prey);
        frog.move();
        Thread fro = new Thread(frog);
        fro.start();
    }
}

public static void main(String[] args) {
    GUI demo = new GUI();
    demo.setSize(520,720);
    demo.createGUI();
    demo.show();
}

1 个解决方案

#1


1  

For an example of timer based animation, have a look at http://www.java2s.com/Code/Java/2D-Graphics-GUI/Timerbasedanimation.htm

有关基于计时器的动画示例,请查看http://www.java2s.com/Code/Java/2D-Graphics-GUI/Timerbasedanimation.htm

Another example of timer based animation, where Swing components are used to draw images on a JPanel was given Jérôme's comment: Randomly moving images on a JPanel

另一个基于计时器的动画示例,其中使用Swing组件在JPanel上绘制图像Jérôme的评论:在JPanel上随机移动图像

If you require having multiple frogs with their own threads of control, then you will need to handle synchronization. Otherwise I would simply call move from the timer before repainting the panel. And then change move:

如果你需要有多个具有自己控制线程的青蛙,那么你需要处理同步。否则我只需在重新绘制面板之前调用计时器移动。然后改变行动:

public void move() {
    if (!hungry) {
        return;
    }
    ...
}

Set the timer's interval appropriately based on the framerate you are looking to achieve. The below is based on the answer from the question Jérôme linked to:

根据您要实现的帧速率适当设置计时器的间隔。以下内容基于Jérôme与以下问题相关的答案:

Timer t = new Timer(1000 / DESIRED_FRAMERATE, (event) -> {
    frogs.forEach(Frog::move);
    panel.repaint();
});

Note that this is Java 8 using lambdas.

请注意,这是使用lambdas的Java 8。

The above in pre-Java 8:

以上在Java 8之前:

Timer t = new Timer(1000 / DESIRED_FRAMERATE, new ActionListener() {
    public void actionPerformed(ActionEvent event) {
        for (Frog frog : frogs) {
            frog.move();
        }
        panel.repaint();
    }
});

You should create the Timer in the initialization code of your JFrame or JPanel. If you have a class extending JPanel, you don't need to reference panel when calling repaint if the Timer is inside that class. Also, here I am guessing you have a collection of Frog objects, typically a list, called frogs. If there's only ever one frog, you don't need the loop. Frog's display method needs to be called from the JPanel's paint method, so I am guessing you have a class extending JPanel.

您应该在JFrame或JPanel的初始化代码中创建Timer。如果你有一个扩展JPanel的类,如果Timer在该类中,则在调用repaint时不需要引用面板。另外,在这里我猜你有一个Frog对象的集合,通常是一个名为frogs的列表。如果只有一只青蛙,你就不需要循环了。需要从JPanel的paint方法调用Frog的显示方法,所以我猜你有一个扩展JPanel的类。

#1


1  

For an example of timer based animation, have a look at http://www.java2s.com/Code/Java/2D-Graphics-GUI/Timerbasedanimation.htm

有关基于计时器的动画示例,请查看http://www.java2s.com/Code/Java/2D-Graphics-GUI/Timerbasedanimation.htm

Another example of timer based animation, where Swing components are used to draw images on a JPanel was given Jérôme's comment: Randomly moving images on a JPanel

另一个基于计时器的动画示例,其中使用Swing组件在JPanel上绘制图像Jérôme的评论:在JPanel上随机移动图像

If you require having multiple frogs with their own threads of control, then you will need to handle synchronization. Otherwise I would simply call move from the timer before repainting the panel. And then change move:

如果你需要有多个具有自己控制线程的青蛙,那么你需要处理同步。否则我只需在重新绘制面板之前调用计时器移动。然后改变行动:

public void move() {
    if (!hungry) {
        return;
    }
    ...
}

Set the timer's interval appropriately based on the framerate you are looking to achieve. The below is based on the answer from the question Jérôme linked to:

根据您要实现的帧速率适当设置计时器的间隔。以下内容基于Jérôme与以下问题相关的答案:

Timer t = new Timer(1000 / DESIRED_FRAMERATE, (event) -> {
    frogs.forEach(Frog::move);
    panel.repaint();
});

Note that this is Java 8 using lambdas.

请注意,这是使用lambdas的Java 8。

The above in pre-Java 8:

以上在Java 8之前:

Timer t = new Timer(1000 / DESIRED_FRAMERATE, new ActionListener() {
    public void actionPerformed(ActionEvent event) {
        for (Frog frog : frogs) {
            frog.move();
        }
        panel.repaint();
    }
});

You should create the Timer in the initialization code of your JFrame or JPanel. If you have a class extending JPanel, you don't need to reference panel when calling repaint if the Timer is inside that class. Also, here I am guessing you have a collection of Frog objects, typically a list, called frogs. If there's only ever one frog, you don't need the loop. Frog's display method needs to be called from the JPanel's paint method, so I am guessing you have a class extending JPanel.

您应该在JFrame或JPanel的初始化代码中创建Timer。如果你有一个扩展JPanel的类,如果Timer在该类中,则在调用repaint时不需要引用面板。另外,在这里我猜你有一个Frog对象的集合,通常是一个名为frogs的列表。如果只有一只青蛙,你就不需要循环了。需要从JPanel的paint方法调用Frog的显示方法,所以我猜你有一个扩展JPanel的类。