我正在尝试在JFrame中制作游戏,但遇到了问题。我创建了一个由四个图像组成的对象。我的问题是,我如何在JFrame中绘制这个对象?
以下是代码:
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.*;
public class t4
{
static boolean running;
public static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public static double width = screenSize.getWidth();
public static double height = screenSize.getHeight();
public static int x = ( 250 );
public static int y = ( 150 );
public static final int sx = (int)width;
public static final int sy = (int)height;
public static void main( String[] args ) throws IOException, InterruptedException
{
Image ur = new ImageIcon("redBlock.gif").getImage();
Image ll = new ImageIcon("redBlock.gif").getImage();
Image ul = new ImageIcon("blueBlock.gif").getImage();
Image lr = new ImageIcon("blueBlock.gif").getImage();
// Create game window...
JFrame app = new JFrame();
app.setIgnoreRepaint( true );
app.setUndecorated( true );
// Add ESC listener to quit...
app.addKeyListener( new KeyAdapter()
{
public void keyPressed( KeyEvent e )
{
if( e.getKeyCode() == KeyEvent.VK_ESCAPE )
running = false;
if((e.getKeyCode()==KeyEvent.VK_LEFT)||(e.getKeyCode()==KeyEvent.VK_KP_LEFT))
x-=10;
if((e.getKeyCode()==KeyEvent.VK_RIGHT)||(e.getKeyCode()==KeyEvent.VK_KP_RIGHT))
x+=10;
if((e.getKeyCode()==KeyEvent.VK_UP)||(e.getKeyCode()==KeyEvent.VK_KP_UP))
y-=10;
if((e.getKeyCode()==KeyEvent.VK_DOWN)||(e.getKeyCode()==KeyEvent.VK_KP_DOWN))
y+=10;
}
});
// Get graphics configuration...
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
// Change to full screen
gd.setFullScreenWindow( app );
if( gd.isDisplayChangeSupported() )
{
gd.setDisplayMode(new DisplayMode( sx, sy, 32, DisplayMode.REFRESH_RATE_UNKNOWN ));
}
// Create BackBuffer...
app.createBufferStrategy( 2 );
BufferStrategy buffer = app.getBufferStrategy();
// Create off-screen drawing surface
BufferedImage bi = gc.createCompatibleImage( sx, sy );
// Objects needed for rendering...
Graphics graphics = null;
Graphics2D g2d = null;
Color background = Color.BLACK;
Random rand = new Random();
// Variables for counting frames per seconds
int fps = 0;
int frames = 0;
long totalTime = 0;
long curTime = System.currentTimeMillis();
long lastTime = curTime;
running = true;
while( running )
{
try
{
// wait(500);
// count Frames per second...
lastTime = curTime;
curTime = System.currentTimeMillis();
totalTime += curTime - lastTime;
if( totalTime > 1000 )
{
totalTime -= 1000;
fps = frames;
frames = 0;
}
++frames;
// clear back buffer...
g2d = bi.createGraphics();
g2d.setColor( background );
g2d.fillRect( 0, 0, sx, sy );
// draw some rectangles...
/* int r = 45;
int g = 232;
int b = 163;
g2d.setColor( new Color(r,g,b) );
int w = ( 250 );
int h = ( 150 );
g2d.fillRect( x+25, y+25, w, h );*/
if(y<775)
{
y++;
}
else
{
y=0;
}
// display frames per second...
g2d.setFont( new Font( "Courier New", Font.PLAIN, 12 ) );
g2d.setColor( Color.GREEN );
g2d.drawString( String.format( "FPS: %s", fps ), 20, 20 );
// Blit image and flip...
graphics = buffer.getDrawGraphics();
graphics.drawImage( bi, 0, 0, null );
graphics.drawImage(ur,x,y,null);
graphics.drawImage(ll,x+50,y+50,null);
graphics.drawImage(ul,x,y+50,null);
graphics.drawImage(lr,x+50,y,null);
if( !buffer.contentsLost() )
buffer.show();
}
finally
{
// release resources
if( graphics != null )
graphics.dispose();
if( g2d != null )
g2d.dispose();
}
}
gd.setFullScreenWindow( null );
System.exit(0);
}
public static void wait(int x) throws InterruptedException
{
Thread.currentThread().sleep(x);
}
}
我想创建一个包含图像ur,ll,ul和lr的对象,并能够在屏幕上绘制它。
答案 0 :(得分:6)
这是你应该做的:
javax.swing.JComponent
。paintComponent(Graphics)
。javax.swing.Timer
以管理帧速率。getPreferredSize()
。首先(根据DavidB的要求)我将解释为什么你应该做这些事情,然后我会告诉你如何
add
方法兼容(实际上,它属于Container
,但这并不重要)。如果你看the JavaDoc documentation for add
,你会发现它不会接受任何Object
;相反,它需要一个Component
(或其子类)的实例。 可以子类Component
而不是JComponent
,但Component
比AWing应用程序更适用于AWT应用程序。JComponent
,以便JFrame.add
接受它作为参数。JComponent
的子类化,你就需要实际告诉窗口管理器要绘制什么。您可以将绘图代码放在任何位置,但请记住,除非实际调用该方法,否则不会调用(使用)它。图形环境调用以启动绘制过程的方法称为paintComponent
*。如果覆盖此方法,则图形环境将调用您的自定义绘制代码
简而言之:覆盖paintComponent
,因为这是图形环境所关注的内容。repaint
方法指定的次数(每帧一次)。这是Swing计时器的要点。你给它一个代码块和几毫秒,它会在每次指定的间隔时间后运行该代码。getPreferredSize
允许您返回所需的任何大小,从而控制组件的大小。** getPreferredSize
,以便窗口管理器和图形环境能够正确地完成所有尺寸。 *实际上并没有paintComponent
被调用;它是paint
。但是,paint
方法会调用paintComponent
,paintBorder
和paintChildren
:
这种方法实际上将绘画作品委托给三个受保护的人 方法:paintComponent,paintBorder和paintChildren。他们&#39;再 按列出的顺序调用,以确保孩子出现在上面 组件本身。一般来说,组件及其子组件 不应该在分配给边框的insets区域中绘制。 子类可以像往常一样覆盖此方法。一个子类 只是想专门化UI(外观和感觉)代表的绘画 方法应该只覆盖paintComponent。
(来源:the JavaDoc)
**覆盖getPreferredSize
实际上并不能保证这是组件显示的大小。它仅指定应显示的大小。一些布局管理器会选择忽略它(例如BorderLayout)。但是,当您调用pack
来正确调整窗口大小时,它应根据此大小计算首选大小。
要使类扩展JComponent,只需将类签名更改为:
import javax.swing.JComponent;
public class MyGameDisplay extends JComponent {
...
}
paintComponent
您需要导入java.awt.Graphics
课程。请参阅此示例代码,了解如何使用paintComponent
:
import javax.swing.JComponent;
import java.awt.Graphics;
public class MyGameDisplay extends JComponent {
// Some code here
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // this line is crucial; see below
g.drawString(100,100,"Hello world");
}
}
注意:上面,我提到了在super.paintComponent
方法中调用paintComponent
的必要性。这样做的原因是它(除其他外)将清除您之前显示的所有图形。因此,例如,如果您的程序在屏幕上绘制一个圆圈,则除非您致电super.paintComponent
,否则图形的每次迭代都将包含前一个绘图中的圆圈轨迹。
Timer
要获得所需的FPS速率,请修改类以包含Swing计时器,如下所示:
// Include these imports:
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MyGameDisplay extends JComponent {
private Timer t;
public MyGameDisplay() {
ActionListener al = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
t = new Timer(1000 / 30 /* frame rate */, al);
t.start();
}
}
getPreferredSize
覆盖getPreferredSize
的原因是布局管理员知道如何正确调整容器大小。
虽然编写实际逻辑来计算大小可能很困难,但覆盖getPreferredSize
本身并不是很重要。这样做:
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400); // for example
}
完成所有操作后,您只需运行以下代码:
import javax.swing.JFrame;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame();
MyGameDisplay mgd = new MyGameDisplay();
frame.add(mgd);
frame.pack();
frame.setVisible(true);
}
}