为什么在java应用程序上移动鼠标时运行更平稳?包括视频
我正在使用“固定时间步”部分的教程 这是密码-为什么在java应用程序上移动鼠标时运行更平稳?包括视频,java,swing,animation,mouseover,java-2d,Java,Swing,Animation,Mouseover,Java 2d,我正在使用“固定时间步”部分的教程 这是密码- import javax.swing.*; 导入java.awt.*; 导入java.awt.event.*; 公共类GameLoopTest扩展JFrame实现ActionListener { private GamePanel GamePanel=新建GamePanel(); 私有JButton startButton=新JButton(“开始”); 私有JButton quitButton=新JButton(“退出”); 私有JButton
import javax.swing.*;
导入java.awt.*;
导入java.awt.event.*;
公共类GameLoopTest扩展JFrame实现ActionListener
{
private GamePanel GamePanel=新建GamePanel();
私有JButton startButton=新JButton(“开始”);
私有JButton quitButton=新JButton(“退出”);
私有JButton pauseButton=新JButton(“暂停”);
私有布尔运行=false;
private=false;
私人整数fps=60;
私有整数帧计数=0;
公共游戏测试()
{
超级(“固定时间步游戏循环测试”);
容器cp=getContentPane();
cp.setLayout(新的BorderLayout());
JPanel p=新的JPanel();
p、 setLayout(新网格布局(1,2));
p、 添加(开始按钮);
p、 添加(暂停按钮);
p、 添加(退出按钮);
cp.add(gamePanel,BorderLayout.CENTER);
cp.add(p,南部边界布局);
设置大小(500500);
addActionListener(这个);
quitButton.addActionListener(此);
pauseButton.addActionListener(这个);
}
公共静态void main(字符串[]args)
{
GameLoopTest glt=新GameLoopTest();
glt.setVisible(真);
}
已执行的公共无效操作(操作事件e)
{
对象s=e.getSource();
如果(s==开始按钮)
{
跑步=!跑步;
如果(正在运行)
{
startButton.setText(“停止”);
runGameLoop();
}
其他的
{
setText(“开始”);
}
}
如果(s==暂停按钮),则为else
{
暂停=!暂停;
如果(暂停)
{
pauseButton.setText(“取消暂停”);
}
其他的
{
pauseButton.setText(“暂停”);
}
}
如果(s==退出按钮),则为else
{
系统出口(0);
}
}
//启动一个新线程并在其中运行游戏循环。
public void runGameLoop()
{
线程循环=新线程()
{
公开募捐
{
gameLoop();
}
};
loop.start();
}
//只在另一个线程中运行这个!
私有void gameLoop()
{
//该值可能存储在其他位置。
最后一场双人赛,赫兹=30.0;
//计算我们的目标游戏赫兹每帧需要多少纳秒。
两次更新之间的最终双倍时间=100000000/游戏赫兹;
//在新的渲染之前,我们最多会更新游戏很多次。
//如果您担心的是视觉障碍而不是完美的时机,请将此设置为1。
最终int MAX_在_RENDER=5之前更新_;
//我们需要最后的更新时间。
double lastUpdateTime=System.nanoTime();
//存储上次渲染的时间。
double lastRenderTime=System.nanoTime();
//如果我们能够获得如此高的FPS,请不要再次渲染。
最终双目标_FPS=60;
两次渲染之间的最终双目标时间=100000000/目标每秒;
//寻找FPS的简单方法。
int lastSecondTime=(int)(lastUpdateTime/100000000);
(跑步时)
{
double now=System.nanoTime();
int updateCount=0;
如果(!暂停)
{
//尽可能多地更新游戏,尽可能地赶上进度。
while(现在-lastUpdateTime>两次更新之间的时间&&updateCount两次更新之间的时间)
{
lastUpdateTime=now—两次更新之间的时间;
}
//为此,我们需要计算平滑渲染的插值。
浮点插值=Math.min(1.0f,(float)((now-lastUpdateTime)/两次更新之间的时间);
抽签游戏(插值);
lastRenderTime=现在;
//更新我们得到的帧。
int thissond=(int)(lastUpdateTime/100000000);
如果(thisSecond>lastSecondTime)
{
System.out.println(“新秒数”+此秒数+“”+帧数);
fps=帧数;
帧数=0;
lastSecondTime=此秒;
}
//在至少达到两次渲染之间的目标时间之前,都可以进行调整。这样可以避免占用CPU。
while(now-lastRenderTimeimport javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GameLoopTest extends JFrame implements ActionListener
{
private GamePanel gamePanel = new GamePanel();
private JButton startButton = new JButton("Start");
private JButton quitButton = new JButton("Quit");
private JButton pauseButton = new JButton("Pause");
private boolean running = false;
private boolean paused = false;
private int fps = 60;
private int frameCount = 0;
public GameLoopTest()
{
super("Fixed Timestep Game Loop Test");
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new GridLayout(1,2));
p.add(startButton);
p.add(pauseButton);
p.add(quitButton);
cp.add(gamePanel, BorderLayout.CENTER);
cp.add(p, BorderLayout.SOUTH);
setSize(500, 500);
startButton.addActionListener(this);
quitButton.addActionListener(this);
pauseButton.addActionListener(this);
}
public static void main(String[] args)
{
GameLoopTest glt = new GameLoopTest();
glt.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
Object s = e.getSource();
if (s == startButton)
{
running = !running;
if (running)
{
startButton.setText("Stop");
runGameLoop();
}
else
{
startButton.setText("Start");
}
}
else if (s == pauseButton)
{
paused = !paused;
if (paused)
{
pauseButton.setText("Unpause");
}
else
{
pauseButton.setText("Pause");
}
}
else if (s == quitButton)
{
System.exit(0);
}
}
//Starts a new thread and runs the game loop in it.
public void runGameLoop()
{
Thread loop = new Thread()
{
public void run()
{
gameLoop();
}
};
loop.start();
}
//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) );
drawGame(interpolation);
lastRenderTime = now;
//Update the frames we got.
int thisSecond = (int) (lastUpdateTime / 1000000000);
if (thisSecond > lastSecondTime)
{
System.out.println("NEW SECOND " + thisSecond + " " + frameCount);
fps = frameCount;
frameCount = 0;
lastSecondTime = thisSecond;
}
//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();
}
}
}
}
private void updateGame()
{
gamePanel.update();
}
private void drawGame(float interpolation)
{
gamePanel.setInterpolation(interpolation);
gamePanel.repaint();
}
private class GamePanel extends JPanel
{
float interpolation;
float ballX, ballY, lastBallX, lastBallY;
int ballWidth, ballHeight;
float ballXVel, ballYVel;
float ballSpeed;
int lastDrawX, lastDrawY;
public GamePanel()
{
ballX = lastBallX = 100;
ballY = lastBallY = 100;
ballWidth = 25;
ballHeight = 25;
ballSpeed = 25;
ballXVel = (float) Math.random() * ballSpeed*2 - ballSpeed;
ballYVel = (float) Math.random() * ballSpeed*2 - ballSpeed;
}
public void setInterpolation(float interp)
{
interpolation = interp;
}
public void update()
{
lastBallX = ballX;
lastBallY = ballY;
ballX += ballXVel;
ballY += ballYVel;
if (ballX + ballWidth/2 >= getWidth())
{
ballXVel *= -1;
ballX = getWidth() - ballWidth/2;
ballYVel = (float) Math.random() * ballSpeed*2 - ballSpeed;
}
else if (ballX - ballWidth/2 <= 0)
{
ballXVel *= -1;
ballX = ballWidth/2;
}
if (ballY + ballHeight/2 >= getHeight())
{
ballYVel *= -1;
ballY = getHeight() - ballHeight/2;
ballXVel = (float) Math.random() * ballSpeed*2 - ballSpeed;
}
else if (ballY - ballHeight/2 <= 0)
{
ballYVel *= -1;
ballY = ballHeight/2;
}
}
public void paintComponent(Graphics g)
{
//BS way of clearing out the old rectangle to save CPU.
g.setColor(getBackground());
g.fillRect(lastDrawX-1, lastDrawY-1, ballWidth+2, ballHeight+2);
g.fillRect(5, 0, 75, 30);
g.setColor(Color.RED);
int drawX = (int) ((ballX - lastBallX) * interpolation + lastBallX - ballWidth/2);
int drawY = (int) ((ballY - lastBallY) * interpolation + lastBallY - ballHeight/2);
g.fillOval(drawX, drawY, ballWidth, ballHeight);
lastDrawX = drawX;
lastDrawY = drawY;
g.setColor(Color.BLACK);
g.drawString("FPS: " + fps, 5, 10);
frameCount++;
}
}
private class Ball
{
float x, y, lastX, lastY;
int width, height;
float xVelocity, yVelocity;
float speed;
public Ball()
{
width = (int) (Math.random() * 50 + 10);
height = (int) (Math.random() * 50 + 10);
x = (float) (Math.random() * (gamePanel.getWidth() - width) + width/2);
y = (float) (Math.random() * (gamePanel.getHeight() - height) + height/2);
lastX = x;
lastY = y;
xVelocity = (float) Math.random() * speed*2 - speed;
yVelocity = (float) Math.random() * speed*2 - speed;
}
public void update()
{
lastX = x;
lastY = y;
x += xVelocity;
y += yVelocity;
if (x + width/2 >= gamePanel.getWidth())
{
xVelocity *= -1;
x = gamePanel.getWidth() - width/2;
yVelocity = (float) Math.random() * speed*2 - speed;
}
else if (x - width/2 <= 0)
{
xVelocity *= -1;
x = width/2;
}
if (y + height/2 >= gamePanel.getHeight())
{
yVelocity *= -1;
y = gamePanel.getHeight() - height/2;
xVelocity = (float) Math.random() * speed*2 - speed;
}
else if (y - height/2 <= 0)
{
yVelocity *= -1;
y = height/2;
}
}
public void draw(Graphics g)
{
}
}
}
final Robot robot = new Robot();
javax.swing.Timer timer = new javax.swing.Timer(initialDelay, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
// update your image...
robot.keyPress(62);
}
});