2013-04-17 66 views
2

我想在Java Applet中開發2D RPG遊戲。現在我有一個簡單的橢圓形,玩家可以使用Left,Right,Up和Down移動,並且與applet邊界的碰撞停止。問題是,我想創造一個玩家可以移動的區域的巨大世界(2000 x 2000 x)。不過,我希望他們一次只能看到600x400x的屏幕。如果他們繼續向右移動,我希望屏幕跟隨他們,同樣向上,向下和向左移動。誰能告訴我如何做到這一點?這是我的代碼到目前爲止:Java Applet遊戲2D窗口滾動

import java.awt.*; 
import java.awt.event.KeyEvent; 
import java.applet.Applet; 
import java.awt.event.KeyListener; 
import javax.swing.*; 

public class Main extends Applet implements Runnable, KeyListener 
{ 
    private Image dbImage; 
    private Graphics dbg; 
    Thread t1; 
    int x = 0; 
    int y = 0; 
    int prevX = x; 
    int prevY = y; 
    int radius = 40; 
    boolean keyReleased = false; 

    public void init() 
    { 
     setSize(600, 400); 

    } 

    public void start() 
    { 

     addKeyListener(this); 
     t1 = new Thread(this); 
     t1.start(); 
    } 

    public void destroy() 
    { 
    } 

    public void stop() 
    { 
    } 

    public void paint(Graphics g) 
    { 
     //player 
     g.setColor(Color.RED); 
     g.fillOval(x, y, radius, radius); 
    } 

    public void update(Graphics g) 
    { 

     dbImage = createImage (this.getSize().width, this.getSize().height); 
     dbg = dbImage.getGraphics(); 
     // initialize buffer 
     if (dbImage == null) 
     { 
     } 

     // clear screen in background 
     dbg.setColor(getBackground()); 
     dbg.fillRect(0, 0, this.getSize().width, this.getSize().height); 

     // draw elements in background 
     dbg.setColor(getForeground()); 
     paint(dbg); 
     // draw image on the screen 
     g.drawImage(dbImage, 0, 0, this); 
    } 

    @Override 
    public void run() 
    { 
     while (true) 
     { 
      //x++; 
      repaint(); 

      try 
      { 
       t1.sleep(17); 
      } 
      catch (Exception e) 
      { 
      } 
     } 
    } 

    public boolean CheckCollision(String dir) 
    { 
     if (x <= 0 && dir.equals("L")) 
     { 
      x = prevX; 
      return true; 
     } 
     else if (y <= 0 && dir.equals("U")) 
     { 
      y = prevY; 
      return true; 
     } 
     else if (x >= (getWidth() - radius) && dir.equals("R")) 
     { 
      System.out.println(getWidth()); 
      x = prevX; 
      return true; 
     } 
     else if (y >= (getHeight() - radius) && dir.equals("D")) 
     { 
      y = prevY; 
      return true; 
     } 
     return false; 
    } 

    @Override 
    public void keyPressed(KeyEvent e) 
    { 
     switch (e.getKeyCode()) 
     { 
     case KeyEvent.VK_RIGHT: 
      if (!CheckCollision("R")) 
      { 
      x += 4; 
      prevX = x; 
      } 
      break; 
     case KeyEvent.VK_LEFT: 
      if (!CheckCollision("L")) 
      { 
      x -= 4; 
      prevX = x; 
      } 
      break; 
     case KeyEvent.VK_UP: 
      if (!CheckCollision("U")) 
      { 
      y -= 4; 
      prevY = y; 
      } 
      break; 
     case KeyEvent.VK_DOWN: 
      if (!CheckCollision("D")) 
      { 
      y += 4; 
      prevY = y; 
      } 
      break; 
     } 

    } 

    @Override 
    public void keyReleased(KeyEvent arg0) 
    { 
     // TODO Auto-generated method stub 

    } 

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

    } 
} 
+0

本質上講,你需要創建一個虛擬世界(無,嚴重),所以即使角色只能在300x200的屏幕上,他們也可以在全球1000x700。這將要求你知道世界的頂部/左邊角落開始,並允許你查找功能將其轉換爲「虛擬」座標。簡單:D – MadProgrammer

+0

@MadProgrammer我是Java的新手,我不明白我如何創建你所說的。是否有代碼可以讓我將尺寸設置爲任何我想要的尺寸,但是讓我將尺寸設置爲像600x400一樣可見,並且隨着玩家向右,向左,向上或向下移動屏幕x或y,會發生什麼情況?換句話說,你是否知道代碼。我真的需要一些東西讓我開始。 –

+0

很多問題涉及到如何渲染世界?它是一個大的位圖還是一系列的瓷磚? – MadProgrammer

回答

1

這是我如何在我的引擎。

我會保持兩個變量OffSetXOffSetY

並計算他們的每一步居中球員像這樣。

OffSetX = 0; 
OffSetY = 0; 
if (MAP_WIDTH > WINDOW_WIDTH) { 
    OffSetX = Math.round(WINDOW_WIDTH/2 - obj.getX() - TILE_SIZE); 
    OffSetX = Math.min(OffSetX, 0); 
    OffSetX = Math.max(OffSetX, WINDOW_WIDTH - MAP_WIDTH); 
} 
if (MAP_HEIGHT > WINDOW_HEIGHT) { 
    OffSetY = Math.round(WINDOW_HEIGHT/2 - obj.getY() - TILE_SIZE); 
    OffSetY = Math.min(OffSetY, 0); 
    OffSetY = Math.max(OffSetY, WINDOW_HEIGHT - MAP_HEIGHT); 
} 

,然後在位置(OffSetX, OffSetY)即繪製地圖,只需添加這些到繪製對象的原來的位置。

您可能想要跳過不可見的渲染對象。

7

這是滾動可視區域的基本示例,其中虛擬世界很大,然後是視圖區域。

這基本上保持了一些參數。它保持了世界頂部/左邊的觀點和球員在世界上的位置。

這些值被轉換回現實世界座標(其中0x0是可視區域的左上角)。

這些示例還使用BufferedImage#getSubImage來更易於渲染。你可以計算出地圖的偏移位置的視圖爲好,但歸結爲需求...

enter image description here

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Point; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import javax.imageio.ImageIO; 
import javax.swing.AbstractAction; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.KeyStroke; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class MiddleEarth { 

    public static void main(String[] args) { 
     new MiddleEarth(); 
    } 

    public MiddleEarth() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new WorldPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class WorldPane extends JPanel { 

     private BufferedImage map; 
     private BufferedImage party; 
     private Point viewPort; 
     private Point partyPoint; 
     private BufferedImage view; 

     public WorldPane() { 
      try { 
       map = ImageIO.read(getClass().getResource("/MiddleEarth.jpg")); 
       party = ImageIO.read(getClass().getResource("/8BitFrodo.png")); 

       viewPort = new Point(0, (map.getHeight()/2) - 100); 
       partyPoint = new Point(party.getWidth()/2, (map.getHeight()/2)); // Virtual Point... 

      } catch (IOException exp) { 
       exp.printStackTrace(); 
      } 

      InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW); 
      ActionMap am = getActionMap(); 

      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "goRight"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "goLeft"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "goUp"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "goDown"); 

      am.put("goRight", new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        moveParty(10, 0); 
       } 
      }); 
      am.put("goLeft", new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        moveParty(-10, 0); 
       } 
      }); 

      am.put("goUp", new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        moveParty(0, -10); 
       } 
      }); 
      am.put("goDown", new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        moveParty(0, 10); 
       } 
      }); 

     } 

     protected void moveParty(int xDelta, int yDelta) { 
      partyPoint.x += xDelta; 
      partyPoint.y += yDelta; 
      Point view = fromWorld(partyPoint); 
      if (view.x > getWidth() - (party.getWidth()/2)) { 
       viewPort.x += xDelta; 
       if (viewPort.x + getWidth() > map.getWidth()) { 
        viewPort.x = map.getWidth() - getWidth(); 
        partyPoint.x = map.getWidth() - (party.getWidth()/2) - 1; 
       } 
       invalidate(); 
      } else if (view.x < party.getWidth()/2) { 
       viewPort.x += xDelta; 
       if (viewPort.x < 0) { 
        viewPort.x = 0; 
        partyPoint.x = (party.getWidth()/2); 
       } 
       invalidate(); 
      } 
      System.out.println(view + "; " + getHeight()); 
      if (view.y > getHeight() - (party.getHeight()/2)) { 
       viewPort.y += yDelta; 
       if (viewPort.y + getHeight() > map.getHeight()) { 
        viewPort.y = map.getHeight() - getHeight(); 
        partyPoint.y = map.getHeight() - (party.getHeight()/2) - 1; 
       } 
       invalidate(); 
      } else if (view.y < party.getHeight()/2) { 
       viewPort.y += yDelta; 
       if (viewPort.y < 0) { 
        viewPort.y = 0; 
        partyPoint.y = (party.getHeight()/2); 
       } 
       invalidate(); 
      } 
      repaint(); 
     } 

     @Override 
     public void invalidate() { 
      view = null; 
      super.invalidate(); 
     } 

     public BufferedImage getView() { 

      if (view == null && getWidth() > 0 && getHeight() > 0) { 

       view = map.getSubimage(viewPort.x, viewPort.y, getWidth(), getHeight()); 

      } 

      return view; 

     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(400, 400); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      if (map != null) { 
       g2d.drawImage(getView(), 0, 0, this); 

       Point real = fromWorld(partyPoint); 

       int x = real.x - (party.getWidth()/2); 
       int y = real.y - (party.getHeight()/ 2); 
       g2d.drawImage(party, x, y, this); 
      } 
      g2d.dispose(); 
     } 

     protected Point fromWorld(Point wp) { 

      Point p = new Point(); 

      p.x = wp.x - viewPort.x; 
      p.y = wp.y - viewPort.y; 

      return p; 

     } 
    } 
} 
+0

嗨,我嘗試使用該代碼併爲地圖重新創建了一張1000x600的圖片,併爲該派對創建了一張圖片,但我收到了此錯誤消息。我沒有更改任何代碼,只是圖像的URL: –

+0

線程「AWT-EventQueue-0」中的異常java.lang.IllegalArgumentException:input == null! \t at javax.imageio.ImageIO.read(Unknown Source) \t at MiddleEarth $ WorldPane。 (MiddleEarth.java:62)在MiddleEarth $ 1.run(MiddleEarth.java:39) \t \t在java.awt.event.InvocationEvent.dispatch(來源不明) \t在java.awt.EventQueue中。dispatchEventImpl(來源不明) \t在java.awt.EventQueue.access $ 200(來源不明) \t在java.awt.EventQueue中的$ 3.run(來源不明) \t在java.awt.EventQueue中的$ 3.run(來源不明) \t at java.security.AccessController.doPrivileged(Native Method) –

+0

圖像嵌入在應用程序中,默認包中。根據你把它們放在哪裏,你可能需要使用新的文件(...),而不是如果getResource(...) – MadProgrammer