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

Java-如何调整2D游戏的大小?,java,resize,components,Java,Resize,Components,我正在开发一个2D游戏,但我在调整尺寸方面遇到了困难。正如您在下面的代码中所看到的,我将所有游戏内容绘制到一个BuffereImage中。之后,我从我的JPanel获取图形并在上面绘制图像 所以我的问题是我现在如何调整我的游戏?我认为有很多可能性:1是图像也可以用jpanel调整大小,另一种方法是,如果你有一个2d世界,你可以调整框架大小,游戏的大小仍然相同,但你现在可以看到更多的2d世界,就像你的观看距离增加了一样 有人知道我的代码的解决方案吗 package de.avarion.theen

我正在开发一个2D游戏,但我在调整尺寸方面遇到了困难。正如您在下面的代码中所看到的,我将所有游戏内容绘制到一个BuffereImage中。之后,我从我的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();       
    }   
}

让我们从
Graphics g2=panel.getGraphics()开始-这不是在Swing中绘制的方式。Swing使用被动渲染算法,这意味着绘制周期可能会在任何时间出于任何原因发生,其中许多都超出了您的控制或知识范围

使用当前的方法,最多只能冒引入闪烁的风险,因为渲染循环和Swing相互竞争,或者由于线程和EDT之间的线程竞争条件而进行部分更新

您也不应该
处理
非自己创建的
图形
上下文,在某些系统上,这实际上可能会阻止绘制任何内容

请查看,并获取更多详细信息

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

Swing组件在默认情况下是双缓冲的,所以您可以免费自动获得它

您可以使用Swing
计时器
作为“游戏循环”,更新游戏的当前状态,并使用
重新绘制管理器
安排重新绘制请求,例如

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

    }

}
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.EventQueue;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.Timer;
导入javax.swing.UIManager;
导入javax.swing.UnsupportedLookAndFeelException;
公开课考试{
公共静态void main(字符串[]args){
新测试();
}
公开考试(){
invokeLater(新的Runnable(){
@凌驾
公开募捐{
试一试{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(ClassNotFoundException |实例化Exception | IllegalacessException |不支持ookandfeelException ex){
例如printStackTrace();
}
JFrame=新JFrame(“测试”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(newtestpane());
frame.pack();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
});
}
公共类TestPane扩展了JPanel{
私人int XPO、YPO;
私有int xDelta=2;
公共测试窗格(){
计时器计时器=新计时器(40,新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
intx=(int)(getWidth()*0.1);
int y=(int)(getHeight()*0.1);
int width=getWidth()-(x*2);
int height=getHeight()-(y*2);
xPos+=xDelta;
yPos=y+((高度-5)/2);
如果(xPos+10>x+宽度){
xPos=x+(宽度-10);
xDelta*=-1;
}否则如果(xPos

如果你想让你对渲染过程有更多的控制,那么你需要考虑使用像A这样的东西。这使您可以执行一个活动的绘制过程,在需要时绘制缓冲区,而不必担心其他线程也会绘制缓冲区


有关更多详细信息,请参见:panel.getGraphics();这不是秋千上绘画的方式。而是重写组件的paintComponent方法,当系统调用时,执行正在绘制的操作。Swing使用被动绘制过程,因此在没有直接交互或知识的情况下,您可以随时绘制组件。调用时,您希望更新组件的当前状态。感谢您的回复,我不是java专家,但我会努力保持覆盖jpanels绘制方法的方式编辑:哈哈,很好:D现在我使用JPanel中的paintComponent方法,调整大小可以很好地工作,无需编写任何其他代码!!:D