2017-10-14 116 views
0

我需要在我的遊戲(Pong)中添加一個可用的FPS計數器。爲了製造FPS計數器,我顯然還需要一個遊戲循環,我試着分別製作一個遊戲循環和FPS計數器,它似乎正在工作。不過,我在將FPS計數器添加到Pong遊戲時遇到了一些問題。我的遊戲中的FPS Counter(Java)

這是遊戲圈/ 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

在這個答案中,我沒有找到你的櫃檯問題的原因。對我來說相當複雜。不過,我會給你一些代碼,以幫助入門:

這是一個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秒,其打印數量的主要方法測試每秒空循環)。

您可以使用它像這樣:

  1. 在你的遊戲類添加private FPSCounter fpscnt;
  2. 構建遊戲構造函數中的對象,如下所示:fpscnt = new FPSCounter();
  3. 通過調用fpscnt.start();在遊戲開始前啓動計數器。例如,你可以在遊戲的構造函數中調用它。
  4. 現在,每當畫一幅畫框時,您應該調用計數器的frame()方法。我現在正在演示...
  5. 現在,只要你想得到每秒幀數,你應該調用計數器的方法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幀/秒,那麼在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) { 

} 
} 
+0

非常感謝你的回覆,它幫助了很多。事情是,我在遊戲中有一個計時器,它不會讓遊戲運行速度超過5毫秒,現在遊戲忽略了那個計時器並且運行速度非常快。我怎樣才能讓遊戲運行得更慢而不影響fps? –

+0

@ J.Doe可能會在遊戲代碼中使用[Thread.sleep](https://docs.oracle.com/javase/9​​/docs/api/java/lang/Thread.html#sleep-long-)? (不是繪畫代碼) – thanopi57

+0

好吧,除了在屏幕上顯示FPS之外,現在一切正在運行。我試着用g.drawString等方法輸入你的建議,但它沒有奏效。每秒幀數應該每秒出現在屏幕上。我應該在哪5個步驟中放置你建議的代碼? –