2014-03-24 22 views
0

我正在尝试创建一个游戏。而几乎每次我动,它留下了痕迹JFrame,长方形的叶子痕迹

代码:

package lt.mchackers.gametest.main; 
import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Insets; 
import java.awt.event.KeyEvent; 
import java.awt.image.BufferedImage; 
import java.io.BufferedReader; 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileReader; 
import java.io.IOException; 

import javax.imageio.ImageIO; 
import javax.swing.JFrame; 

import lt.mchackers.gametest.handlers.InputHandler; 

/** 
* Main class for the game 
*/ 
public class Main extends JFrame 
{ 
     private static final long serialVersionUID = -828018325337767157L; 
     boolean isRunning = true; 
     int fps = 30; 
     int windowWidth = 320; 
     int windowHeight = 320; 
     int speed; 

     BufferedImage backBuffer; 
     Insets insets; 
     InputHandler input; 

     int x = 0; 
     int y = 0; 
     int xa = 0; 
     int ya = 0; 
     Coordinates coords = new Coordinates(0, 0); 

     public static void main(String[] args) 
     {  Main game = new Main(); 
       game.run(); 
       System.exit(0); 
     } 

     /** 
     * This method starts the game and runs it in a loop 
     */ 
     public void run() 
     { 
       initialize(); 

       while(isRunning) 
       { 

         long time = System.currentTimeMillis(); 

         update(); 
         draw(); 

         // delay for each frame - time it took for one frame 
         time = (1000/fps) - (System.currentTimeMillis() - time); 

         if (time > 0) 
         { 
           try 
           { 
             Thread.sleep(time); 
           } 
           catch(Exception e){} 
         } 
       } 

       setVisible(false); 
     } 

     /** 
     * This method will set up everything need for the game to run 
     */ 
     void initialize() 
     { 
       setTitle("Game Tutorial"); 
       setSize(windowWidth, windowHeight); 
       setResizable(false); 
       setDefaultCloseOperation(EXIT_ON_CLOSE); 
       setVisible(true); 

       insets = getInsets(); 
       setSize(insets.left + windowWidth + insets.right, 
           insets.top + windowHeight + insets.bottom); 

       backBuffer = new BufferedImage(windowWidth, windowHeight, BufferedImage.TYPE_INT_RGB); 
       input = new InputHandler(this); 
       Graphics bbg = backBuffer.getGraphics(); 
       BufferedReader reader = null; 
       try { 
        reader = new BufferedReader(new FileReader("map")); 
       } catch (FileNotFoundException e1) { 
        e1.printStackTrace(); 
       } 
       String line = null; 
       try { 
        BufferedImage gray = ImageIO.read(new File("gray.png")); 
        BufferedImage black = ImageIO.read(new File("black.png")); 
        while ((line = reader.readLine()) != null) { 
         for(String s : line.split("")) 
         { 
          if (s.contains("*")) 
          { 
           bbg.drawImage(gray, xa-32, ya, null); 
          } 
          else if (s.contains("#")) 
          { 
           bbg.drawImage(black, xa-32, ya, null); 
          } 
          if (xa < 320) 
          { 
           xa += 32; 
          } 
          else 
          { 
           ya += 32; 
           xa = 0; 
          } 
          System.out.println(xa); 
          System.out.println(ya); 
         } 
        } 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 

     } 

     /** 
     * This method will check for input, move things 
     * around and check for win conditions, etc 
     */ 
     void update() 
     { 
      if (input.isKeyDown(KeyEvent.VK_NUMPAD0)) 
      { 
       speed -= 1; 
      } 
      if (input.isKeyDown(KeyEvent.VK_NUMPAD1)) 
      { 
       speed += 1; 
      } 
      if (input.isKeyDown(KeyEvent.VK_RIGHT)) 
      { 
       coords.setCoords(coords.getX() + 32, coords.getY()); 
      } 
      if (input.isKeyDown(KeyEvent.VK_LEFT)) 
      { 
       coords.setCoords(coords.getX() - 32, coords.getY()); 
      } 
      if (input.isKeyDown(KeyEvent.VK_UP)) 
      { 
       coords.setCoords(coords.getX(), coords.getY() - 32); 
      } 
      if (input.isKeyDown(KeyEvent.VK_DOWN)) 
      { 
       coords.setCoords(coords.getX(), coords.getY() + 32); 
      } 
      //System.out.println(x); 
      //System.out.println(y); 
      //System.out.println(speed); 
      if (coords.getY() < 0) 
      { 
       coords.setCoords(coords.getX(), 0); 
      } 
      if (coords.getX() < 0) 
      { 
       coords.setCoords(0, coords.getY()); 
      } 
      if (coords.getX() > windowWidth - 32) 
      { 
       coords.setCoords(windowWidth - 32, coords.getY()); 
      } 
      if (coords.getY() > windowHeight - 32) 
      { 
       coords.setCoords(coords.getX(), windowHeight - 32); 
      // y = windowHeight - 32; 
      } 

     } 

     /** 
     * This method will draw everything 
     */ 
     void draw() 
     {    
       Graphics g = getGraphics(); 
       //this.setBackground(Color.BLACK); 
       //super.paintComponents(g); 
       backBuffer.setRGB(x, y, Color.BLACK.getRGB()); 

       Graphics bbg = backBuffer.getGraphics(); 

       BufferedReader reader = null; 
       try { 
        reader = new BufferedReader(new FileReader("map")); 
       } catch (FileNotFoundException e1) { 
        e1.printStackTrace(); 
       } 
       String line = null; 
       try { 
        BufferedImage gray = ImageIO.read(new File("gray.png")); 
        BufferedImage black = ImageIO.read(new File("black.png")); 
        while ((line = reader.readLine()) != null) { 
         for(String s : line.split("")) 
         { 
          if (s.contains("*") && xa + 32!= coords.getX() && ya - 32 != coords.getY()) 
          { 
           bbg.drawImage(gray, xa-32, ya, null); 
          } 
          else if (s.contains("#") && xa + 32 != coords.getX() && ya - 32 != coords.getY()) 
          { 
           bbg.drawImage(black, xa-32, ya, null); 
          } 
          if (xa < 320) 
          { 
           xa += 32; 
          } 
          else 
          { 
           ya += 32; 
           xa = 0; 
          } 
          //System.out.println(xa); 
          //System.out.println(ya); 
         } 
        } 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
       bbg.setColor(Color.WHITE); 

       xa = 0; 
       ya = 0; 
       System.out.println(coords.getX()); 
       bbg.setColor(Color.WHITE); 
       bbg.fillRect(coords.getX(),coords.getY(), 32,32); 
       System.out.println(coords.getY()); 
       //bbg.setColor(Color.BLACK); 
       //bbg.drawOval(x, y, 20, 20); 


       g.drawImage(backBuffer, insets.left, insets.top, this); 
     } 
} 

感谢您的帮助。

+2

祝你好运,我希望你找到代码的问题..... –

+0

您可能需要重新绘制其他明智的背景,前一个位置仍然可见。取消注释paintcomponent调用可能会做到这一点。另外我会将文件和图像的读取移出绘图方法。在您的init中读取并存储它们。 – onesixtyfourth

+0

当我取消注释paintcomponent调用时,窗口闪烁。 – Zygimantas

回答

0

查看我的代码here,以获得有关如何正确绘制游戏循环中的东西的提示。

基本上你需要照顾的是双缓冲,以防止任何闪烁,并重新绘制背景,以便你不留下任何长方形的踪迹。

您还可以查看Killer Game Programming in Java在线书籍,它可以帮助您了解游戏编程概念及其实现。

双缓冲的概念很简单。由于在屏幕上绘画比在游戏中更新对象的状态需要更多的时间,因此我们使用两个画布来防止在对象直接在屏幕上绘制时出现的任何闪烁问题。

当游戏循环中更新对象状态时,它将呈现在背景画布中。然后将背景画布复制到屏幕上,与直接在屏幕上绘画相比,花费的时间更少。在复制过程中,对象状态会再次更新,并且会再次显示在背景画布上,然后复制到屏幕上。重复这一遍,你会得到双缓冲。
基本上你保留了一个屏幕缓冲区,这个缓冲区将被绘制,然后你的游戏将缓冲区中的对象渲染到屏幕上。

这里的,我认为可能会帮助一个代码,你理解的概念:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.Toolkit; 
import java.awt.event.KeyAdapter; 
import java.awt.event.KeyEvent; 

public class GamePanel extends JPanel implements Runnable 
{ 
    private static final long serialVersionUID = 6892533030374996243L; 
    public static final int WIDTH = 800; 
    public static final int HEIGHT = 600; 

    private Thread animator; 

    private volatile boolean running = false; 
    private volatile boolean isGameOver = false; 
    private volatile boolean isUserPaused = false; 
    private volatile boolean isWindowPaused = false; 

    private Graphics dbg; 
    private Image dbImage = null; 

    private static final int NO_DELAYS_PER_YIELD = 16; 
    private static final int MAX_FRAME_SKIPS = 5; 

    private static final Color backgroundColor = new Color(245, 245, 245); 

    private static long fps = 30; 
    private static long period = 1000000L * (long) 1000.0/fps; 

    private static volatile boolean isPainted = false; 

    public GamePanel() 
    { 
    setBackground(backgroundColor); 
    setPreferredSize(new Dimension(WIDTH, HEIGHT)); 

    setFocusable(true); 
    requestFocus(); 
    readyForPause(); 

    // Add key listeners here... 
    } 

    public void addNotify() 
    { 
    super.addNotify(); 
    startGame(); 
    } 

    void startGame() 
    { 
    if (animator == null || !running) 
    { 
     animator = new Thread(this); 
     animator.start(); 
    } 
    } 

    void stopGame() 
    { 
    running = false; 
    } 

    private void readyForPause() 
    { 
    addKeyListener(new KeyAdapter() 
    { 
     public void keyPressed(KeyEvent e) 
     { 
     int keyCode = e.getKeyCode(); 
     if ((keyCode == KeyEvent.VK_ESCAPE) || (keyCode == KeyEvent.VK_Q) 
      || (keyCode == KeyEvent.VK_END) || (keyCode == KeyEvent.VK_P) 
      || ((keyCode == KeyEvent.VK_C) && e.isControlDown())) 
     { 
      if (!isUserPaused) 
      setUserPaused(true); 
      else 
      setUserPaused(false); 
     } 
     } 
    }); 
    } 

    // This is the game loop. You can copy-paste it even in your own code if you want to. 
    public void run() 
    { 
    long beforeTime, afterTime, timeDiff, sleepTime; 
    long overSleepTime = 0L; 
    int noDelays = 0; 
    long excess = 0L; 

    beforeTime = System.nanoTime(); 

    running = true; 

    while (running) 
    { 
     requestFocus(); 
     gameUpdate(); 
     gameRender(); 
     paintScreen(); 

     afterTime = System.nanoTime(); 

     timeDiff = afterTime - beforeTime; 
     sleepTime = (period - timeDiff) - overSleepTime; 

     if (sleepTime > 0) 
     { 
     try 
     { 
      Thread.sleep(sleepTime/1000000L); 
     } 
     catch (InterruptedException e) 
     { 
     } 

     overSleepTime = (System.nanoTime() - afterTime - sleepTime); 
     } 
     else 
     { 
     excess -= sleepTime; 
     overSleepTime = 0L; 

     if (++noDelays >= NO_DELAYS_PER_YIELD) 
     { 
      Thread.yield(); 
      noDelays = 0; 
     } 
     } 

     beforeTime = System.nanoTime(); 

     int skips = 0; 

     while ((excess > period) && (skips < MAX_FRAME_SKIPS)) 
     { 
     excess -= period; 
     gameUpdate(); 
     skips++; 
     } 

     isPainted = true; 
    } 
    System.exit(0); 
    } 

    private void gameUpdate() 
    { 
    if (!isUserPaused && !isWindowPaused && !isGameOver) 
    { 
     // Update the state of your game objects here... 
    } 
    } 

    private void gameRender() 
    { 
    if (dbImage == null) 
    { 
     dbImage = createImage(WIDTH, HEIGHT); 
     if (dbImage == null) 
     { 
     System.out.println("Image is null."); 
     return; 
     } 
     else 
     dbg = dbImage.getGraphics(); 
    } 

    dbg.setColor(backgroundColor); 
    dbg.fillRect(0, 0, WIDTH, HEIGHT); 

    // Render your game objects here.... 
    // like: xyzObject.draw(dbg); 
    // or dbg.drawOval(...); 

    if (isGameOver) 
     gameOverMessage(dbg); 
    } 

    private void gameOverMessage(Graphics g) 
    { 
    // Paint a game over message here.. 
    } 

    private void paintScreen() 
    { 
    Graphics g; 

    try 
    { 
     g = this.getGraphics(); 
     if ((g != null) && (dbImage != null)) 
     g.drawImage(dbImage, 0, 0, null); 
     Toolkit.getDefaultToolkit().sync(); 
     g.dispose(); 
    } 
    catch (Exception e) 
    { 
     System.out.println("Graphics context error : " + e); 
    } 
    } 

    public void setWindowPaused(boolean isPaused) 
    { 
    isWindowPaused = isPaused; 
    } 

    public void setUserPaused(boolean isPaused) 
    { 
    isUserPaused = isPaused; 
    } 
} 

然后你就可以在你的游戏面板简单地添加到您的JFrame类似以下内容:

import java.awt.GridBagLayout; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 

import javax.swing.JFrame; 

public class GameFrame extends JFrame 
{ 
    private static final long serialVersionUID = -1624735497099558420L; 
    private GameFrame gamePanel = new GamePanel(); 

    public GameFrame() 
    { 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setTitle("Game"); 

    addWindowListener(new FrameListener()); 

    getContentPane().setLayout(new GridBagLayout()); 
    getContentPane().add(gamePanel); 

    pack(); 
    setLocationRelativeTo(null); 
    setResizable(false); 
    setVisible(true); 
    } 

    public class FrameListener extends WindowAdapter 
    { 
    public void windowActivated(WindowEvent we) 
    { 
     gamePanel.setWindowPaused(false); 
    } 

    public void windowDeactivated(WindowEvent we) 
    { 
     gamePanel.setWindowPaused(true); 
    } 

    public void windowDeiconified(WindowEvent we) 
    { 
     gamePanel.setWindowPaused(false); 
    } 

    public void windowIconified(WindowEvent we) 
    { 
     gamePanel.setWindowPaused(true); 
    } 

    public void windowClosing(WindowEvent we) 
    { 
     gamePanel.stopGame(); 
    } 
    } 

    public static void main(String args[]) 
    { 
    new GameFrame(); 
    } 
} 
+0

我是游戏编程的新手,您能告诉我该怎么做吗? – Zygimantas

+0

好吧,我的代码都在链接中,你可以先看到,并让我知道你是否想知道什么特别。这是一个完整的工作游戏,你可以下载并自己玩。 –

+0

如何制作双缓冲? – Zygimantas