Pri*_*ank 0 java swing repaint game-loop graphics2d
我正在尝试学习如何使用 java 创建一个游戏循环并每秒绘制一个新屏幕一定次数。游戏循环工作正常,但是当我尝试使用 repaint() 调用paint方法时,未调用paint方法。这是我的代码:
import javax.swing.JButton;
import javax.swing.JComponent;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.awt.image.*;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class mainFrame extends Thread{
static boolean gameIsRunning = false;
MyCanvas2 myCanvas2 = new MyCanvas2();
static final int TARGET_FPS = 1;
static int x = 10;
static int y = 10;
static long startTime = 0;
static long elapsedTime = 0;
static long waitTime = 0;
public void createFrame(){
JFrame window = new JFrame("Out from Eden");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setBounds(30, 30, 700, 500);
window.setVisible(true);
gameIsRunning = true;
gameStart();
}
public void setGame(boolean game){
gameIsRunning = game;
}
public void gameStart(){
(new Thread(new mainFrame())).start();
}
public void run(){
while(gameIsRunning == true){
startTime = System.nanoTime();
myCanvas2.updateGame();
myCanvas2.renderGame();
elapsedTime = System.nanoTime() - startTime;
waitTime = (TARGET_FPS*10) - (elapsedTime / 1000000);
if (waitTime < 0) {
waitTime = 5;
}
try {
Thread.sleep(waitTime);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class MyCanvas2 extends JPanel{
private static int x = 100;
private static int y = 100;
static int i =0;
public void updateGame(){
}
public void renderGame(){
repaint();
System.out.println("Hello");
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.blue);
g2.drawString("Test", x,y);
System.out.println("Goodbye");
}
}
Run Code Online (Sandbox Code Playgroud)
Hello 被打印了很多次,但是 Goodbye 从来没有被调用过,这让我相信 Paint 方法从来没有被调用过。为什么重绘方法不会更新我的绘画方法?
你永远不会将你的 MyCanvas2 对象添加到任何东西,所以似乎没有任何东西被渲染,因此没有被绘制。因此,我的主要建议是将 MyCanvas2 JPanel 添加到您的 GUI 中,如果您想要它呈现的话。还:
createFrame(),因此永远不会创建 GUI(JFrame)——因此请确保您调用它。gameStart()方法, MainFrame 的一个实例方法会创建一个新的MainFrame 实例,这是一个危险且不必要的递归——不要这样做。其他方面的建议和注意事项:
paintComponent,而不是绘制,因为这会自动为您提供双缓冲,从而获得更流畅的动画/图形。repaint()并不能保证一定会完成一幅画,因为这只是一个建议。如果重绘请求堆积起来,例如由于处理繁重或等待时间太短,那么一些重绘请求将被忽略。例如这里使用 Swing Timer 并执行简单的动画:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class MainGui {
private static final int TIMER_DELAY = 100;
private static void createAndShowGui() {
// create our JPanel
MainGuiPanel mainPanel = new MainGuiPanel();
// and create our ActionListener for the Swing Timer
MyTimerListener myTimerListener = new MyTimerListener(mainPanel);
// create a JFrame
JFrame frame = new JFrame("Main Gui");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// add our JPanel to it
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true); // display the GUI
// create and start the Swing Timer
new Timer(TIMER_DELAY, myTimerListener).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
@SuppressWarnings("serial")
class MainGuiPanel extends JPanel {
private static final int PREF_W = 700;
private static final int PREF_H = 500;
private int textX = 0;
private int textY = 10;
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.drawString("Test", textX, textY);
System.out.println("Goodbye");
}
@Override
// make our GUI larger
public Dimension getPreferredSize() {
Dimension superSz = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSz;
}
int prefW = Math.max(superSz.width, PREF_W);
int prefH = Math.max(superSz.height, PREF_H);
return new Dimension(prefW, prefH);
}
public void moveText() {
textX++;
textY++;
repaint();
}
}
// ActionListener for Swing Timer that drives the game loop
class MyTimerListener implements ActionListener {
private MainGuiPanel mainGuiPanel;
public MyTimerListener(pkg.MainGuiPanel mainGuiPanel) {
this.mainGuiPanel = mainGuiPanel;
}
@Override
// this method gets called each time the timer "ticks"
public void actionPerformed(ActionEvent e) {
// make sure our GUI is not null and is displayed
if (mainGuiPanel != null && mainGuiPanel.isDisplayable()) {
// call method to animate.
mainGuiPanel.moveText(); // this method calls repaint
} else {
((Timer) e.getSource()).stop();
}
}
}
Run Code Online (Sandbox Code Playgroud)