Java Applet Game Scorrimento 2D della finestra

Sto cercando di sviluppare un gioco di ruolo in 2D in un’applet Java. In questo momento ho un semplice ovale che il giocatore può usare Sinistra, Destra, Su e Giù per muoversi, e le collisioni contro i bordi dell’applet si fermano. Il problema è che voglio creare un mondo gigante (2000 px per 2000x) di area che il giocatore può spostare. Comunque, voglio che vedano solo 600px per 400x dello schermo alla volta. Se continuano a muoversi a destra, voglio che lo schermo li segua, lo stesso vale per su, giù e sinistra. Qualcuno può dirmi come farlo? Ecco il mio codice finora:

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

Questo è un esempio di base dell’area di visualizzazione a scorrimento, in cui il mondo virtuale è grande rispetto all’area di visualizzazione.

Questo in pratica mantiene un certo numero di parametri. Mantiene il punto in cui nel mondo la parte superiore / sinistra della vista è e i giocatori si posizionano all’interno del mondo.

Questi valori vengono convertiti in coordinate del mondo reale (dove 0x0 è l’angolo in alto a sinistra dell’area visibile).

Gli esempi utilizzano anche BufferedImage#getSubImage per rendere più semplice il rendering. Puoi anche calcolare la posizione di offset della mappa sulla vista, ma questo dipende dai bisogni …

inserisci la descrizione dell'immagine qui

 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 actionPerformsd(ActionEvent e) { moveParty(10, 0); } }); am.put("goLeft", new AbstractAction() { @Override public void actionPerformsd(ActionEvent e) { moveParty(-10, 0); } }); am.put("goUp", new AbstractAction() { @Override public void actionPerformsd(ActionEvent e) { moveParty(0, -10); } }); am.put("goDown", new AbstractAction() { @Override public void actionPerformsd(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; } } } 

Questo è come faccio nel mio motore.

Terrò due variabili OffSetX e OffSetY

E calcolarli ogni passo per centrare il giocatore in questo modo.

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

E quindi disegnare la mappa nella posizione (OffSetX, OffSetY) cioè, basta aggiungerli alla posizione originale dell’object da disegnare.

Puoi saltare gli oggetti di rendering che non sono visibili.