简体   繁体   English

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

[英]Java - how do I resize my 2D Game?

I'm developing a 2D game but i get stuck on the resizing. 我正在开发2D游戏,但在调整大小时遇到​​问题。 So as you can see in the code below, I draw all the game things into a BufferedImage. 因此,如您在下面的代码中看到的那样,我将所有游戏内容都绘制到BufferedImage中。 After that i get the graphics from my JPanel and draw the image on it. 之后,我从JPanel获取图形并在其上绘制图像。

So my question is how can i resize my game now? 所以我的问题是我现在如何调整游戏大小? I think there are many possibilities: 1 would be that the image is just resizing with the jpanel as well and the other method could be that if you have a 2d world and you resize the frame, the game will be still in the same size but you can see now more of the 2d world, like that your viewing distance increased. 我认为有很多可能性:1可能是图像也只是使用jpanel调整大小,另一种方法可能是如果您拥有2D世界并且调整了框架的大小,那么游戏的大小仍然相同您现在可以看到更多的2d世界,就像您的观看距离增加了一样。

Does someone knows a solution for my code? 有人知道我的代码的解决方案吗?

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

Let's start with Graphics g2 = panel.getGraphics(); 让我们从Graphics g2 = panel.getGraphics();开始Graphics g2 = panel.getGraphics(); - This is not how painting is done in Swing. -这不是在Swing中完成绘画的方式。 Swing uses a passive rendering algorithm, this means that a paint cycle may occur at any time and for any reason, many of which are out of your control or knowledge. Swing使用被动渲染算法,这意味着绘画循环可能随时随地发生,并且出于任何原因,其中许多是您无法控制或不了解的。

Using your current approach, at best, you run the risk of the introducing flickering, as your rendering loop and Swing compete with each other or having partial updates due to a thread race condition between your thread and the EDT. 使用当前的方法,充其量冒着引入闪烁的风险,因为由于线程与EDT之间的线程竞争条件,渲染循环和Swing相互竞争或进行部分更新。

You should also never dispose of a Graphics context you did not create yourself, on some systems, this could actually prevent anything from been painted. 在某些系统上,也永远不要dispose没有创建自己的Graphics上下文,这实际上可能阻止任何内容的绘制。

Take a look at Painting in AWT and Swing , Performing Custom Painting and Concurrency in Swing for more details. 看看AWT和Swing中的 绘画在Swing中 执行自定义绘画并发以了解更多详细信息。

A simple solution would be to override the paintComponent method of a Swing component, like JPanel and perform your custom painting directly within it. 一个简单的解决方案是重写Swing组件(如JPanelpaintComponent方法,并直接在其中执行自定义绘制。 This allows you to not only ascertain the current size of the component, but the paintComponent method will be called automatically when the component is resized. 这样,您不仅可以确定组件的当前大小,而且可以在调整组件大小时自动调用paintComponent方法。

Swing components are double buffered by default, so you get that automatically for free 默认情况下,Swing组件是双缓冲的,因此您可以免费自动获得它

You could use a Swing Timer to act as the "game loop", updating the current state of the game and scheduling a repaint request with the RepaintManager , for example... 您可以使用Swing Timer充当“游戏循环”,例如,使用RepaintManager更新游戏的当前状态并安排repaint请求。

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

    }

}

If you want something that gives you more control over the rendering process, then you will need consider using something like a BufferStrategy . 如果您想要使您对渲染过程有更多控制的东西,则需要考虑使用诸如BufferStrategy类的东西。 This allows you to employee a active painting process, painting to the buffer when you want to, without fear of some other thread painting to it as well. 这使您可以进行主动的绘画过程,在需要时绘画到缓冲区,而不必担心其他线程绘画。

See BufferStrategy and BufferCapabilities for more details 有关更多详细信息,请参见BufferStrategy和BufferCapabilities

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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