简体   繁体   中英

Java Applet Game 2D Window Scrolling

I'm trying to develop a 2D RPG Game in a Java Applet. Right now I've got a simple oval that the player can use Left, Right, Up and Down to move, and collisions against the borders of the applet stops them. The problem is, I want to create a giant world(2000px by 2000x) of area that the player can move. However, I want them only to see 600px by 400x of the screen at one time. If they keep moving right, I want the screen to follow them, same goes for up, down and left. Can anyone tell me how to do this? Here is my code so far:

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

    }
}

This is a basic example of scrolling viewable area, where the virtual world is large then the view area.

This basically maintains a number of parameters. It maintains the point where in the world the top/left of the view is and the players position within the world.

These values are converted back to real world coordinates (where 0x0 is the top left corner of the viewable area).

The examples also use BufferedImage#getSubImage to make it easier to render. You could calculate the offset position of the map to the view as well, but that comes down to needs...

在此输入图像描述

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;

        }
    }
}

This is how I do in my engine.

I'll keep two variables OffSetX and OffSetY

And calculate them every step to center the player like this.

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

And then draw the map at the position (OffSetX, OffSetY) ie, just add these to the original position of the object to draw.

You may want to skip rendering objects which are not visible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM