[英]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.