为什么我的无限导致程序的其余部分冻结,即使它在一个单独的线程上?
Why does my infinite cause the rest of the program to freeze even though its on a separate thread?
我正在尝试编写一个重力模拟程序。您指定一个速度和角度,然后它进行数学运算,我使用 Java2D 实时绘制它。该程序本身有效,我对其进行了测试,它很漂亮。但是,为了清楚起见,我做了一些重组,但现在我遇到了问题。
这里是预期的行为:重力物理都是在它自己的 class 中定义的。这个 class 基本上有一个计时器,它不断更新作为参数的坐标。我正在另一个名为 Sprite 的 class 的 运行()(线程)方法中创建此 class。调用 class(作为 Sprite)可以使用我在 Gravity 中定义的称为 getX() 和 getY() 的方法检索这些更新的坐标。因此,一旦我在 Sprite 的 运行() 方法中创建了重力对象,我就让 Sprite 开始无限调用 getX 和 getY 方法并更新它自己的 x 和 y 坐标。
问题是,即使 Gravity 对象和 infinite 在不同的线程上,infinite 正在冻结 gravity/updating。为什么要这样做?
重力Class:
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);
}
}
}
雪碧Class:
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();
在您的方法 retrieve()
中设置一个断点,其中包含无限循环和 运行 您在调试器中的程序。您会看到您从 keyPressed()
中调用了 retrieve()
,这是由 Swing 工具包在 AWTEventQueue 线程上调用的。您的无限循环在事件调度线程上,因此无法处理更多事件(包括 Swing 计时器)。
你的重力和你的精灵在同一个线程中。
您的检索方法是从一个键事件调用的,该事件正在等待该方法完成。不要对这样的事情使用无限循环。
重力应该在精灵更新时更新(每秒 x 次,参见每秒更新 [UPS])。通常你一次会有不止一个精灵,所有的精灵都必须在一个循环中每秒更新几次。
您应该为 ui 和事件使用单独的线程:
在 SwingUtilities.invokeLater()
抢劫
最好创建一个控制器class,它存储所有精灵对象并有一个更新线程,运行以固定的更新速率运行并调用每个精灵的更新方法。
编辑:
您目前拥有的是:
一个线程,里面有一个对象(精灵),一个对象(重力)作为精灵的属性。现在在 运行 中,您只需创建一个新对象 (g),然后胎面就结束了。
如果你真的想让每个精灵都有自己的重力线,你必须这样做。
public Sprite(){
//do what you want to
g = new Gravity(...);
}
public void run(){
while(true){
retrieve();
}
}
使用此方法,在调用 Thread.start 时您的 sprite 方法将开始调用 retrieve。
线程总是有一个主循环,当你取消循环时,线程停止工作。在 java 中,Runnable 的 运行 方法是循环的起点,当线程准备好使用 运行 方法时,它将停止工作。所以你想在新线程中做的所有事情都必须在 运行 方法中。
我正在尝试编写一个重力模拟程序。您指定一个速度和角度,然后它进行数学运算,我使用 Java2D 实时绘制它。该程序本身有效,我对其进行了测试,它很漂亮。但是,为了清楚起见,我做了一些重组,但现在我遇到了问题。
这里是预期的行为:重力物理都是在它自己的 class 中定义的。这个 class 基本上有一个计时器,它不断更新作为参数的坐标。我正在另一个名为 Sprite 的 class 的 运行()(线程)方法中创建此 class。调用 class(作为 Sprite)可以使用我在 Gravity 中定义的称为 getX() 和 getY() 的方法检索这些更新的坐标。因此,一旦我在 Sprite 的 运行() 方法中创建了重力对象,我就让 Sprite 开始无限调用 getX 和 getY 方法并更新它自己的 x 和 y 坐标。
问题是,即使 Gravity 对象和 infinite 在不同的线程上,infinite 正在冻结 gravity/updating。为什么要这样做?
重力Class:
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);
}
}
}
雪碧Class:
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();
在您的方法 retrieve()
中设置一个断点,其中包含无限循环和 运行 您在调试器中的程序。您会看到您从 keyPressed()
中调用了 retrieve()
,这是由 Swing 工具包在 AWTEventQueue 线程上调用的。您的无限循环在事件调度线程上,因此无法处理更多事件(包括 Swing 计时器)。
你的重力和你的精灵在同一个线程中。
您的检索方法是从一个键事件调用的,该事件正在等待该方法完成。不要对这样的事情使用无限循环。
重力应该在精灵更新时更新(每秒 x 次,参见每秒更新 [UPS])。通常你一次会有不止一个精灵,所有的精灵都必须在一个循环中每秒更新几次。
您应该为 ui 和事件使用单独的线程: 在 SwingUtilities.invokeLater()
抢劫最好创建一个控制器class,它存储所有精灵对象并有一个更新线程,运行以固定的更新速率运行并调用每个精灵的更新方法。
编辑:
您目前拥有的是:
一个线程,里面有一个对象(精灵),一个对象(重力)作为精灵的属性。现在在 运行 中,您只需创建一个新对象 (g),然后胎面就结束了。
如果你真的想让每个精灵都有自己的重力线,你必须这样做。
public Sprite(){
//do what you want to
g = new Gravity(...);
}
public void run(){
while(true){
retrieve();
}
}
使用此方法,在调用 Thread.start 时您的 sprite 方法将开始调用 retrieve。
线程总是有一个主循环,当你取消循环时,线程停止工作。在 java 中,Runnable 的 运行 方法是循环的起点,当线程准备好使用 运行 方法时,它将停止工作。所以你想在新线程中做的所有事情都必须在 运行 方法中。