我正在尝试使用线程在applet中移动一个球,但它没有移动。任何人都可以帮助我作为applet的新手并继续游戏开发......这里的参考是我的代码
public class ballGame extends JApplet implements Runnable
{
int x_pos=50;
int y_pos=100;
int rad=10;
Thread t;
public void start()
{
super.start();
t=new Thread("t");
t.start();
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.red);
setBackground(Color.BLACK);
g.drawOval(x_pos,y_pos,2*rad,2*rad);
while(true)
{
x_pos++;
//validate();
repaint();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}//end of while
}//end of paint()
}
答案 0 :(得分:2)
在paint
中有一个无限循环意味着该方法不能完成一次传递。
此外,您不应该在Thread.sleep(100)
方法中致电paint
。这会阻止EDT
并降低性能。
而是使用Swing Timer进行更新和重新绘制工作。我也会对JComponent
进行细分,并覆盖paintComponent
。
答案 1 :(得分:2)
Swing是一个单线程环境。也就是说,所有更新和交互都在单个线程中执行。 Swing也 NOT 线程安全。这意味着UI 必须的所有更新都将在该线程的上下文(事件调度线程或ETD)中执行。
阻止EDT的任何代码都会阻止它(重要的是)重新绘制UI并响应用户的输入。
你的绘画代码永远不会更新屏幕,实际上它会使你的应用程序看起来“挂起”,因为paint
方法不允许完成并阻止ETD。
paint
方法在被调用后会快速返回,并且可以快速连续调用,这是一个例外。
一般来说,Thread
可能有点过度杀戮,在这种情况下,像javax.swing.Timer
这样的东西会更合适。
public class AnimatedBoat {
public static void main(String[] args) {
new AnimatedBoat();
}
public AnimatedBoat() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new AnimationPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class AnimationPane extends JPanel {
private BufferedImage boat;
private int xPos = 0;
private int direction = 1;
public AnimationPane() {
try {
boat = ImageIO.read(new File("boat.png"));
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
xPos += direction;
if (xPos + boat.getWidth() > getWidth()) {
xPos = getWidth() - boat.getWidth();
direction *= -1;
} else if (xPos < 0) {
xPos = 0;
direction *= -1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int y = getHeight() - boat.getHeight();
g.drawImage(boat, xPos, y, this);
}
}
}
作为旁注。您应该很少需要覆盖paint
或JApplet
等顶级容器的JFrame
方法,而有很多很好的理由,那就是你要去的那个最感兴趣的是它们不是双缓冲的,这意味着当屏幕更新时你可能会看到闪烁。
最好使用JPanel
之类的内容,而不是覆盖它的paintComponent
方法。
看看
了解更多信息
nb的
虽然我在我的例子中使用了JFrame
,但将动画面板放入JApplet
这是一件简单的事情,这是你不需要/想要的另一个原因从顶级容器扩展;)
答案 2 :(得分:1)
你不能在paint()中调用repaint()方法。并且你无法在paint()方法中无限循环组织 - 这样做,你就是在applet中阻止绘图。
答案 3 :(得分:0)
在Runnable的run方法中使用while循环。
<强>更新强>
在start方法中有这个。
t=new Thread(this);
t.start();
答案 4 :(得分:0)
x_pos
是一个int值,因此它按值传递给方法,而不是通过引用传递给方法。这就是为什么当你改变它的值时,你圈子里面的值不会更新......
答案 5 :(得分:0)
您创建一个没有run()
方法的线程。这个方法应该包含可运行的代码......此外,paint()
方法是绘制内容,而不是更新内容!
所以将while循环从paint()
方法移动到线程的run()
方法中:
t=new Thread("t") {
@Override
public void run()
{
while(true)
{
x_pos++;
//validate();
repaint();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}//end of while
}
};
请注意,ballGame
不需要implement Runnable
部分。由于您创建的主题将提供它。