天天看點

JAVA圖形操作中FPS的計算(附帶随機生成亂數球體用例)

 FPS:即幀 /秒(frames per second)的縮寫,也稱為幀速率。是指1秒鐘時間裡重新整理的圖檔的幀數,也可以了解為圖形處理器每秒鐘能夠重新整理幾次。如果具體到手機上就是指每秒鐘能夠 播放(或者錄制)多少格畫面。同時越高的幀速率可以得到更流暢、更逼真的動畫。每秒鐘幀數(fps)越多,所顯示的動作就會越流暢。 

在絕大多數圖形程式中(以遊戲類為典型),執行效率都以FPS作為評估标準。

由于目前JAVA方面缺少相關用例,故完成功能如下圖(在本機測試中,最大fps設定為500,實際達到FPS效率在IDE中280左右,單獨運作380左右,受系統配置等因素影響):

代碼如下:(請變更檔案字尾為jar)

FPS部分相關源碼:

package org.test;

import java.text.DecimalFormat;

/** 

* <p>Title: LoonFramework</p>

* <p>Description:</p>

* <p>Copyright: Copyright (c) 2007</p>

* <p>Company: LoonFramework</p>

* @author chenpeng    

* @email:[email][email protected][/email] 

* @version 0.1

*/

public class FPSListen {

        //設定動畫的FPS桢數,此數值越高,動畫速度越快。

        public static final int FPS = 500;    

        // 換算為運作周期

        public static final long PERIOD = (long) (1.0 / FPS * 1000000000); // 機關: ns(納秒)

        // FPS最大間隔時間,換算為1s = 10^9ns

        public static long FPS_MAX_INTERVAL = 1000000000L; // 機關: ns

        // 實際的FPS數值

        private double nowFPS = 0.0;

        // FPS累計用間距時間

        private long interval = 0L; // in ns

        private long time;

        //運作桢累計

        private long frameCount = 0;

        //格式化小數位數

        private DecimalFormat df = new DecimalFormat("0.0");

        //開啟opengl

        public void opengl(){

                System.setProperty("sun.java2d.opengl", "True");

                System.setProperty("sun.java2d.translaccel", "True");

        }

        /** *//**

         * 制造FPS資料

         * 

         */

        public void makeFPS() {

                frameCount++;

                interval += PERIOD;

                //當實際間隔符合時間時。

                if (interval >= FPS_MAX_INTERVAL) {

                        //nanoTime()傳回最準确的可用系統計時器的目前值,以毫微秒為機關

                        long timeNow = System.nanoTime();

                        // 獲得到目前為止的時間距離

                        long realTime = timeNow - time; // 機關: ns

                        //換算為實際的fps數值

                        nowFPS = ((double) frameCount / realTime) * FPS_MAX_INTERVAL;

                        //變更數值

                        frameCount = 0L;

                        interval = 0L;

                        time = timeNow;

                }

        public long getFrameCount() {

                return frameCount;

        public void setFrameCount(long frameCount) {

                this.frameCount = frameCount;

        public long getInterval() {

                return interval;

        public void setInterval(long interval) {

                this.interval = interval;

        public double getNowFPS() {

                return nowFPS;

        public void setNowFPS(double nowFPS) {

                this.nowFPS = nowFPS;

        public long getTime() {

                return time;

        public void setTime(long time) {

                this.time = time;

        public String getFPS(){

                return df.format(nowFPS);

}

球體類相關代碼:

import java.awt.Color;

import java.awt.Graphics;

/** *//**

public class Ball {

                private static final int SIZE = 10;

                private int x, y;

                protected int vx, vy;

                public Ball(int x, int y, int vx, int vy) {

                        this.x = x;

                        this.y = y;

                        this.vx = vx;

                        this.vy = vy;

                public void move() {

                        x += vx;

                        y += vy;

                        if (x < 0 || x > BallPanel.WIDTH - SIZE) {

                                vx = -vx;

                        }

                        if (y < 0 || y > BallPanel.HEIGHT - SIZE) {

                                vy = -vy;

                public void draw(Graphics g) {

                        g.setColor(Color.RED);

                        g.fillOval(x, y, SIZE, SIZE);

FPS及球體處理用代碼如下:

import java.awt.Dimension;

import java.awt.Frame;

import java.awt.Image;

import java.awt.Panel;

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import java.awt.image.BufferedImage;

import java.util.Random;

* <p>

* Title: LoonFramework

* </p>

* Description:以JAVA擷取FPS用示範程式及随機生成亂數球體。(更優化代碼内置于loonframework-game架構中)

* Copyright: Copyright (c) 2007

* Company: LoonFramework

* @author chenpeng

* @email:[email][email protected][/email]

public class BallPanel extends Panel implements Runnable {

        private static final long serialVersionUID = 1L;

        public static final int WIDTH = 360;

        public static final int HEIGHT = 360;

        // 設定最大球體數量

        private static final int NUM_BALLS = 50;

        // 定義球體數組

        private Ball[] ball;

        // 運作狀态

        private volatile boolean running = false;

        private Thread gameLoop;

        // 緩存用圖形

        private Graphics bg;

        private Image screen = null;

        // 生成随機數

        private Random rand;

        // fps監聽

        private FPSListen fps = null;

        public BallPanel() {

                setPreferredSize(new Dimension(WIDTH, HEIGHT));

                screen = new BufferedImage(WIDTH, HEIGHT, 1);

                bg = screen.getGraphics();

                fps = new FPSListen();

                //fps.opengl();

                // 以目前毫秒生成随機數

                rand = new Random(System.currentTimeMillis());

                ball = new Ball[NUM_BALLS];

                // 初始化球體參數

                for (int i = 0; i < NUM_BALLS; i++) {

                        int x = rand.nextInt(WIDTH);

                        int y = rand.nextInt(HEIGHT);

                        int vx = rand.nextInt(10);

                        int vy = rand.nextInt(10);

                        ball[i] = new Ball(x, y, vx, vy);

        // 加入Notify

        public void addNotify() {

                super.addNotify();

                // 判斷循環條件是否成立

                if (gameLoop == null || !running) {

                        gameLoop = new Thread(this);

                        gameLoop.start();

         * 進行線程運作。

        public void run() {

                long beforeTime, afterTime, timeDiff, sleepTime;

                long overSleepTime = 0L;

                int noDelays = 0;

                // 獲得精确納秒時間

                beforeTime = System.nanoTime();

                fps.setTime(beforeTime);

                running = true;

                while (running) {

                        gameUpdate();

                        repaint();

                        afterTime = System.nanoTime();

                        timeDiff = afterTime - beforeTime;

                        // 換算間隔時間

                        sleepTime = (FPSListen.PERIOD - timeDiff) - overSleepTime;

                        if (sleepTime > 0) {

                                // 制造延遲

                                try {

                                        Thread.sleep(sleepTime / 1000000L); // nano->ms

                                } catch (InterruptedException e) {

                                }

                                // 獲得延遲時間

                                overSleepTime = (System.nanoTime() - afterTime) - sleepTime;

                        } else {

                                // 重新計算

                                overSleepTime = 0L;

                                // 判斷noDelays值

                                if (++noDelays >= 16) {

                                        Thread.yield(); // 令線程讓步

                                        noDelays = 0;

                        // 重新獲得beforeTime

                        beforeTime = System.nanoTime();

                        // 制造FPS結果

                        fps.makeFPS();

         * 變更球體軌迹

        private void gameUpdate() {

                        ball[i].move();

         * 變更圖形

        public void update(Graphics g) {

                paint(g);

         * 顯示圖形

        public void paint(Graphics g) {

                // 設定背景為白色,并清空圖形

                bg.setColor(Color.WHITE);

                bg.fillRect(0, 0, WIDTH, HEIGHT);

                // FPS數值顯示

                bg.setColor(Color.BLUE);

                bg.drawString("FPS: " + fps.getFPS(), 4, 16);

                // 分别繪制相應球體

                        ball[i].draw(bg);

                g.drawImage(screen, 0, 0, this);

                g.dispose();

        public static void main(String[] args) {

                Frame frm = new Frame();

                frm.setTitle("Java FPS速度測試(由Loonframework架構提供)");

                frm.setSize(WIDTH, HEIGHT+20);

                frm.setResizable(false);

                frm.add(new BallPanel());

                frm.setVisible(true);

                frm.addWindowListener(new WindowAdapter(){

                        public void windowClosing(WindowEvent e){

                                System.exit(0);

                });

本文轉自 cping 51CTO部落格,原文連結:http://blog.51cto.com/cping1982/116709