[英]Why does my infinite cause the rest of the program to freeze even though its on a separate thread?
我试图编写一个重力模拟程序。 您指定速度和角度,然后进行数学计算,我使用Java2D实时绘制它。 该程序本身可以工作,我对其进行了测试,它很漂亮。 但是,为了清晰起见,我进行了一些重组,现在遇到了问题。
这是预期的行为:重力物理学都在其自己的类中定义。 此类基本上有一个计时器,该计时器不断更新作为参数的坐标。 我正在另一个名为Sprite的类的run()(线程)方法中创建此类。 调用类(即Sprite)可以使用我在Gravity中定义的称为getX()和getY()的方法来检索这些更新的坐标。 因此,一旦我在Sprite的run()方法中创建了重力对象,我便让Sprite启动了一个调用getX和getY方法的无限对象并更新了自己的x和y坐标。
问题是,即使Gravity对象和infinite在单独的线程上,infinite冻结了重力/更新。 为什么这样做呢?
重力等级:
public class Gravity implements ActionListener { // create me in a run() method
// for a new thread
final double gravAccel = -32.174;
double velocity; // in FPS
double angle; // in degrees
double x; // centralized location of object in feet
double y; // centralized location in feet
double time = 0;
Timer timer;
boolean fired = true;
Point start;
public Gravity(double x, double y, double velocity, double angle, Point start) {
this.x = x;
this.y = y;
this.velocity = velocity;
this.angle = angle;
this.start = start;
initTimer();
}
void initTimer() {
timer = new Timer(10, this);
timer.start();
}
public void fire(double velocity, double angle) {
//timer.start();
x = (velocity * Math.cos(Math.toRadians(angle))) * time + start.getX();
y = 0.5 * gravAccel * Math.pow(time, 2) + (velocity * Math.sin(Math.toRadians(angle))) * time + start.getY();
System.out.println("Time:" + time + " " + x + "," + y);
}
public double getX() {
return x;
}
public double getY() {
return y;
}
@Override
public void actionPerformed(ActionEvent e) {
time = time + 0.01;
if (fired == true) {
fire(velocity, angle);
}
}
}
精灵类:
public class Sprite implements KeyListener, Runnable {
public Dimension hitbox;
double startX = 30;
double startY = 30;
double x = startX; // centralized location of object in feet
double y = startY; // centralized location in feet
Gravity g;
public Sprite() {
hitbox = new Dimension(1, 1);
}
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
int i = e.getKeyCode();
if (i == KeyEvent.VK_SPACE) {
retrieve();
}
}
@Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
public void retrieve() {
for(;;){
x = g.getX();
y = g.getY();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
g = new Gravity(x, y, 50, 70, new Point((int) startX, (int) startY));
}
}
我如何初始化Sprite :
Sprite s = new Sprite();
Thread t = new Thread(s);
t.start();
您的重力与子画面位于同一线程中。
从关键事件中调用您的检索方法,该事件正在等待方法完成。 请勿对此类事情使用无限循环。
精灵更新时应更新重力(每秒x时间,请参阅每秒更新[UPS])。 通常,您一次将拥有一个以上的子画面,并且所有这些子画面必须每秒循环更新几次。
您应该对ui和事件使用单独的线程:在SwingUtilities.invokeLater()处获取战利品
可以创建一个控制器类,该类存储所有Sprite对象并具有一个更新线程,该线程以固定的更新速率运行,并调用每个Sprite的update方法。
编辑:
您目前所拥有的是:
一个线程,其中包含一个对象(精灵),一个对象(重力)作为精灵的属性。 现在,在运行内,您只需创建一个新对象(g),然后胎面结束。
如果您确实要为每个子图创建自己的重力线,则必须这样做。
public Sprite(){
//do what you want to
g = new Gravity(...);
}
public void run(){
while(true){
retrieve();
}
}
使用此方法,在调用Thread.start时,您的sprite方法将开始调用检索。
线程始终具有一个主循环,当您打开该循环时,胎面将停止工作。 在Java中,Runnable的run方法是循环的起点,当线程已准备好run方法时,它将停止工作。 因此,您想要在新线程内执行的所有操作都必须在run方法内。
在包含无限循环的方法retrieve()
设置一个断点,然后在调试器中运行程序。 您会看到您从keyPressed()
内调用retrieve()
,该方法由AWTEventQueue线程上的Swing工具包调用。 您的无限循环位于事件分配线程上,因此无法处理更多事件(包括Swing计时器)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.