2013-04-17 2 views
2

Java 애플릿에서 2D RPG 게임을 개발하려고합니다. 지금 나는 플레이어가 왼쪽, 오른쪽, 위, 아래로 움직일 수있는 간단한 타원형을 가지고 있으며, 애플릿의 테두리에 대한 충돌은 그들을 멈추게합니다. 문제는 플레이어가 움직일 수있는 거대한 세계 (2000x 2000x)를 만들고 싶습니다. 그러나 한 번에 화면의 600xx400x 만보기를 원합니다. 그들이 계속 오른쪽으로 움직인다면 나는 스크린을 따라 가야한다. 똑같은 것이 위, 아래, 왼쪽이다. 아무도 이걸하는 방법을 말해 줄 수 있습니까? 지금까지 내 코드는 다음과 같습니다.Java 애플릿 게임 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

을 당신은뿐만 아니라 보려면지도의 오프셋 (offset) 위치를 계산할 수 있지만, 그 요구에 내려 오는, 당신은 (아니, 심각) 가상 세계를 만들어야합니다 문자가 화면의 300x200에만있을 수도 있지만, 세계에서 1000x700 일 수 있습니다. 이것은 당신이 세계의 좌/우 구석이 어디에서 시작하는지 알 필요가 있고 그것을 "가상"좌표로 변환하기위한 검색 기능을 허용합니다. Easy : 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! MiddleEarth $ WorldPane에서 \t (javax.imageio.ImageIO.read) (알 수없는 출처) \t java.awt.EventQueue에서 java.awt.event.InvocationEvent.dispatch (알 수없는 소스) \t에서 \t MiddleEarth $ 1.run (MiddleEarth.java:39) \t에서 (MiddleEarth.java:62).dispatchEventImpl (알 수없는 소스) \t (알 수없는 소스) java.awt.EventQueue $의 3.run에서 \t (알 수없는 소스) java.awt.EventQueue $의 3.run에서 \t (알 수없는 소스) (200) java.awt.EventQueue.access $에서 \t at java.security.AccessController.doPrivileged (네이티브 메소드) –

+0

이미지는 기본 패키지의 응용 프로그램 내에 포함됩니다. 어디에 놓았 느냐에 따라 getResource (...)가있는 경우 새 File (...)을 사용해야 할 수도 있습니다. – MadProgrammer