2017-10-05 92 views
0

我正在寻找一种有效的方法来实现2D游戏渲染。如何正确高效地在2D游戏中渲染Java图形

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

我使用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(); 
    } 
} 
+0

对于fps,因为渲染图像不能完全总是在同一时间,你应该等待考虑最后渲染时间 – Tuco

+0

这是一个非常聪明的想法,究竟是多么准确我会这样做吗? –

+0

尽管在渲染循环中使用setFps()方法创建了16毫秒的延迟,该延迟允许每1000毫秒(几乎)60帧或每秒60帧 –

回答

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()之间的差异,您可以在调用之间花费时间(以纳秒为单位)。 我sugest不使用System.currentTimeMillis这是不太准确

+0

哇,很好,非常感谢,我会设置变量'fps'为60,以每秒60帧的速度渲染? –

+0

不,你的fps变量是以毫秒为单位的,所以如果你想要每秒60帧:fps = 1000/60 – Tuco

+0

有道理,alrigh t非常感谢你,tuco。 –