gpt4 book ai didi

java - 乒乓 Racket 不停地晃动,不停留在一个位置上

转载 作者:行者123 更新时间:2023-12-01 13:46:05 24 4
gpt4 key购买 nike

请看一下我的 pong 游戏的以下结构。

gameLoop();方法

   //Only run this in another Thread!
private void gameLoop()
{
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();

//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;

//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime / 1000000000);

while (running)
{
double now = System.nanoTime();
int updateCount = 0;

if (!paused)
{

//Do as many game updates as we need to, potentially playing catchup.
while( now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER )
{
updateGame();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}



//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if ( now - lastUpdateTime > TIME_BETWEEN_UPDATES)
{

lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}


//Render. To do so, we need to calculate interpolation for a smooth render.
float interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime) / TIME_BETWEEN_UPDATES) );

//float interpolation = 1.0f;

drawGame(interpolation);
lastRenderTime = now;

//Yield until it has been at least the target time between renders. This saves the CPU from hogging.
while ( now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES)
{
Thread.yield();

//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
try {Thread.sleep(1);} catch(Exception e) {}

now = System.nanoTime();
}


}
}
}

updateGame();方法

  if(p1_up){


if(player.equals("p1")){
p1.moveUp();
}
else
{

p2.moveUp();

}


}
else if(p1_down){


if(player.equals("p1")){

p1.moveDown();

}
else
{

p2.moveDown();

}


}

向上移动();向下移动();桨法

  public void moveUp(){

last_y = y;
last_x = x;

y -= 50.0;


}




public void moveDown(){

last_y = y;
last_x = x;

y += 50.0;


}

drawGame(插值);方法

      public void paintComponent(Graphics g)
{

super.paintComponent(g);

for(int i=0;i<balls.size();i++){

paintBall(g, balls.get(i));

}

drawPaddle(g, p1);
drawPaddle(g, p2);




}





public void drawPaddle(Graphics g, Paddle p){


paddle_drawX = (int)((p.x - p.last_x)*interpolation + p.last_x);
paddle_drawY = (int)((p.y - p.last_y)*interpolation + p.last_y);



g.drawRect(paddle_drawX, paddle_drawY, 10, 50);


}

我是游戏编程的初学者,所以我对游戏循环不太了解。我在互联网上找到了上述固定时间步长的游戏循环,并将其用作我的游戏的游戏循环。环使球平稳移动,但 Racket 在移动时不会停留在一处。当我按下一个按键来移动桨时,桨会不断晃动不在一处停留。桨的 y 坐标不断变化,就像

33、45、20、59、34、59、34、59、33、59、34、58

我知道问题出在插值上,因为它不断变化的值会改变渲染中桨的 y 坐标。我已经思考这个问题有一段时间了,但我不知道如何使游戏循环适用于任何 Action ,所以我来这里寻求帮助。我感谢任何建议/帮助!

这是我完整的桨类(class)。

   public class Paddle
{

float x;
float y;
float last_y;
float last_x;

public Paddle(int x, int y)
{

this.x = x;
this.y = y;
this.last_x = x;
this.last_y = y;

}


public void setNewX(int d){


last_y = y;
last_x = x;

x = d;


}


public void setNewY(int d){

last_y = y;
last_x = x;

y = d;


}

public void moveUp(){

last_y = y;
last_x = x;

y -= 50.0;


}




public void moveDown(){

last_y = y;
last_x = x;

y += 50.0;


}



}

我通过全局变量在主类中启动桨位置。

public Paddle p1 = new Paddle(10, 10);
public Paddle p2 = new Paddle(950, 10);

我有以下事件监听器来处理击键。

  Action handle_up_action = new AbstractAction(){

public void actionPerformed(ActionEvent e){

p1_up = true;


}

};



Action handle_up_action_released = new AbstractAction(){

public void actionPerformed(ActionEvent e){

p1_up = false;
}

};


Action handle_down_action = new AbstractAction(){

public void actionPerformed(ActionEvent e){

p1_down = true;


}

};



Action handle_down_action_released = new AbstractAction(){

public void actionPerformed(ActionEvent e){

p1_down = false;

}

};

最佳答案

您想通过 interpolation 实现什么目标?根据我的理解,它代表上一个和下一个“更新时间”之间耗时百分比。因此它应该每 33.3 毫秒从 0 连续进展到 1。

不知道你怎么用这个interpolation paintBall 中的变量方法,但对于桨,它会将你的桨绘制在 p.x;p.y 之间的“伪随机位置”和p.last_x;p.last_y (取决于两者之间的时间updateGame())。

为了纠正这个问题,从循环逻辑中,您应该了解每个游戏实体(球、桨等)必须有两种状态(位置):- 逻辑状态,仅在每次 TIME_BETWEEN_UPDATES 时更新- 视觉状态,可以在每次渲染时随时更新。

这就像您有一组点(代表逻辑状态)并且您想要在这些点(代表视觉状态)之间的任意位置进行插值。你的代码就像 this .

第一个解决方案

纠正桨抖动的最简单方法是避免插值和使用:

public void drawPaddle(Graphics g, Paddle p){
paddle_drawX = (int)p.x;
paddle_drawY = (int)p.y;
g.drawRect(paddle_drawX, paddle_drawY, 10, 50);
}

但是你的 Action 看起来像 this (视觉位置只会改变每个 TIME_BETWEEN_UPDATES )

第二种解决方案

您想要p.x;p.y作为逻辑位置,但视觉位置应插入 p.last_x;p.last_y 之间以及逻辑位置(如果渲染是在输入处理和下一个 updateGame() 之间完成的):您必须重置 p.last_x;p.last_yupdateGame()叫做。要实现此目的,请在 updateGame() 内调用桨的 updateMovement() 方法.

public void updateMovement(){
last_y = y;
last_x = x;
}

您可以有其他解决方案,例如使用速度变量或移动函数,以获得平滑的移动、加速度等。它主要是第二种解决方案的推广。它需要更大的改变,但更灵活、更强大。为了实现这一点,您可能需要在桨中存储最后的“更新位置”以及所有与运动相关的变量,例如运动开始日期。添加一个方法来检索可以使用两次更新之间的任何日期调用的“视觉位置”,以及一个更新“逻辑位置”的方法,调用每个 updateGame() .

关于java - 乒乓 Racket 不停地晃动,不停留在一个位置上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20365539/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com