2017-10-05 11 views
0

Je suis à la recherche d'un moyen efficace de mettre en œuvre le rendu de jeux 2D.Comment rendre les graphiques Java dans un jeu 2D correctement et efficacement

Voici un exemple du type de système de rendu que mon jeu utilise pour le moment. (Je ne sais pas comment l'utiliser ou ce n'est pas assez flexible.)

J'utilise Canvas et ses BufferStrategies mais je ne suis pas sûr de leur efficacité. Toute aide est appréciée.

//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

Pour le fps, parce que le rendu d'une image ne peut pas prendre exactement exactement le même temps, vous devez attendre en tenant compte du dernier temps de rendu – Tuco

+0

c'est une idée assez intelligente, comment exactement est-ce que j'irais faire ça? –

+0

même si la méthode setFps() est utilisée dans la boucle de rendu pour créer un délai de 16 millisecondes qui autorise 60 images par 1000 millisecondes (presque) ou 60 images par seconde –

Répondre

0

Pour les images par seconde, vous devez prendre en compte la durée de la dernière image du rendu Il permet d'avoir frame rate constant

Pour cela, vous pouvez, pour chaque image:

//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 permet de mesurer le temps avec une bonne précision: si vous faites la différence entre deux appels de System.nanoTime(), vous avez le temps écoulé entre les appels en nanosecondes. Je sugest de ne pas utiliser System.currentTimeMillis qui est moins précis

+0

Wow gentil, merci beaucoup et je définirais la variable 'fps' à 60 pour rendre à 60 images par seconde droite? –

+0

Non, votre variable fps était en ms, donc si vous voulez 60 images par seconde: fps = 1000/60 – Tuco

+0

Semble, alrigh Je vous remercie beaucoup tuco. –