java更改面板视野

java更改面板视野,java,swing,2d,Java,Swing,2d,我正在尝试创建一个简单的Java 2D物理游戏,而我目前遇到的问题是,我想不出一种方法来在飞船移动时将相机置于中心位置 我有船的模型作为面板宇宙中的一个组件,在主框架中。当前,面板显示从0、0到1000、1000的像素 我想发生的是,如果飞船向右移动10个像素,那么面板将显示10,0到1010,1000的像素,跟随飞船,但在帧中保持刚性 或者也许有更好的方法来达到类似的效果 这是我认为相关的部分: public class Main extends JFrame { public st

我正在尝试创建一个简单的Java 2D物理游戏,而我目前遇到的问题是,我想不出一种方法来在飞船移动时将相机置于中心位置

我有船的模型作为面板宇宙中的一个组件,在主框架中。当前,面板显示从0、0到1000、1000的像素

我想发生的是,如果飞船向右移动10个像素,那么面板将显示10,0到1010,1000的像素,跟随飞船,但在帧中保持刚性

或者也许有更好的方法来达到类似的效果

这是我认为相关的部分:

public class Main extends JFrame {

    public static void main(String[] args) {
        M = new Main(1000, 1000);

    }

    public Main(int width, int height) {
        boardWidth = width;
        boardHeight = height;
        FRAMERATE = 60;
        setSize(boardWidth, boardHeight);
        setTitle("space");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        createUniverse();
        createShip();
        runThreads();
    }

    private void createUniverse() {
        U = new Universe();
        U.setLayout(new BorderLayout());
        add(U, BorderLayout.CENTER);
    }

    private void createShip() {
        U.createShip();
    }

    private void runThreads() {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
        long lengthOfFrame = (long) (1000 / FRAMERATE);
        executor.scheduleAtFixedRate(new Input(U.getShip(), FRAMERATE), 0L, lengthOfFrame, TimeUnit.MILLISECONDS);
        executor.scheduleAtFixedRate(new UpdatePhysics(U.getObjects(), FRAMERATE), 0L, lengthOfFrame, TimeUnit.MILLISECONDS);
        executor.scheduleAtFixedRate(new RepaintFrame(this), 0L, lengthOfFrame, TimeUnit.MILLISECONDS);
        this.addKeyListener(new UserInput());
    }
}
这是固定此面板的JFrame:

public class Universe extends JPanel {

    public Universe() {
        setSize(Main.boardWidth, Main.boardHeight);
        setBackground(Color.BLACK);
        setVisible(true);
    }

    public void createShip() {
        ship = new Ship(new double[]{getWidth() / 2, getHeight() / 2});
        shipM = new ShipModel(ship);
        _objects = new MassiveObject[1];
        _objects[0] = ship;
        add(shipM, BorderLayout.CENTER);
    }
}
ShipModel只是由几个多边形表示的Java组件

框架是由Main中的线程绘制的,它基本上只是反复调用Main.repaint


我想这就是所有相关的部分。我对这个链接不好,以前从未发布过。

我的建议是走不同的路线,或者至少是稍微不同的路线

您肯定不想从图片中检索像素并在每一帧绘制新像素您将在每一帧绘制像素,但在每一次勾选中获取像素将降低速度

您可以从抽象描述中加载整个背景图像,然后根据按键移动背景图像的位置。这艘船总是在中间。背景图像的边缘是这个问题变得棘手的地方——这是一个需要解决的另一个挑战

还可以选择将背景图像分割为平铺,并相应地移动这些平铺

我已经完成了以上两个步骤,因为我希望背景图像非常大,所以只有在我以编程方式将其拆分为分片,存储在内存中并根据位置渲染每个分片后,它才会平滑地移动

就像我说的,如果你想让你的宇宙飞船移动到边缘,边缘是很棘手的。如果你只是在背景图像后面显示无限黑色,并且你不介意显示它,那么你可以保持相同的物理特性,只有屏幕的一半显示背景图像

总之,只需相应地移动框架/面板内的背景图像

您的问题不是非常清楚,链接到您的代码并不是解决堆栈溢出问题的好方法。最好在您的帖子中包含相关的代码段,使用如下反勾号:

这是代码,我用反勾号来包围它


这会使它在长时滚动。

考虑将背景图像放置在JScrollPane中,通过设置适当的滚动策略来删除滚动条:

scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
您可以通过调用

backgroundLabel.scrollRectToVisible(rect);
并根据按键更改此矩形的位置

例如:

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")
public class SideScroll extends JLayeredPane {
    public static final String BG_IMG_PATH = "https://upload.wikimedia.org/wikipedia/commons"
            + "/a/ad/Tomada_da_cidade_de_S%C3%A3o_Salvador_s%C3%A9culo_XVIII_%28panor%C3%A2mico%29.jpg";
    public static final String CAMEL_PATH = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/PEO-bactrian_camel.svg/200px-PEO-bactrian_camel.svg.png";
    private static final int PREF_W = 800;
    private static final int PREF_H = 650;
    protected static final int SCALE = 10;
    private JLabel backgroundLabel = new JLabel();
    JScrollPane scrollPane = new JScrollPane(backgroundLabel);
    private JLabel camelLabel = new JLabel();

    public SideScroll(Icon bgIcon, Icon camelIcon) {
        camelLabel.setIcon(camelIcon);
        camelLabel.setSize(camelLabel.getPreferredSize());

        JPanel camelPanel = new JPanel(new GridBagLayout());
        camelPanel.setOpaque(false);
        camelPanel.add(camelLabel);
        camelPanel.setSize(getPreferredSize());

        backgroundLabel.setIcon(bgIcon);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
        scrollPane.setSize(getPreferredSize());

        add(scrollPane, JLayeredPane.DEFAULT_LAYER);
        add(camelPanel, JLayeredPane.PALETTE_LAYER);

        setFocusable(true);
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int keyCode = e.getKeyCode();
                switch (keyCode) {
                case KeyEvent.VK_LEFT:
                    moveImg(-1, 0);
                    break;
                case KeyEvent.VK_RIGHT:
                    moveImg(1, 0);
                    break;
                case KeyEvent.VK_UP:
                    moveImg(0, -1);
                    break;
                case KeyEvent.VK_DOWN:
                    moveImg(0, 1);
                    break;
                default:
                    break;
                }
            }

            private void moveImg(int right, int down) {
                Rectangle rect = backgroundLabel.getVisibleRect();
                int x = rect.x + SCALE * right;
                int y = rect.y + SCALE * down;
                int width = rect.width;
                int height = rect.height;
                rect = new Rectangle(x, y, width, height);
                backgroundLabel.scrollRectToVisible(rect);
            }
        });

    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    private static void createAndShowGui() {
        Icon bgIcon = null;
        BufferedImage camel = null;
        Icon camelIcon = null;
        BufferedImage bgImg;
        try {
            URL bgImageUrl = new URL(BG_IMG_PATH);
            URL camelUrl = new URL(CAMEL_PATH);
            bgImg = ImageIO.read(bgImageUrl);
            camel = ImageIO.read(camelUrl);

            // make background one quarter the size because it's too big
            int imgW = bgImg.getWidth() / 4;
            int imgH = bgImg.getHeight() / 4;
            BufferedImage bgImage2 = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2 = bgImage2.createGraphics();
            g2.drawImage(bgImg, 0, 0, imgW, imgH, null);
            g2.dispose();
            bgIcon = new ImageIcon(bgImage2);

            // flip camel image so facing right
            imgW = camel.getWidth();
            imgH = camel.getHeight();
            BufferedImage camelImg = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB);
            g2 = camelImg.createGraphics();
            AffineTransform xform = AffineTransform.getTranslateInstance(imgW, 0);
            xform.scale(-1, 1);
            g2.drawImage(camel, xform, null);
            g2.dispose();
            camelIcon = new ImageIcon(camelImg);

        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }

        JFrame frame = new JFrame("SideScroll");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new SideScroll(bgIcon, camelIcon));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

为了对未来的读者有用,问题必须是独立的。外部链接可能会过时。请使用问题底部的“编辑”链接编辑您的问题,并直接在其中包含您的代码。我仔细查看了您的代码,并尝试在我的代码中实现相同的策略,但遇到了一些问题。将JPanel宇宙添加到JScrollPane中,但是当我设置ScrollBarPolicy时,JPanel由于未知原因不再可见。此外,反复调用船舶当前位置周围矩形上的scrollRectToVisible不会改变ScrollPane的视图。不知道我做错了什么。Thanks@john:答案已编辑。恐怕你上面的评论把我弄糊涂了。@john:注意我发布的代码的一个特殊属性:你可以复制并粘贴到你的IDE中运行它,它可以工作,然后你可以随意修改和测试它,因为它是有效的。我们无法对您的代码执行此操作,因为它有太多的依赖项,而我们没有这些依赖项。如果您仍然需要帮助,您将希望通过创建和发布您自己的问题作为问题的编辑来改进您的问题,我们可以运行、测试、修改和体验这些代码。这个程序将和我的一样小,不在链接中。