如何正确有效地在2D游戏中渲染Java图形

时间:2017-10-05 04:24:16

标签: java 2d rendering

我正在寻找一种实现2D游戏渲染的有效方法。

这是我的游戏目前使用什么样的渲染系统的示例。 (我要么不知道如何使用它,要么它不够灵活。)

我使用Canvas及其BufferStrategies,但我不确定它们的效率如何。 任何帮助表示赞赏。

//MY RENDERING SYSTEM EXPLAINED IN JAVA AND WITH ONLY ONE CLASS.
//DOES NOT INCLUDE TICKING JUST RENDERING, TICKING IS A DIFFERENT THREAD.
//(so they can run on different frames per second)
//main() method is at the very bottom.

/*
 * @Author
 *  CodyOrr4
 */

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;


public class Main implements Runnable {

    public static Cache cache;
    public static JFrame frame;
    public static JPanel panel;
    public static JViewport camera;
    public static Canvas canvas;
    public static BufferStrategy bufferStrategy;
    public static Graphics graphics;
    public static boolean rendering = false;
    public static Thread renderingThread;

    //turns this runnable into an object.
    public Main() {
        frame = new JFrame("Rendering System Example");
        frame.setSize(new Dimension(800, 600));
        frame.setDefaultCloseOperation(1);
        frame.setVisible(true);

        panel = new JPanel();
        panel.setBackground(Color.DARK_GRAY);

        canvas = new Canvas();
        canvas.setBackground(Color.BLACK);
        canvas.setPreferredSize(new Dimension(800, 600));
        canvas.setMinimumSize(new Dimension(800, 600));
        canvas.setMaximumSize(new Dimension(2000, 2000));

        cache = new Cache();

        panel.add(canvas);
        frame.getContentPane().add(panel);
    }

    //used to run things that are not meant to be run in a loop;
    private void init() {
        cache.initCache(); //can now grab sprites (including names/ids) and other types within cache.
    }

    //renders everything (this method is used in a while() loop based on a boolean, within the run() method);
    private void render(Graphics g) {

        g.drawImage(cache.getSprite(0), 400, 300, 25, 25, null);

    }

    //runs the runnable
    public void run() {
        init();
        while(rendering) {
            setFps(16);//simply set fps now - iJustin   *codys note on the setFps(fps); method* = not sure if its the same thing lol, 
                                                        //but since ticking and rendering are separate threads in the main source (and contain separate init() methods) it seems like it would be good.

            if(bufferStrategy == null) {
                canvas.createBufferStrategy(3);//should only need a max of 3.
                bufferStrategy = canvas.getBufferStrategy();
                graphics = bufferStrategy.getDrawGraphics();
                System.out.println("creating canvas components...");
            }

            //drawing with methods
            render(graphics);

            //drawing without methods
            graphics.drawImage(cache.getSprite(0), 0, 0, 50, 50, null);



            bufferStrategy.show();
            graphics.dispose();
        }
    }

    //starts the run method and creates a thread for this 
    public synchronized void start() {
        renderingThread = new Thread(this);
        renderingThread.setName("Game Rendering Thread");
        renderingThread.start();
        rendering = true;
    }

    //stops the while loop by setting the boolean to false and the thread is now null
    public synchronized void stop() {
        renderingThread = null;
        rendering = false;
    }

    //@Author iJustin - sets fps of the rendering loop (while() loop within run() method)
    @SuppressWarnings("static-access")
    public void setFps(long fps) {
        try {
            renderingThread.sleep(fps);
        }
        catch(InterruptedException e) {

        }
    }

    //main method obv.
    public static void main(String[] args) {
        Main gameExample = new Main();
        gameExample.start();
    }
}

1 个答案:

答案 0 :(得分:0)

对于fps,您应该考虑最后一帧渲染时间的持续时间 它允许具有恒定的帧速率

为此,您可以为每一帧:

//a the start of rendering process
long startRendering=System.nanoTime();

... rendering here...

//duration of the frame rendering in ms :
long durationMs=TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-startRendering);

// now waits 
if (durationMs < fps) 
{
renderingThread.sleep(fps - durationMs);
}

System.nanoTime允许以很高的准确度测量时间:如果你在两次System.nanoTime()调用之间取得差异,那么在调用之间经过的时间以纳秒为单位。 我觉得不使用System.currentTimeMillis不太准确