java canvas 的增量时间问题
java delta time problems with canvas
你好我正在尝试使用 canvas 和位图制作一个小游戏我希望我的游戏在所有设备上 运行 相同我发现增量时间是最好的做法但出于某种原因当我尝试将它实现到我的代码中时,我遇到了显示问题,例如,我试图在天空中移动我的 coluds,但是当我添加 delta 时,它们都 disapere 我不知道我是否做错了,所以请有人帮助我这是代码
private float c1x = 0.0f;
private float c2x = cloudWidth;
private float c3x = cloudWidth * 2;
private float cloudSpeed = 0.1f;
private long curentTime;
private long lastTime = 0;
private double delta;
@Override
public void run(){
while(running){
if(!holder.getSurface().isValid()){
continue;
}
curentTime = System.nanoTime();
delta = curentTime - lastTime;
lastTime = curentTime;
cloudMovement();
canvas = holder.lockCanvas();
canvas.drawBitmap(bg, 0, 0, null);
canvas.drawBitmap(sun, 20, 20, null);
canvas.drawBitmap(cloud1, c1x, c1y, null);
canvas.drawBitmap(cloud2, c2x, c2y, null);
canvas.drawBitmap(cloud3, c3x, c3y, null);
holder.unlockCanvasAndPost(canvas);
}
}
private void cloudMovement(){
if(c1x <= 0 - cloudWidth){
c1x = w;
c1y = y.nextInt(rand);
}
if(c2x <= 0 - cloudWidth){
c2x = w;
c2y = y.nextInt(rand);
}
if(c3x <= 0 - cloudWidth){
c3x = w;
c3y = y.nextInt(rand);
}
c1x-=cloudSpeed * delta;
c2x-=cloudSpeed * delta;
c3x-=cloudSpeed * delta;
}
您可以改用全局 FPS 机制,这会强制您的游戏保持稳定的 FPS :)
如果您跟踪 FPS,游戏将 运行 在任何设备上都以相同的方式运行,您不需要在所有更新过程中包含增量时间。
这是我在旧项目中使用的 FpsTracker 的代码片段:
private static final long SECOND = 1000;
private static final long TARGET_FPS = 40;
private static final long FRAME_PERIOD = SECOND / TARGET_FPS;
private long time = System.currentTimeMillis();
/**
*
* @param startTime
* @return <code>true</code> if the interval between startTime and the time
* when this method was called is smaller or equal to the given
* frame period.
*
* Will return <code>false</code> if the interval was longer.
*/
public boolean doFpsCheck(long startTime) {
if (System.currentTimeMillis() - time >= SECOND) {
time = System.currentTimeMillis();
}
long sleepTime = FRAME_PERIOD
- (System.currentTimeMillis() - startTime);
if (sleepTime >= 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
//TODO handle this properly
e.printStacktrace()
}
return true;
} else {
return false;
}
}
如果此方法 returns false
这意味着您的操作花费的时间比您给一帧的时间段更长。您可以通过检查 doFpsCheck
return 参数对此做出反应。
在您的代码中实现它如下所示:
@Override
public void run()
{
while(running)
{
if(!holder.getSurface().isValid())
{
continue;
}
startTime = System.currentTimeMillis();
cloudMovement();
canvas = holder.lockCanvas();
canvas.drawBitmap(bg, 0, 0, null);
canvas.drawBitmap(sun, 20, 20, null);
canvas.drawBitmap(cloud1, c1x, c1y, null);
canvas.drawBitmap(cloud2, c2x, c2y, null);
canvas.drawBitmap(cloud3, c3x, c3y, null);
holder.unlockCanvasAndPost(canvas);
doFpsCheck(startTime);
}
}
顺便说一句 - 将游戏循环划分为专业子流程是一种很好的做法,一个是更新流程,另一个是绘制流程。
对于许多不同的位图,您应该考虑将字段和功能提取到单独的 classes 中,其中包含 draw(Canvas c)
和 update()
方法。所以你不会在主 class.
上获得一万亿个字段
你好我正在尝试使用 canvas 和位图制作一个小游戏我希望我的游戏在所有设备上 运行 相同我发现增量时间是最好的做法但出于某种原因当我尝试将它实现到我的代码中时,我遇到了显示问题,例如,我试图在天空中移动我的 coluds,但是当我添加 delta 时,它们都 disapere 我不知道我是否做错了,所以请有人帮助我这是代码
private float c1x = 0.0f;
private float c2x = cloudWidth;
private float c3x = cloudWidth * 2;
private float cloudSpeed = 0.1f;
private long curentTime;
private long lastTime = 0;
private double delta;
@Override
public void run(){
while(running){
if(!holder.getSurface().isValid()){
continue;
}
curentTime = System.nanoTime();
delta = curentTime - lastTime;
lastTime = curentTime;
cloudMovement();
canvas = holder.lockCanvas();
canvas.drawBitmap(bg, 0, 0, null);
canvas.drawBitmap(sun, 20, 20, null);
canvas.drawBitmap(cloud1, c1x, c1y, null);
canvas.drawBitmap(cloud2, c2x, c2y, null);
canvas.drawBitmap(cloud3, c3x, c3y, null);
holder.unlockCanvasAndPost(canvas);
}
}
private void cloudMovement(){
if(c1x <= 0 - cloudWidth){
c1x = w;
c1y = y.nextInt(rand);
}
if(c2x <= 0 - cloudWidth){
c2x = w;
c2y = y.nextInt(rand);
}
if(c3x <= 0 - cloudWidth){
c3x = w;
c3y = y.nextInt(rand);
}
c1x-=cloudSpeed * delta;
c2x-=cloudSpeed * delta;
c3x-=cloudSpeed * delta;
}
您可以改用全局 FPS 机制,这会强制您的游戏保持稳定的 FPS :)
如果您跟踪 FPS,游戏将 运行 在任何设备上都以相同的方式运行,您不需要在所有更新过程中包含增量时间。
这是我在旧项目中使用的 FpsTracker 的代码片段:
private static final long SECOND = 1000;
private static final long TARGET_FPS = 40;
private static final long FRAME_PERIOD = SECOND / TARGET_FPS;
private long time = System.currentTimeMillis();
/**
*
* @param startTime
* @return <code>true</code> if the interval between startTime and the time
* when this method was called is smaller or equal to the given
* frame period.
*
* Will return <code>false</code> if the interval was longer.
*/
public boolean doFpsCheck(long startTime) {
if (System.currentTimeMillis() - time >= SECOND) {
time = System.currentTimeMillis();
}
long sleepTime = FRAME_PERIOD
- (System.currentTimeMillis() - startTime);
if (sleepTime >= 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
//TODO handle this properly
e.printStacktrace()
}
return true;
} else {
return false;
}
}
如果此方法 returns false
这意味着您的操作花费的时间比您给一帧的时间段更长。您可以通过检查 doFpsCheck
return 参数对此做出反应。
在您的代码中实现它如下所示:
@Override
public void run()
{
while(running)
{
if(!holder.getSurface().isValid())
{
continue;
}
startTime = System.currentTimeMillis();
cloudMovement();
canvas = holder.lockCanvas();
canvas.drawBitmap(bg, 0, 0, null);
canvas.drawBitmap(sun, 20, 20, null);
canvas.drawBitmap(cloud1, c1x, c1y, null);
canvas.drawBitmap(cloud2, c2x, c2y, null);
canvas.drawBitmap(cloud3, c3x, c3y, null);
holder.unlockCanvasAndPost(canvas);
doFpsCheck(startTime);
}
}
顺便说一句 - 将游戏循环划分为专业子流程是一种很好的做法,一个是更新流程,另一个是绘制流程。
对于许多不同的位图,您应该考虑将字段和功能提取到单独的 classes 中,其中包含 draw(Canvas c)
和 update()
方法。所以你不会在主 class.