2016-03-30 36 views
2

我原本写这篇文章的时候开始在windows上写这个,它运行的很顺利,虽然偶尔会冻结;但是,我切换到Linux后,图形非常非常波涛汹涌。我期望它以前能够工作,因为我的显卡上有合适的驱动程序,但是在切换之后,我可能会因为坏的驱动程序而导致性能下降。虽然2D游戏引擎应该可以在非常糟糕的电脑上运行。我在想,为什么它运行得如此缓慢,以及我如何能让运行速度更快。除了下面的类外,还有其他类,但下面的类包含程序的大部分主要功能。我的2dGameEngine非常滞后

package Platformer; 

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.awt.event.KeyListener; 
import java.io.File; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.HashMap; 

import javax.sound.sampled.*; 
import javax.sound.sampled.LineEvent.Type; 
import javax.swing.JPanel; 
import javax.swing.Timer; 

public abstract class GameComponent extends JPanel{ 
    //delete this i think 
    public static int ticks=0; 
    public Rectangle box; 

    private final int FPS=40; 
    public int xMovement=0; 
    public int yMovement=0; 
    public final int A=0,D=1,S=2,W=3,SPACE=4; 
    public boolean[] keyPressed=new boolean[5]; 
    private InputController keyListener; 
    public ArrayList<Entity> Entities=new ArrayList<Entity>(); 
    HashMap sounds=new HashMap(); 

    public boolean drawLines=false; 
    public int xAxisLines=40; 
    public int yAxisLines=27; 

    Quadtree quad=new Quadtree(0,new Rectangle(0,0,1920,1080)); 


    public GameComponent(){ 
     keyListener=new InputController(); 
     box=new Rectangle(90,90,20,20); 
     setFocusable(true); 
     requestFocusInWindow(true); 
     run(); 

    } 
    public void run(){ 
     addKeyListener(keyListener); 

     Timer timer=new Timer(1000/FPS, new ActionListener(){ 

      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       //movement(); 

       gameLoop(); 
       collisions(); 
       repaint(); 
       ticks++; 
       if(ticks==360 || ticks==1000){ 
        try{ 
         playSound("spun"); 



        } 
        catch(Exception e){ 
         e.printStackTrace(); 
        } 
       } 

      } 

     }); 
     timer.start(); 
    } 
    @Override 
    public void paint(Graphics g){ 
     super.paint(g); 
     Graphics2D g2d=(Graphics2D)g.create(); 
     //g2d.setColor(Color.RED); 
     //g2d.fill(box); 




     for(Entity entity: Entities){ 
      g2d.drawImage(entity.IMAGE, entity.getX(),entity.getY(), entity.IMAGE.getWidth(), entity.IMAGE.getHeight(), null); 
      g2d.drawString(String.valueOf(entity.NAME), entity.getX(), entity.getY()); 
     } 
     ///draw lines in window if enabiled 
     if(drawLines){ 
      drawLines(g2d); 
     } 
     ///do collisions 

     g2d.dispose(); 

    } 

    class InputController implements KeyListener{ 

     @Override 
     public void keyPressed(KeyEvent e) { 
      switch(e.getKeyCode()){ 
      case KeyEvent.VK_W: 
       keyPressed[W]=true; 
       break; 
      case KeyEvent.VK_S: 
       keyPressed[S]=true; 
       break; 
      case KeyEvent.VK_A: 
       keyPressed[A]=true; 
       break; 
      case KeyEvent.VK_D: 
       keyPressed[D]=true; 
       break; 
      case KeyEvent.VK_SPACE: 
       keyPressed[SPACE]=true; 
      } 
     } 

     @Override 
     public void keyReleased(KeyEvent e) { 
      // TODO Auto-generated method stub 
      switch(e.getKeyCode()){ 
      case KeyEvent.VK_W: 
       keyPressed[W]=false; 
       break; 
      case KeyEvent.VK_S: 
       keyPressed[S]=false; 
       break; 
      case KeyEvent.VK_A: 
       keyPressed[A]=false; 
       break; 
      case KeyEvent.VK_D: 
       keyPressed[D]=false; 
       break; 
      case KeyEvent.VK_SPACE: 
       keyPressed[SPACE]=false; 
      } 
     } 

     @Override 
     public void keyTyped(KeyEvent e) { 
      // TODO Auto-generated method stub 

     } 
    } 

    public abstract void gameLoop(); 
    public void drawLines(Graphics2D g2d){ 
     for(int i=0;i<1920;i+=1920/xAxisLines){ 
      g2d.drawLine(i, 0, i, 1080); 
     } 
     for(int i=0;i<1080;i+=1080/yAxisLines){ 
      g2d.drawLine(0, i, 1920, i); 
     } 
    } 
    public void collisions(){ 
    ////collisions! 

     ArrayList<Entity> returnEntities=new ArrayList<Entity>(); 
     quad.clear(); 
     for(int i=0;i<Entities.size();i++){ 
      quad.insert(Entities.get(i)); 
     } 

     for(int i=0;i <Entities.size();i++){ 
      returnEntities.clear(); 
      returnEntities=quad.retrieve(returnEntities,Entities.get(i)); 

      for(Entity e:returnEntities){ 
       //System.out.println(Entities.get(i).NAME+" could collide with "+e.NAME); 
       if(Math.abs(Entities.get(i).getX()-e.getX())<= Entities.get(i).IMAGE.getWidth()/2+e.IMAGE.getWidth()/2 && Math.abs(Entities.get(i).getY()-e.getY())<= Entities.get(i).IMAGE.getHeight()/2+e.IMAGE.getHeight()/2 && Entities.get(i)!=e){ 
        //System.out.println(Entities.get(i).NAME+" is colliding with "+e.NAME); 
       } 
      } 
     } 
      ////collisions! 
     /* 
     System.out.println(String.valueOf(quad.getIndex(Entities.get(0)))); 
     System.out.println(Entities.get(0).bounds.x); 
     System.out.println(Entities.get(0).bounds.y); 
     */ 
    } 
    public void playSound(String fileName) throws IOException, 
     UnsupportedAudioFileException, LineUnavailableException, InterruptedException { 
     File clipFile=new File("assets//"+fileName+".wav"); 

     class AudioListener implements LineListener { 
      private boolean done = false; 
      @Override public synchronized void update(LineEvent event) { 
       Type eventType = event.getType(); 
       if (eventType == Type.STOP || eventType == Type.CLOSE) { 
       done = true; 
       notifyAll(); 
       } 
      } 
      public synchronized void waitUntilDone() throws InterruptedException { 
       while (!done) {} 
      } 
     } 
     class SoundThread implements Runnable { 
      AudioListener listener = new AudioListener(); 
      AudioInputStream audioInputStream; 
      public SoundThread() throws UnsupportedAudioFileException, IOException{ 
       audioInputStream = AudioSystem.getAudioInputStream(clipFile); 
      } 

      @Override 
      public void run() { 
       try{ 
        Clip clip=AudioSystem.getClip(); 
        clip.addLineListener(listener); 
        clip.open(audioInputStream); 
        try{ 
         clip.start(); 
         listener.waitUntilDone(); 
        } 
        finally{ 
         clip.close(); 
        } 
       } 
       catch(Exception e){ 
        e.printStackTrace(); 
       } 
       finally{ 
        try { 
         audioInputStream.close(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 

     } 
     Thread thread=new Thread(new SoundThread()); 
     thread.start(); 
    } 

} 
+0

[MCVE(http://www.stackoverflow.com/help/mcve) –

回答

3

那么你已经写得非常程序化,而不是面向对象。你有很多的迭代列表,也许如果你重构它,那么你可能会加快它,有没有什么地方可以得到代码(github等),就像这段代码一样,我们可以做的不多。

+0

噢,这里https://github.com/quiteaniceguy/2dGameEngine – user2350459

+0

你能否解释它是如何以非常程序化的方式编写的,而不是面向对象的? – user2350459

+0

经典的例子是空间侵略者,如果你有一个主循环来完成移动和射击等,这是程序化的,在OO世界里你会做类似于激光基地的东西来侦听它的移动命令和发射命令,当它发射时它会创建一个新的“子弹”对象,该对象具有移动的开始位置和向量/方向。然后,当子弹检测到它已经触及某事物时,它会通知所击中的物体它已经这样做,并让物体决定是否应该炸毁,什么也不做,或者让子弹反转它的方向。 etc. –

3

做任何具体原因Graphics2D g2d=(Graphics2D)g.create()g2d.dispose();

难道你不能只是Graphics2D g2d = (Graphics2D) g;?它可能会提高性能。

0

我不知道你在用什么IDE,但我建议你做一个分析。 Eclipse有一个很好的插件。

有一次,我只好写了一个游戏我自己,和我的问题是与图像的大小:

``g2d.drawImage(entity.IMAGE, entity.getX(),entity.getY(), entity.IMAGE.getWidth(), entity.IMAGE.getHeight(), null);`` 

我有将每个图像的大小减小到40kb以下以正常运行。

另一件事是,你切换你的用户界面上的一些元素,看看是什么使性能大幅提升,然后你可以调整该组件。

+0

这种方法有什么问题? – JSONStatham

3

TLDR;但设法找到2个根本性错误:

  • 在Swing 从未覆盖paint()做图形。

使用覆盖安全paintComponent()。 (除@ YoavAharoni的观点外,不要在每次重新绘制时创建新的图形上下文。)

  • 永远不要在EDT内部进行长期持久的任务。

在你的情况,你叫gameLoop()collisions()playSound() - 我以为是耗时 - 计时器的事件方法内。相反,请使用java.util.Timer或线程。

如果您必须使用EDT,以便渲染持久图形,请使用SwingWorker。(注:repaint()可以被EDT外面叫)