2011-07-18 54 views
2

好吧,即時通訊在我的智慧結束。我正在嘗試創建一個小的等角拼貼地圖,這個拼圖的大小可以隨着鼠標拖拽而修改視角。 我得到了正確的繪圖(我想),我得到了拖動的工作,只是似乎沒有能夠得到正確的鼠標。 我到目前爲止,我得到的瓷磚幾乎是正確的,但它的大約一半的瓷磚大小,我找不到彌補偏移的方式。爪哇鼠標採摘鑽石瓷磚地圖

下面是代碼:

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.GraphicsConfiguration; 
import java.awt.GraphicsEnvironment; 
import java.awt.Point; 
import java.awt.Polygon; 
import java.awt.Rectangle; 
import java.awt.Transparency; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.event.MouseMotionListener; 
import java.awt.image.BufferedImage; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class MapView { 

    public static void main(String[] args) { 
     JFrame test = new JFrame("IsoView"); 
     test.setSize(800, 600); 
     MapViewPane pane = new MapViewPane(); 
     test.getContentPane().setLayout(new BorderLayout()); 
     test.getContentPane().add(pane, BorderLayout.CENTER); 
     test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     test.setVisible(true); 
    } 

    private static class MapViewPane extends JPanel 
      implements MouseMotionListener, MouseListener { 

     private BufferedImage BackImage; 
     BufferedImage GrassTile, SelectedBorder; 
     private Point MousePoint, PrevView, ViewLocation, Selected; 
     private boolean Dragging; 
     private int mapwidth, mapheight, tilecount; 

     public MapViewPane() { 
      super(); 
      this.setOpaque(true); 
      createAssets(); 
      tilecount = 30; 
      mapwidth = GrassTile.getWidth() * tilecount; 
      mapheight = GrassTile.getHeight() * tilecount; 
      ViewLocation = new Point(0, mapheight/2); 
      Selected = new Point(-1, -1); 
      addMouseListener(this); 
      addMouseMotionListener(this); 
     } 

     private void createAssets() { 
      GraphicsConfiguration gc = 
        GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); 
      GrassTile = gc.createCompatibleImage(128, 
        64, Transparency.TRANSLUCENT); 
      Graphics g = GrassTile.getGraphics(); 
      Polygon poly = new Polygon(); 
      poly.addPoint(0, 32); 
      poly.addPoint(64, 0); 
      poly.addPoint(128, 32); 
      poly.addPoint(64, 64); 
      g.setColor(Color.GREEN); 
      g.fillPolygon(poly); 
      g.setColor(Color.BLUE); 
      g.drawPolygon(poly); 
      g.dispose(); 
      SelectedBorder = gc.createCompatibleImage(128, 
        64, Transparency.TRANSLUCENT); 
      g = SelectedBorder.getGraphics(); 
      g.setColor(Color.red); 
      g.drawPolygon(poly); 
      g.dispose(); 
     } 

     @Override 
     public void paint(Graphics g) { 
      //super.paint(g); 
      Rectangle visiblerec = this.getVisibleRect(); 
      g.setColor(Color.BLACK); 
      g.fillRect(visiblerec.x, visiblerec.y, 
        visiblerec.width, visiblerec.height); 
      checkBackImage(); 
      Graphics bg = BackImage.getGraphics(); 
      drawGrassGrid(bg); 
      bg.dispose(); 
      g.drawImage(BackImage, 0, 0, this); 
     } 

     private void drawGrassGrid(Graphics g) { 
      int dx = 0; 
      int dy = 0; 
      g.setColor(Color.BLACK); 
      g.fillRect(0, 0, BackImage.getWidth(), BackImage.getHeight()); 
      for (int x = 0; x < tilecount; x++) { 
       for (int y = 0; y < tilecount; y++) { 
        dx = x * GrassTile.getWidth()/2 
          - y * GrassTile.getWidth()/2; 
        dy = x * GrassTile.getHeight()/2 
          + y * GrassTile.getHeight()/2; 
        dx -= ViewLocation.x; 
        dy -= ViewLocation.y; 
        g.drawImage(GrassTile, dx, dy, this); 
        if ((x == Selected.x) && (y == Selected.y)) { 
         g.drawImage(SelectedBorder, dx, dy, this); 
        } 
        g.drawString("(" + x + "," + y + ")", dx, dy 
          + GrassTile.getHeight()/2); 
       } 
      } 
     } 

     private void checkBackImage() { 
      if ((BackImage == null) || (BackImage.getWidth() != this.getWidth()) 
        || (BackImage.getHeight() != this.getHeight())) { 
       GraphicsConfiguration gc = 
         GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); 
       BackImage = gc.createCompatibleImage(this.getWidth(), 
         this.getHeight(), Transparency.BITMASK); 
      } 
     } 

     @Override 
     public void mouseDragged(MouseEvent e) { 
      if (Dragging) { 
       ViewLocation.x = PrevView.x + MousePoint.x - e.getX(); 
       ViewLocation.y = PrevView.y + MousePoint.y - e.getY(); 
       if (ViewLocation.x < -mapwidth/2) { 
        ViewLocation.x = -mapwidth/2; 
       } 
       if (ViewLocation.y < -mapheight/2 + this.getHeight()) { 
        ViewLocation.y = -mapheight/2 + this.getHeight(); 
       } 
       if (ViewLocation.x > mapwidth/2 - this.getWidth() 
         + GrassTile.getWidth()) { 
        ViewLocation.x = mapwidth/2 - this.getWidth() 
          + GrassTile.getWidth(); 
       } 
       if (ViewLocation.y > mapheight/2 + this.getHeight()) { 
        ViewLocation.y = mapheight/2 + this.getHeight(); 
       } 
       repaint(); 
      } 
     } 

     @Override 
     public void mouseMoved(MouseEvent e) { 
     } 

     @Override 
     public void mouseClicked(MouseEvent e) { 
      if (!Dragging) { 
       int x = (GrassTile.getWidth() * (e.getY() + ViewLocation.y) 
         + GrassTile.getHeight() * (e.getX() + ViewLocation.x)) 
         /(GrassTile.getWidth() * GrassTile.getHeight()); 
       int y = (GrassTile.getWidth() * (e.getY() + ViewLocation.y) 
         - GrassTile.getHeight() * (e.getX() + ViewLocation.x)) 
         /(GrassTile.getWidth() * GrassTile.getHeight()); 

//  int x = (int) Math.floor((e.getY() + ViewLocation.y) 
//   /(double) GrassTile.getHeight() - (e.getX() + ViewLocation.x) 
//   /(double) GrassTile.getWidth()); 
//  int y = (int) Math.floor((e.getY() + ViewLocation.y) 
//   /(double) GrassTile.getHeight() + (e.getX() + ViewLocation.x) 
//   /(double) GrassTile.getWidth()); 

       Selected.setLocation(x, y); 
       repaint(); 
       System.out.println("(" + x + "," + y + ")"); 
      } 
     } 

     @Override 
     public void mousePressed(MouseEvent e) { 
      if ((e.getButton() == MouseEvent.BUTTON1) && !Dragging) { 
       MousePoint = e.getPoint(); 
       PrevView = new Point(ViewLocation); 
       Dragging = true; 
      } 
     } 

     @Override 
     public void mouseReleased(MouseEvent e) { 
      Dragging = false; 
      MousePoint = null; 
     } 

     @Override 
     public void mouseEntered(MouseEvent e) { 
     } 

     @Override 
     public void mouseExited(MouseEvent e) { 
     } 
    } 
} 

我在點擊方法中的一些公式註釋掉至極我嘗試過,但他們不工作(x和y軸反轉的那個樣子,還沒有嘗試找出原因然而)。 如果有人能指出我所犯的錯誤,我會很感激。

+0

能不能使這是一個[SSCCE(http://pscode.org/sscce.html)因爲有一些模棱兩可的班有(進口什麼雪碧,例如)。 –

+0

好吧,希望這是SSCCE現在;) 我發現,如果我畫瓷磚向左移動tilewidth/2它完美的作品,但id仍然想找出我的錯誤是在計算中,因爲這只是一個workarround不是等式的修復;) –

+0

+1 [sscce](http://sscce.org/)。 – trashgod

回答

1

我設法爲您解決它。首先,我做了一些代數(希望通過內聯評論解釋)來簡化計算哪個瓦片的命中。接下來的一點你有點意識到;有鑄造問題。您需要在使用前將的所有內容轉換爲雙精度。如果你做int/int那麼你已經進行了演員並失去了精確度。

使它擊中正確的瓷磚的訣竅是1)鑄造早期和2)+/- 0.5這是用來強制返回int演員去一個或另一個。詳細說明,(int)6.9 == 6

這裏的工作答案:

@Override 
    public void mouseClicked(MouseEvent e) { 
     if (!Dragging) { 
      /* 
      // copy of the tile location assignment code as a reminder 
      dx = x * GrassTile.getWidth()/2 
        - y * GrassTile.getWidth()/2; 
      dy = x * GrassTile.getHeight()/2 
        + y * GrassTile.getHeight()/2; 
      dx -= ViewLocation.x; 
      dy -= ViewLocation.y; 
      */ 
      int pickX = e.getX() + ViewLocation.x; 
      int pickY = e.getY() + ViewLocation.y; 
      int tileW = GrassTile.getWidth(); 
      int tileH = GrassTile.getHeight(); 
      /* 
      // assignment code refactored 
      x - y = 2 * pickX/tileW; 
      x + y = 2 * pickY/tileH; 

      // x+y= refactored to y= 
      y = (2*pickY/tileH) - x; 
      // substitute into x-y + refactor 
      2x = (2 * pickX/tileW) + (2 * pickY/tileH); 

      // x+y= refactored to x= 
      x = (2*pickY/tileH) - y; 
      // substitute x-y + refactor 
      -2y = (2 * pickX/tileW) - (2 * pickY/tileH); 
      2y = (2 * pickY/tileH) - (2 * pickX/tileW); 
      */ 
      int hitx = (int)(((double)pickX/(double)tileW) + ((double)pickY/(double)tileH) - 0.5); 
      int hity = (int)(((double)pickY/(double)tileH) - ((double)pickX/(double)tileW) + 0.5); 
      Selected.setLocation(hitx, hity); 
      repaint(); 
      //System.out.println("(" + x + "," + y + ")"); 
     } 
    } 
+0

謝謝,像這樣的魅力工作。但爲什麼不使用Math.Floor()和Math.Ceil()而不是那些+ -0.5? –

+0

無論哪種方式工作。前一段時間我使用鑄造來提高效率,但你是對的。 Math.Floor()和Math.Ceil()更清晰,您可以使用它。 –

+0

「如果任一操作數的類型爲double,則另一個操作數轉換爲double。」 - [JLS第5.6.2節二進制數字升級](http://java.sun.com/docs/books/jls/third_edition/html/ conversions.html#5.6.2) – trashgod

1

Polygon實現了Shape接口,因此幾個contain()變體之一可能會簡化您的計算。如example所示,AffineTransformcreateTransformedShape()方法也可能有所幫助。

+0

我只使用多邊形來簡化示例代碼。我實際上使用圖像作爲瓷磚,所以改變它們的形狀不是必須的,因爲它們都是等距的。如果我將每個瓷磚包裹一個多邊形,我將不得不爲每個瓷磚創建一個圓形。我喜歡保持簡單和高效的內存,所以我很早就拋棄了這個解決方案。此外,還需要在拖動時移動所有邊界的座標,或者有一個公式來計算視圖座標以映射座標,這將使我回到當前的問題。 –

+0

使用[flyweight pattern](http://en.wikipedia.org/wiki/Flyweight_pattern)將顯着降低開銷並仍然簡化幾何。 'createTransformedShape()'只需要翻譯,而不是旋轉或剪切。 – trashgod

+0

那麼這將是一個好方法,如果我將它用於一個真實的遊戲或類似的東西,但在這種情況下,它只是表格數據的圖形表示,所以我想保持儘可能簡單的事情。它仍然需要一個工作方程來挑選。 但是,謝謝你的建議,可能會在我的另一個項目中有用。 –