2013-05-05 57 views
1

編輯:這是一個SSCCE來展示我的問題。儘管我雙緩衝JPanel撕裂?

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.Point; 
import java.awt.event.ActionEvent; 
import java.awt.image.BufferedImage; 
import java.awt.Graphics2D; 
import javax.swing.AbstractAction; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.KeyStroke; 

public class Main { 
    public static BufferedImage map, tileSand, tileSea; 
    public static void main(String[] args) { 
     map = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB); 
     for(int x = 0; x < 50 ; x++){ 
      for(int y = 0; y < 50 ; y++){ 
       boolean colour = Math.random() < 0.5; 
       if (colour){ 
        map.setRGB(x, y, -256); 
       } else { 
        map.setRGB(x, y, -16776961); 
       } 
      } 
     } 
     tileSand = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); 
     Graphics g = tileSand.getGraphics(); 
     g.setColor(Color.YELLOW); 
     g.fillRect(0, 0, 32, 32); 
     tileSea = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); 
     g.setColor(Color.BLUE); 
     g = tileSea.getGraphics(); 
     g.fillRect(0, 0, 32, 32); 
     Island test = new Main.Island(); 
     test.start(); 
     long start, sleep; 
     while(true) { 
      start = System.currentTimeMillis(); 
      test.getCanvas().requestFocus(); 
      test.getCanvas().repaint(); 
      sleep = 15-(System.currentTimeMillis()-start); 
      try { 
       Thread.sleep(sleep > 0 ? sleep : 0); 
      } catch (InterruptedException e) { 
      } 
     } 
    } 

    static class Island implements Runnable { 

     private Tile[][] tiles; 
     private JFrame frame; 
     private JPanel panel; 
     private Thread logicThread; 
     private boolean running = false; 
     private boolean paused = false; 
     private Image image; 
     private Player player; 

     public Island() { 
      image = new BufferedImage(1027, 768, BufferedImage.TYPE_INT_ARGB); 
      player = new Player(); 
      tiles = new Tile[map.getWidth()][map.getHeight()]; 
      int rgb; 
      for(int x = 0; x < map.getWidth(); x++) { 
       for(int y = 0; y < map.getHeight(); y++) { 
        rgb = map.getRGB(x, y); 
        switch (rgb) { 
         case -16776961: tiles[x][y] = new Tile("sea"); 
             break; 
         case -256: tiles[x][y] = new Tile("sand"); 
            break; 
        } 
       } 
      } 
      makeMap(); 
      makeFrame(); 
      addBindings(); 
      logicThread = new Thread(this); 
     } 

     public JPanel getCanvas() { 
      return panel; 
     } 

     public void start() { 
      running = true; 
      paused = false; 
      logicThread.start(); 
     } 

     public void run() { 
      long sleep, before; 
      while(running){ 
       before = System.currentTimeMillis(); 
       player.move(); 
       try { 
        sleep = 15-(System.currentTimeMillis()-before); 
        Thread.sleep(sleep > 0 ? sleep : 0); 
       } catch (InterruptedException ex) { 
       } 
       while(running && paused); 
      } 
      paused = false; 
     } 

     private void makeFrame() { 
      frame = new JFrame("Island"); 
      panel = new JPanel(){ 
       @Override 
       public void paintComponent(Graphics g) { 
        super.paintComponent(g); 
        Graphics2D g2d = (Graphics2D) image.getGraphics(); 
        g2d.setColor(Color.BLACK); 
        g2d.fillRect(0, 0, 1024, 768); 
        long xl, yl; 
        xl = player.getLocation().x-512; 
        yl = player.getLocation().y-384; 
        int x2, y2; 
        x2 = (int) Math.floor(xl/32); 
        y2 = (int) Math.floor(yl/32); 
        int xoffset, yoffset; 
        xoffset = (int) (xl % 32); 
        yoffset = (int) (yl % 32); 
        for(int x = x2; x < x2+40; x++) { 
         for(int y = y2; y < y2+40; y++) { 
          if (x < tiles.length && x > 0 && y < tiles[0].length && y > 0) { 
           g2d.drawImage(tiles[x][y].getContent(), (x-x2)*32 - xoffset, (y-y2)*32 - yoffset, null); 
          } 
         } 
        } 
        g.drawImage(image, 0, 0, null); 
       } 
      }; 
      panel.setPreferredSize(new Dimension(1024, 768)); 
      panel.setIgnoreRepaint(true); 
      frame.add(panel); 
      frame.pack(); 
      frame.setVisible(true); 
     } 

     private void addBindings() { 
      InputMap inputMap = panel.getInputMap(); 
      ActionMap actionMap = panel.getActionMap(); 
      inputMap.put(KeyStroke.getKeyStroke("Q"),"hold-sprint"); 
      actionMap.put("hold-sprint", new AbstractAction() { 
       public void actionPerformed(ActionEvent e) { 
        player.sprint(true); 
       } 
      }); 
      inputMap.put(KeyStroke.getKeyStroke("released Q"),"release-sprint"); 
      actionMap.put("release-sprint", new AbstractAction() { 
       public void actionPerformed(ActionEvent e) { 
        player.sprint(false); 
       } 
      }); 
      inputMap.put(KeyStroke.getKeyStroke("RIGHT"),"hold-right"); 
      actionMap.put("hold-right", new AbstractAction() { 
       public void actionPerformed(ActionEvent e) { 
        player.right(true); 
       } 
      }); 
      inputMap.put(KeyStroke.getKeyStroke("released RIGHT"),"release-right"); 
      actionMap.put("release-right", new AbstractAction() { 
       public void actionPerformed(ActionEvent e) { 
        player.right(false); 
       } 
      }); 
      inputMap.put(KeyStroke.getKeyStroke("DOWN"),"hold-down"); 
      actionMap.put("hold-down", new AbstractAction() { 
       public void actionPerformed(ActionEvent e) { 
        player.down(true); 
       } 
      }); 
      inputMap.put(KeyStroke.getKeyStroke("released DOWN"),"release-down"); 
      actionMap.put("release-down", new AbstractAction() { 
       public void actionPerformed(ActionEvent e) { 
        player.down(false); 
       } 
      }); 
      inputMap.put(KeyStroke.getKeyStroke("LEFT"),"hold-left"); 
      actionMap.put("hold-left", new AbstractAction() { 
       public void actionPerformed(ActionEvent e) { 
        player.left(true); 
       } 
      }); 
      inputMap.put(KeyStroke.getKeyStroke("released LEFT"),"release-left"); 
      actionMap.put("release-left", new AbstractAction() { 
       public void actionPerformed(ActionEvent e) { 
        player.left(false); 
       } 
      }); 
      inputMap.put(KeyStroke.getKeyStroke("UP"),"hold-up"); 
      actionMap.put("hold-up", new AbstractAction() { 
       public void actionPerformed(ActionEvent e) { 
        player.up(true); 
       } 
      }); 
      inputMap.put(KeyStroke.getKeyStroke("released UP"),"release-up"); 
      actionMap.put("release-up", new AbstractAction() { 
       public void actionPerformed(ActionEvent e) { 
        player.up(false); 
       } 
      }); 
     } 

     private void makeMap() { 
      for(int x = 0; x < tiles.length; x++) { 
       for(int y = 0; y < tiles[0].length; y++) { 
        switch (tiles[x][y].getType()) { 
         case "sea": tiles[x][y].setContent(tileSea); 
            break; 
         case "sand": tiles[x][y].setContent(tileSand); 
             break; 
        } 
       } 
      } 
     } 
    } 

    static class Player{ 
     private Point location; 
     private int xspeed, yspeed; 
     private boolean left, up, right, down, sprint; 

     public Player() { 
      location = new Point(0, 0); 
      left = false; 
      up = false; 
      right = false; 
      down = false; 
      sprint = false; 
      xspeed = yspeed = 0; 
     } 
     public void left(boolean state){ 
      left = state; 
     } 

     public void up(boolean state){ 
      up = state; 
     } 

     public void right(boolean state){ 
      right = state; 
     } 

     public void down(boolean state){ 
      down = state; 
     } 

     public void sprint(boolean state) { 
      sprint = state; 
     } 

     public void move() { 
      if (sprint) { 
       if (left) { 
        if(xspeed>-10) 
         xspeed--; 
       } if (right) { 
        if(xspeed<10) 
         xspeed++; 
       } if (up) { 
        if(yspeed>-10) 
         yspeed--; 
       } if (down) { 
        if(yspeed<10) 
         yspeed++; 
       } 
      } else { 
       if (left) { 
        if(xspeed>-5) 
         xspeed--; 
       } if (right) { 
        if(xspeed<5) 
         xspeed++; 
       } if (up) { 
        if(yspeed>-5) 
         yspeed--; 
       } if (down) { 
        if(yspeed<5) 
         yspeed++; 
       } 
      } 
      if (!sprint) { 
       if (xspeed > 5) { 
        xspeed--; 
       } if (xspeed < -5) { 
        xspeed++; 
       } if (yspeed > 5) { 
        yspeed--; 
       } if (yspeed < -5) { 
        yspeed++; 
       } 
      } 
      if (!left && !right) { 
       if (xspeed > 0) { 
        xspeed--; 
       } if (xspeed < 0) { 
        xspeed++; 
       } 
      } if (!up && !down) { 
       if (yspeed > 0) { 
        yspeed--; 
       } if (yspeed < 0) { 
        yspeed++; 
       } 
      } 
      location.x = location.x + xspeed; 
      location.y = location.y + yspeed; 
     } 

     public Point getLocation() { 
      return location; 
     } 
    } 

    static class Tile { 
     private String type; 
     private BufferedImage tile; 

     public Tile(String type) { 
      this.type = type; 
     } 

     public String getType() { 
      return type; 
     } 

     public void setContent(BufferedImage newTile) { 
      tile = newTile; 
     } 

     public BufferedImage getContent() { 
      return tile; 
     } 
    } 
} 

我有一個修改過的paintComponent方法的JPanel。在這種方法中,我根據玩家的位置將2D陣列中的相關圖塊繪製到屏幕上。我將所有瓷磚都繪製到BufferedImage上,然後在繪製方法結束時將其應用到屏幕上。理論上這不應該造成撕裂,因爲我是雙緩衝?下面是相應的代碼,圖像僅僅是一個與屏幕尺寸的BufferedImage:

public void paintComponent(Graphics g) { 
     Graphics2D g2d = (Graphics2D) image.getGraphics(); 
     g2d.setColor(Color.BLACK); 
     g2d.fillRect(0, 0, 1024, 768); 
     long xl, yl; 
     xl = player.getLocation().x-512; 
     yl = player.getLocation().y-384; 
     int x2, y2; 
     x2 = (int) Math.floor(xl/32); 
     y2 = (int) Math.floor(yl/32); 
     int xoffset, yoffset; 
     xoffset = (int) (xl % 32); 
     yoffset = (int) (yl % 32); 
     for(int x = x2; x < x2+40; x++) { 
      for(int y = y2; y < y2+40; y++) { 
       if (x < tiles.length && x > 0 && y < tiles[0].length && y > 0) { 
        g2d.drawImage(tiles[x][y].getContent(), (x-x2)*32 - xoffset, (y-y2)*32 - yoffset, null); 
       } 
      } 
     } 
     g.drawImage(image, 0, 0, null); 
    } 

我覺得撕裂可能會因玩家的位置改變了塗料方法的持續時間造成瓷磚不引起匹配起來,玩家越快效果越明顯。不過,我在開始時獲得球員位置並將其存儲爲兩次,我的印象是長時間通過值而非參考傳遞,所以在方法運行時球員位置應該保持不變。

我很高興提供更多代碼:),並提前致謝。

+0

爲了更快提供更好的幫助,請發佈[SSCCE](http://sscce.org/)。 – 2013-05-05 16:15:34

+2

更改'public void paintComponent(Graphics g){..' to'public void paintComponent(Graphics g){super.paintComponent(g)..' – 2013-05-05 16:16:22

+0

剛剛測試過,恐怕沒有任何影響,我是在印象中,如果你在面板上繪製組件,只需要這樣做? 另一件要補充的是,我沒有用JPanel擴展我的類,我在我的構造函數中初始化JPanel後覆蓋了paintComponent。像這樣: panel = new JPanel(){ @Override public void paintComponent(Graphics g){etc ... – Iain 2013-05-05 16:24:16

回答

-1

就這樣,如果人們發現我的問題,並想知道我最終做了什麼「修復」,切換到C++和SDL或其他圖像庫,然後再進入你的項目,這對於這種類型更好的東西。

+0

爲什麼你會投我的答案?這是我能找到的唯一解決方案。 – Iain 2013-05-08 11:46:38