我正在开发一款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();
}
}
答案 0 :(得分:0)
让我们从Graphics g2 = panel.getGraphics();
开始 - 这不是在Swing中完成绘画的方式。 Swing使用被动渲染算法,这意味着绘制周期可能随时出现,出于任何原因,其中许多都是您无法控制或知识的。
使用您当前的方法,充其量只会导致引入闪烁的风险,因为渲染循环和Swing相互竞争或由于线程与EDT之间的线程竞争条件而部分更新。
你也不应该dispose
你自己没有创建的Graphics
上下文,在某些系统上,这实际上可以防止任何内容被绘制。
请查看Painting in AWT and Swing,Performing Custom Painting和Concurrency 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