Java - 如何调整2D游戏的大小?

时间:2015-07-09 19:57:24

标签: java resize components

我正在开发一款2D游戏,但我对调整大小感到困惑。因此,您可以在下面的代码中看到,我将所有游戏内容绘制成BufferedImage。之后,我从我的JPanel获取图形并在其上绘制图像。

所以我的问题是我现在如何调整游戏大小?我认为有很多可能性:1就是图像只是用jpanel调整大小,另一种方法可能是如果你有一个2d世界并且你调整框架大小,游戏仍将保持相同的大小但是你现在可以看到更多的2D世界,就像你的观看距离增加一样。

有人知道我的代码的解决方案吗?

package de.avarion.theenchanter;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Game implements Runnable{

    public static int WIDTH = 800;
    public static int HEIGHT = 600;
    public static int FPS = 30;

    private JFrame frame;
    private JPanel panel;

    private BufferedImage image;
    private Graphics2D g;

    private Thread thread;
    private boolean running


    public Game() {
        panel = new JPanel();
        panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
        panel.setFocusable(true);
        panel.requestFocus();

        frame = new JFrame("The Enchanter - pre Alpha");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(panel, BorderLayout.CENTER);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setResizable(true);
        frame.setVisible(true);

        image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        g = (Graphics2D) image.getGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        running = true;

        thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() { //game loop
        while(running) {
            update();
            render();
            try {
                Thread.sleep(1000/FPS);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    private void update() {
        if(frame.getWidth() != WIDTH || frame.getHeight() != HEIGHT) {
            frame.pack();
        }
    }

    private void render() {
        g.setColor(Color.black);//drawing on my image
        g.fillRect(0, 0, WIDTH, HEIGHT);

        Graphics g2 = panel.getGraphics(); // get graphics from panel
        g2.drawImage(image, 0, 0, null); //drawing on my panel
        g2.dispose();       
    }   
}

1 个答案:

答案 0 :(得分:0)

让我们从Graphics g2 = panel.getGraphics();开始 - 这不是在Swing中完成绘画的方式。 Swing使用被动渲染算法,这意味着绘制周期可能随时出现,出于任何原因,其中许多都是您无法控制或知识的。

使用您当前的方法,充其量只会导致引入闪烁的风险,因为渲染循环和Swing相互竞争或由于线程与EDT之间的线程竞争条件而部分更新。

你也不应该dispose你自己没有创建的Graphics上下文,在某些系统上,这实际上可以防止任何内容被绘制。

请查看Painting in AWT and SwingPerforming Custom PaintingConcurrency in Swing了解详情。

一个简单的解决方案是覆盖Swing组件的paintComponent方法,如JPanel,并直接在其中执行自定义绘制。这使您不仅可以确定组件的当前大小,还可以在调整组件大小时自动调用paintComponent方法。

默认情况下,Swing组件是双缓冲的,因此您可以免费自动获取

您可以使用Swing Timer充当“游戏循环”,更新游戏的当前状态并使用repaint安排RepaintManager请求,例如..

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private int xPos, yPos;
        private int xDelta = 2;

        public TestPane() {
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    int x = (int) (getWidth() * 0.1);
                    int y = (int) (getHeight() * 0.1);
                    int width = getWidth() - (x * 2);
                    int height = getHeight()- (y * 2);

                    xPos += xDelta;
                    yPos = y + ((height - 5) / 2);

                    if (xPos + 10 > x + width) {
                        xPos = x + (width - 10);
                        xDelta *= -1;
                    } else if (xPos < x) {
                        xPos = x;
                        xDelta *= -1;
                    }

                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int x = (int) (getWidth() * 0.1);
            int y = (int) (getHeight() * 0.1);
            g2d.drawRect(x, y, getWidth() - (x * 2), getHeight() - (y * 2));
            g2d.setColor(Color.RED);
            g2d.drawOval(xPos, yPos, 10, 10);
            g2d.dispose();
        }

    }

}

如果你想要一些可以让你更好地控制渲染过程的东西,那么你需要考虑使用类似BufferStrategy的东西。这允许您雇佣一个活跃的绘画过程,在您想要的时候绘制到缓冲区,而不用担心其他一些线程绘制它。

有关详细信息,请参阅BufferStrategy and BufferCapabilities