Java Applet游戏2D窗口滚动

时间:2013-04-17 03:02:56

标签: java 2d

我正在尝试在Java Applet中开发2D RPG游戏。现在我有一个简单的椭圆形,玩家可以使用左,右,上和下移动,并且与小程序边界的碰撞会阻止它们。问题是,我想创造一个玩家可以移动的巨大世界(2000px乘2000x)的区域。但是,我希望他们一次只能看到600px到400x的屏幕。如果他们继续向前移动,我希望屏幕跟随他们,同样是向上,向下和向左。谁能告诉我怎么做?到目前为止,这是我的代码:

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

    }
}

2 个答案:

答案 0 :(得分: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;

        }
    }
}

答案 1 :(得分: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)位置绘制地图,即将这些地图添加到要绘制的对象的原始位置。

您可能希望跳过不可见的渲染对象。