Java Applet Game 2D Ventana de desplazamiento

Intento desarrollar un juego 2D RPG en un applet de Java. Ahora mismo tengo un óvalo simple que el jugador puede usar Izquierda, Derecha, Arriba y Abajo para moverse, y las colisiones contra los bordes del applet los detienen. El problema es que quiero crear un mundo gigante (2000px por 2000x) de área que el jugador puede mover. Sin embargo, quiero que solo vean 600px por 400x de la pantalla a la vez. Si siguen moviéndose hacia la derecha, quiero que la pantalla los siga, lo mismo va hacia arriba, abajo y hacia la izquierda. ¿Puede alguien decirme cómo hacer esto? Aquí está mi código hasta ahora:

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 = (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 } } 

Este es un ejemplo básico de desplazamiento del área visible, donde el mundo virtual es grande y luego el área de visualización.

Esto básicamente mantiene una cantidad de parámetros. Mantiene el punto donde en el mundo está la parte superior / izquierda de la vista y la posición de los jugadores dentro del mundo.

Estos valores se convierten a coordenadas del mundo real (donde 0x0 es la esquina superior izquierda del área visible).

Los ejemplos también usan BufferedImage#getSubImage para facilitar el procesamiento. También podría calcular la posición de desplazamiento del mapa a la vista, pero eso se reduce a las necesidades …

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(); px = wp.x - viewPort.x; py = wp.y - viewPort.y; return p; } } } 

Así es como lo hago en mi motor.

Mantendré dos variables OffSetX y OffSetY

Y calcule cada paso para centrar al jugador de esta manera.

 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); } 

Y luego dibuje el mapa en la posición (OffSetX, OffSetY) , es decir, simplemente agréguelos a la posición original del objeto para dibujar.

Es posible que desee omitir los objetos de representación que no son visibles.