我正在尝试编写一个小重力模拟程序。你指定一个速度和角度,然后它做数学,我用Java2D实时绘制它。程序本身有效,我测试了它,它很漂亮。但是,出于清晰的目的,我做了一些重组,现在我遇到了问题。
这是预期的行为:重力物理都是在自己的类中定义的。这个类基本上有一个定时器,它不断更新作为参数的坐标。我在另一个名为Sprite的类的run()(线程)方法中创建了这个类。调用类(是Sprite)可以使用我在Gravity中定义的名为getX()和getY()的方法来检索这些更新的坐标。所以,一旦我在Sprite的run()方法中创建了引力对象,我就会让Sprite启动一个无限的调用getX& getY方法并更新自己的x& y coords。
问题是,即使Gravity对象和无限对象在单独的线程上,无限正在冻结重力/更新。它为什么这样做?
重力等级:
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 s = new Sprite();
Thread t = new Thread(s);
t.start();
答案 0 :(得分:1)
你的引力与你的精灵在同一个线程中。
从一个键事件调用您的retrievev方法,该事件正在等待方法完成。不要使用无限循环来做这些事情。
更新精灵时应更新重力(每秒x次,请参阅每秒更新次数[UPS])。通常,您将同时拥有多个精灵,并且所有精灵都必须每秒更新几次。
你应该为ui和事件使用一个单独的线程: 抢劫SwingUtilities.invokeLater()
创建一个控制器类会更好,它会存储所有的精灵对象,并且有一个更新线程,它以固定的更新速率运行并调用每个精灵的更新方法。
修改强>
目前你所拥有的是:
一个线程,其中包含一个对象(精灵),一个对象(重力)作为精灵的属性。现在在运行中你只需创建一个新对象(g),然后踏板就会结束。
如果你真的希望每个精灵都有一个自己的重力线程,那么你就可以做这样的事情了。
public Sprite(){
//do what you want to
g = new Gravity(...);
}
public void run(){
while(true){
retrieve();
}
}
使用它,在调用Thread.start时,你的sprite方法将开始调用retrieve。
线程总是有一个主循环,当你循环时,踏板停止工作。在java中,Runnable的run方法是循环的起点,当一个线程准备好run方法时,它停止工作。所以你想在新线程中做的只是在run方法中。
答案 1 :(得分:0)
在方法retrieve()
中设置一个包含无限循环的断点,并在调试器中运行程序。您将看到从retrieve()
内调用keyPressed()
,这是由AWTEventQueue线程上的Swing工具包调用的。您的无限循环位于事件派发线程上,因此无法处理更多事件(包括Swing计时器)。