本节书摘来异步社区《Java 2D游戏编程入门》一书中的第1章,第1.4节,作者:【美】Timothy Wright(莱特),更多章节内容可以访问云栖社区“异步社区”公众号查看。
除了使用前面的代码来执行定制的渲染外,还需要一个定制的渲染线程。为了只是关注线程问题,位于javagames.render包中的RenderThreadExample实际上不会在屏幕上绘制任何内容,它只是在渲染代码应该出现的地方打印出“Game Loop”。下面的示例将RenderThreadExample和前面的代码组合起来,创建了一个主动渲染的应用程序。
在RenderThreadExample中,首先需要注意的是,它实现了一个可运行的接口。这个可运行的接口包含一个单个的方法,即public void run()。这个方法包含了渲染循环,并且它只调用一次。当它返回的时候,线程结束并且不能再次使用。为了防止run方法中的代码在程序完成之前退出,Boolean类型的running变量保持run方法重复运行。
private volatile boolean running;``` 注意,该变量的声明中带有volatile关键字。由于这个变量是一个基本类型,并且可以从多个线程中访问它,因此必须要告诉编译器总是从内存中读取该变量。没有使用volatile这个关键字的话,变量可能会被Java虚拟机(JVM)用一个缓冲值来进行优化,并且线程可能变得无法停止下来。 此外,注意RenderThreadExample中的sleep()方法,它用来将应用程序减慢到一个较为合理的运行速度。sleep()方法接受一个毫秒值,然后将自身挂起达到一定的时间,以允许其他的线程使用CPU。 一旦应用程序关闭了,渲染线程也应该停止。通过添加一个窗口监听器,程序可以响应窗口关闭事件。在这个例子中,程序调用onWindowClosing()。如果你的程序需要关闭那些不再需要的资源和文件,那么在这里做这些事情。app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { app.onWindowClosing(); }});`要关闭渲染线程,running变量应设置为false。然而,渲染线程可能只是读取running变量的值,并且进入睡眠。要确保该线程已经停止了,应调用join()方法。该方法将会等待,直到该线程结束,并且run方法已经返回。如果没有向join()方法传入一个超时值,将会在线程结束前造成阻塞,因此,如果没有提供超时值的话,请确保线程将会结束。
最后,必须通过手动调用System.exit(0)来关闭程序。之前,当在JFrame中设置JFrame.EXIT_ON_CLOSE标志的时候,程序将会结束。这时应用程序负责处理关闭,只有在调用了exit方法的时候,程序才会结束。如果应用程序在关闭后挂起,通常是因为程序员忘了调用System.exit()。
package javagames.render; import java.awt.event.*; import javax.swing.*; public class RenderThreadExample extends JFrame implements Runnable { private volatile boolean running; private Thread gameThread; public RenderThreadExample() { } protected void createAndShowGUI() { setSize( 320, 240 ); setTitle( "Render Thread" ); setVisible( true ); gameThread = new Thread( this ); gameThread.start(); } public void run() { running = true; while( running ) { System.out.println( "Game Loop" ); sleep( 10 ); } } private void sleep( long sleep ) { try { Thread.sleep( sleep ); } catch( InterruptedException ex ) { } } protected void onWindowClosing() { try { System.out.println( "Stopping Thread..." ); running = false; gameThread.join(); System.out.println( "Stopped!!!" ); } catch( InterruptedException e ) { e.printStackTrace(); } System.exit( 0 ); } public static void main( String[] args ) { final RenderThreadExample app = new RenderThreadExample(); app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { app.onWindowClosing(); } }); SwingUtilities.invokeLater( new Runnable() { public void run() { app.createAndShowGUI(); } }); } 相关资源:Java游戏编程入门