我需要在游戏(Pong)中添加一个可用的FPS计数器。为了制作一个FPS计数器我显然也需要一个游戏循环,我尝试分别制作一个游戏循环和FPS计数器,它似乎正在工作。但是,我在将PPS计数器添加到我的Pong游戏时遇到了一些问题。
这是游戏循环/ FPS计数器的代码:
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.Timer;
public class Main extends Canvas implements Runnable{
JFrame frame;
int windowWidth, windowHeight;
Point bollXY;
int screenWidth, screenHeight;
Timer timer;
Image bildPaddel;
Image bildBollen;
int paddelY;
int paddel2Y;
boolean paddelUp, paddelDown;
Random rand;
int score, score2;
boolean bollUp, bollRight, changeDirection;
boolean paused;
int fruktDistansRand;
long time;
int fps, newfps;
private boolean running = false;
private Thread thread;
private synchronized void start() {
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
private synchronized void stop(){
if(!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.exit(1);
}
public static void main(String args[]) {
Main main = new Main();
JFrame frame = new JFrame();
frame.add(main);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
main.start();
}
@Override
public void run() {
long lastTime = System.nanoTime();
final double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks ;
double delta = 0;
int updates = 0;
int frames = 0;
long timer = System.currentTimeMillis();
while(running) {
long now = System.nanoTime();
delta += (lastTime - now) / ns;
lastTime = now;
if(delta >= 1) {
updates++;
delta--;
}
frames++;
if(System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("Ticks: " + updates + ", FPS: " + frames);
updates = 0;
frames = 0;
}
}
stop();
}
}
我尝试将FPS计数器添加到游戏中但由于某种原因它不起作用。如果您知道如何制作更好的FPS计数器和/或如何将其添加到游戏中,请提供帮助。顺便说一句,我不希望FPS锁定在60。
答案 0 :(得分:0)
在这个答案中,我找不到你的反问题的原因。这对我来说相当复杂。但我会给你一些代码来帮助你开始:
这是FPS计数器的代码:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class FPSCounter implements ActionListener {
private final Timer resetTimer;
private int current, last;
public FPSCounter() {
resetTimer = new Timer(1000, this);
}
public synchronized void start() {
resetTimer.start();
current = 0;
last = -1;
}
public synchronized void stop() {
resetTimer.stop();
current = -1;
}
public synchronized void frame() {
++current;
}
@Override
public synchronized void actionPerformed(final ActionEvent e) {
last = current;
current = 0;
}
public synchronized int get() {
return last;
}
public static void main(final String[] args) {
final FPSCounter cnt = new FPSCounter();
cnt.start();
new Timer(2000, e -> { System.out.println(cnt.get()); }).start();
while (true)
cnt.frame();
// cnt.stop();
}
}
主方法测试计数器是否有效(每2秒,它会打印每秒空循环的数量)。
您可以像这样使用它:
private FPSCounter fpscnt;
。fpscnt = new FPSCounter();
。fpscnt.start();
启动计数器。例如,你可以在游戏的构造函数中调用它。frame()
方法。我接下来要示威...... get()
方法。我接下来要示威...... 现在,在游戏的paintComponent()
方法中,打印帧数/秒的行应如下所示:
fpscnt.frame(); //Because this is a new frame paint operation.
g.setFont(new Font("Arial", Font.BOLD, 25));
g.drawString("" + fpscnt.get(), 5, 22); //Paint the FPS.
注意:
get()
方法返回的每个值都会延迟1秒。我的意思是如果你看到64 fps,那么64就是最后(过去)秒的帧。
所以你的游戏的Main
课程应该是这样的:
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class Main extends JPanel implements KeyListener, ActionListener{
public static class FPSCounter implements ActionListener {
private final Timer resetTimer;
private int current, last;
public FPSCounter() {
resetTimer = new Timer(1000, this);
}
public synchronized void start() {
resetTimer.start();
current = 0;
last = -1;
}
public synchronized void stop() {
resetTimer.stop();
current = -1;
}
public synchronized void frame() {
++current;
}
@Override
public synchronized void actionPerformed(final ActionEvent e) {
last = current;
current = 0;
}
public synchronized int get() {
return last;
}
}
// Variabler
JFrame frame;
int windowWidth, windowHeight;
Point ballXY;
int screenWidth, screenHeight;
Timer timer;
Image imagePaddle;
Image imageBall;
int paddleY;
int paddle2Y;
boolean paddelUp, paddelDown;
Random rand;
int score, score2;
boolean ballUp, ballRight, changeDirection;
boolean paused;
int DistanceRand;
long time;
int fps, newfps;
private final FPSCounter fpscnt; //added line (step 1).
// Konstruktor
public Main(){
// Definera variabler
frame = new JFrame();
imagePaddle = new ImageIcon("src/images/Player.png").getImage();
imageBall = new ImageIcon("src/images/Pong.png").getImage();
ballXY = new Point(673, 352);
paddleY = 312;
paddle2Y = 312;
paddelUp = false;
rand = new Random();
score = 0;
score2 = 0;
ballUp = false;
ballRight = false;
changeDirection = false;
paused = false;
DistanceRand = 0;
time = System.currentTimeMillis();
fps = 0;
newfps = 0;
// Lyssnare
frame.addKeyListener(this);
// Bygga fönstret
frame.add(this);
// Obligatoriska egenskaper
frame.setTitle("Pong");
frame.setSize(1366, 724);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
this.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
ballUp = true;
ballRight = true;
changeDirection = false;
ballXY = new Point();
frame.add(this);
timer = new Timer(5, this);
timer.start();
fpscnt = new FPSCounter(); //added line (step 2).
fpscnt.start(); //added line (step 3).
}
// Metoder
public static void main(String[] args) {
new Main();
}
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(imageBall, ballXY.x, ballXY.y, null);
g.drawImage(imagePaddle, 50, paddleY, null);
g.drawImage(imagePaddle, 1300, paddle2Y, null);
g.setFont(new Font("Arial", Font.BOLD, 100));
g.setColor(Color.WHITE);
g.drawString(score2 + "", 1002, 100);
g.drawString(score + "", 314, 100);
if(paused){
g.setFont(new Font("Arial", Font.BOLD, 80));
g.drawString("PAUSED", 510, 370);
timer.stop();
}
if(System.currentTimeMillis() - time >= 1000){
time = System.currentTimeMillis();
fps = newfps;
newfps = 0;
}
else{
newfps++;
}
fpscnt.frame(); //added line (step 4).
g.setFont(new Font("Arial", Font.BOLD, 25));
g.drawString("" + fpscnt.get(), 5, 22); //added line (step 5).
}
public void AI(){
DistanceRand = rand.nextInt(200) + 960;
if(ballXY.x > DistanceRand && ballXY.x < 1380 && ballRight && paddle2Y > 0 && paddle2Y < 596){
if(paddle2Y + 50 < ballXY.y){
paddle2Y = paddle2Y + 3;
}
else{
paddle2Y = paddle2Y - 3;
}
if(paddle2Y <= 0){
paddle2Y = paddle2Y + 3;
}
if(paddle2Y >= 596){
paddle2Y = paddle2Y - 3;
}
}
}
public void ifUp(){
if(ballUp){
if(changeDirection){
if(ballXY.y < 0){
ballUp = false;
}
else{
ballXY.y = ballXY.y - 3;
}
}
else{
if(ballXY.y < 0){
ballUp = false;
}
else{
ballXY.y = ballXY.y - 3;
}
}
}
else{
if(changeDirection){
if(ballXY.y > 675){
ballUp = true;
}
else{
ballXY.y = ballXY.y + 3;
}
}
else{
if(ballXY.y > 675){
ballUp = true;
}
else{
ballXY.y = ballXY.y + 3;
}
}
}
}
public void update(){
if(paddelUp){
if(paddleY > 0){
paddleY = paddleY - 3;
}
}
if(paddelDown){
if(paddleY < 596){
paddleY = paddleY + 3;
}
}
if(ballRight){
if(ballXY.x > 1290 && ballXY.x < 1300 && ballXY.y < paddle2Y + 100 && ballXY.y > paddle2Y-20){
if(!ballUp && ballXY.y < paddle2Y){
changeDirection = true;
ballUp = true;
}
else if(ballUp && ballXY.y > paddle2Y + 80){
changeDirection = true;
ballUp = false;
}
ballRight = false;
}
else if(ballXY.x > 1600){
score++;
ballXY.y = rand.nextInt(690);
ballXY.x = 678;
}
else
ballXY.x = ballXY.x + 3;
ifUp();
}
else{
if(ballXY.x > 50 && ballXY.x < 60 &&ballXY.y < paddleY + 100 && ballXY.y > paddleY-20){
if(!ballUp && ballXY.y < paddleY){
changeDirection = true;
ballUp = true;
}
else if(ballUp && ballXY.y > paddleY + 80){
changeDirection = true;
ballUp = false;
}
ballRight = true;
}
else if(ballXY.x < -244){
score2++;
ballXY.x = 678;
ballXY.y = rand.nextInt(596);
}
else
ballXY.x = ballXY.x - 3;
ifUp();
}
AI();
repaint();
}
@Override
public void actionPerformed(ActionEvent e) {
update();
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W || e.getKeyCode() == KeyEvent.VK_UP){
paddelUp = true;
}
if(e.getKeyCode() == KeyEvent.VK_S || e.getKeyCode() == KeyEvent.VK_DOWN){
paddelDown = true;
}
if(e.getKeyCode() == KeyEvent.VK_SPACE){
if(paused){
paused = false;
timer.start();
}
else{
paused = true;
}
}
}
@Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W || e.getKeyCode() == KeyEvent.VK_UP){
paddelUp = false;
}
if(e.getKeyCode() == KeyEvent.VK_S || e.getKeyCode() == KeyEvent.VK_DOWN){
paddelDown = false;
}
}
@Override
public void keyTyped(KeyEvent e) {
}
}