我有一个MainThread类,可以作为游戏循环使用。然后在我的面板中,我有这些矩形,它们是音符表的音符和线条(我解析音乐XML文件并根据解析的数据绘制这些),我也解析速度,我希望这些被移动根据节奏。我有一个函数updateX(float x),它更新了对象的x位置。通过线程的开始,我设置一个变量startTime = System.CurrentTimeMillis()然后我计算elapsedTime = System.CurrentTimeMillis() - startTime。那么delta x就是velocity * elapsedTime其中velocity =(一个小节的长度/节拍数)*(60000 millis / tempo)。但问题是,当我用节拍器测试它时,它是不准确的。此外,音符(矩形)往往比线条移动得快一点。这是mainthread:
public class MainThread extends Thread{
public static final int MAX_FPS = 30;
private double averageFPS;
private SurfaceHolder surfaceHolder;
private PlayPanel playPanel;
private boolean running;
public static Canvas canvas;
public MainThread(SurfaceHolder surfaceHolder, PlayPanel playPanel) {
super();
this.surfaceHolder = surfaceHolder;
this.playPanel = playPanel;
}
ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
ScheduledFuture scheduledFuture;
long tick = 0;
int count = 1;
public void start() {
final Runnable runnable = new Runnable() {
@Override
public void run() {
canvas = null;
if (metronomeOn) {
if (tick == 0) {
// System.out.println(TAG + " Running " + tick + " " + 60000/tempo);
if (count % beat == 1) {
sendMidi(0x99, 77, 64);
// System.out.println("TICK");
} else {
sendMidi(0x99, 76, 64);
// System.out.println("TACK");
}
count++;
tick++;
} else if (tick >= 600/tempo - 1) {
tick = 0;
} else {
// System.out.println(TAG + " Running " + tick + " " + 60000/tempo);
tick++;
}
} else if (!metronomeOn) {
tick = 0;
count = 1;
}
try {
canvas = surfaceHolder.lockCanvas();
playPanel.update();
playPanel.draw(canvas);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (canvas != null) {
try {
surfaceHolder.unlockCanvasAndPost(canvas);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
};
scheduledFuture =
scheduler.scheduleAtFixedRate(runnable, 0, 100, TimeUnit.MILLISECONDS);
}
public void cancel() {
scheduledFuture.cancel(true);
}
这是updateX函数:
// updates the x_position of the notes
public void updateX(float x) {
rectangle.set(x, rectangle.top, x+rectangle.width(), rectangle.bottom);
rectangle2.set(x, rectangle2.top, x+rectangle2.width(), rectangle2.bottom);
if (ledger != null) {
ledger.updateX(x);
}
}
// updates the x position of the lines
public void updateX(float x) {
startX = x;
stopX = x;
}
和更新功能:
// updates the notes with the given speed
public void update(float s, long startTime) {
float elapsedTime = (float)(System.currentTimeMillis() - startTime);
//System.out.println(TAG + "elapsed time float: " + elapsedTime + " elapsed time long " + (System.currentTimeMillis() - startTime));
for (Notes n : notes) {
n.decrementX(s * elapsedTime);
}
任何人都知道为什么会发生这种情况或有任何解决方案? 提前谢谢。
要添加,我已经使用countDownTimer实现了节拍器,并且根据节奏准确,所以我想知道我是否可以使用countDownTimer实现游戏循环?!
答案 0 :(得分:0)
Thread.sleep
不够准确,无法达到您的目的。当线程退出睡眠时,可能无法立即执行。从睡眠结束到恢复执行之间的时间是不确定的,例如,取决于系统目前的繁忙程度。
我建议您查看java.util.concurrent.ScheduledExecutorService.scheduleAtFixedRate()
。您可以将其配置为以固定间隔运行更新代码。它可能比你自己的while循环更好地测量时间。
答案 1 :(得分:0)
这是因为你计算距离的“数学”是错误的,你不应该添加一些时间,而只是计算从开始经过的时间。你需要设置确切的位置,删除任何添加或减少位置的代码 - 它需要大量的重构,但会简化你的代码,我不能这样做,因为你没有发布整个代码,它也是很多工作,你可以自己做:)这是一个代码示例,显示了如何以正确的方式做到这一点:
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ExactPositionBasedOnTime {
public static void main(String[] args) {
final long speed = 100; // in pixels per second
final long startTime = System.currentTimeMillis();
Runnable updater = new Runnable() {
@Override
public void run() {
long elapsedTime = System.currentTimeMillis() - startTime;
int xPosition = (int) ((elapsedTime * speed) / 1000);
updateXPosition(xPosition);
}
};
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(updater, 0, 1000 / 30, TimeUnit.MILLISECONDS);
}
private static void updateXPosition(int xPosition) {
// set the position, not add anything, just set it !!!
System.out.println("the xPosition is: " + xPosition);
}
}