《Java 2D游戏编程入门》—— 1.4 创建定制的渲染线程

1.4 创建定制的渲染线程

除了使用前面的代码来执行定制的渲染外,还需要一个定制的渲染线程。为了只是关注线程问题,位于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();
      }
    });
  }
时间: 2024-08-02 12:00:55

《Java 2D游戏编程入门》—— 1.4 创建定制的渲染线程的相关文章

《Java 2D游戏编程入门》—— 1.3 使用主动渲染

1.3 使用主动渲染 前面的示例使用了一种叫做被动渲染(passive rendering)的技术.该应用程序在paint()方法中重新绘制自身,但是,由Swing库来决定什么时候调用该方法.事件分派线程处理Swing组件的渲染,而这并不由你来控制.尽管这对于常规应用程序来说很好,但对于游戏不推荐这么做. 要处理渲染,可以使用BufferStrategy类,但这需要对应用程序的结构做一些修改.这将允许应用程序把渲染代码放在一个单独的线程中,并且由整个进程来控制. 把游戏代码放在paint()方法

《Java 2D游戏编程入门》—— 导读

前言 多年前,当我第一次将软件开发作为专业工作的时候,有人请我编写一个applet.那时候,我对于Java语言知道得并不多.在整个上学期间,我很广泛地使用C++.我确实用Java编写过一些代码,但认为它太慢并且是C++的没落版. 同时,我购买和阅读了很多可以接触到的游戏编程图书.我通读了一本关于人工智能的书,其中包含很多不错的示例,但它们都是用C++和DirectX编写的.由于忙着学习Java以便在工作中使用,我认为将示例转换为由Java编写可能是学习这门语言的一种好办法. 毕竟,Java游戏编

《Java 2D游戏编程入门》—— 8.1 创建一个多边形包装类

8.1 创建一个多边形包装类 制作一款2D太空飞船游戏时,首先要解决的大问题是,当飞船到达屏幕边缘时,会发生什么事情.一个解决方案是,将飞船保持在屏幕的中央,而移动其周围的环境.没有对加载文件的任何支持,也没有关卡编辑器的话,要做到这点似乎有点难.另一个选择是,当飞船到达屏幕边界的时候,将其弹回.这样做似乎显得很奇怪.第三种选择是,让飞船从一端到另一端折返.让我们采用第三种方法. 还有很多方法可以解决这一问题.一种方法是,让飞船完全离开屏幕,然后让其在另一端返回,如图8.1所示. 尝试这一想法似

《Java 2D游戏编程入门》—— 8.2 创建一个原型小行星

8.2 创建一个原型小行星 PrototypeAsteroid类位于javagames.prototype包中,它表示一个穿越太空的陨石.在创建的时候,使用了一个随机的速率和旋转.Java的随机数生成器只能返回0到1之间的浮点数,因此,要创建在任意范围内分布的随机数,需要一些额外的步骤.例如,要返回-3到7之间的随机数,应按照如下步骤进行. 1.用最大值减去最小值,计算随机数之间的差距. 2.生成从0到1的一个随机浮点数. 3.将随机数乘以差距值. 4.通过加上最小值来迁移范围. 这些步骤听起来

《Java 2D游戏编程入门》—— 8.3 创建一个原型编辑器

8.3 创建一个原型编辑器 现在是时候创建一些多边形了.尽管有可能可以猜到每个点,但要创建9个小行星形状,手动进行的话,工作量还是很大的.就像大多数程序一样,我也很懒.编写一个编辑器来创建多边形,这样会容易很多.位于javagames.prototype包中的PrototypeEditor,如图8.9所示. 如果模型存储为文件,它们将在运行时加载.然而,做这些事情所需的代码还没有介绍过,因此,编辑器将会作弊.当按下空格键的时候,编辑器会产生出能够粘贴到其他源文件中的代码.本书的第二部分将会介绍使

《Java 2D游戏编程入门》—— 1.2 创建Hello World应用程序

1.2 创建Hello World应用程序 图1.1所示的Hello World应用程序是第一个游戏窗口的示例.HelloWorldApp位于javagames.render包中.除了清除和重新绘制背景,这个窗口中不再渲染其他内容.HelloWorldApp扩展了JFrame类,这是Java的Swing库中一个顶级的窗口组件.这个应用程序包含一个FrameRate对象,该对象用来测量应用程序的帧速率. 由于Swing库不是线程安全的,因此你应该总是在Swing事件线程上创建并展示一个JFrame

《Java 2D游戏编程入门》—— 2.4 相对鼠标移动

2.4 相对鼠标移动 对于图2.3所示的当前的鼠标输入类来说,有一个问题.首先,它看上去似乎挺明显,但是,只有在鼠标位于窗口之中的时候,程序才接受鼠标事件.一旦鼠标离开了窗口,鼠标指针的坐标位置在应用程序中就变得不再有效.更为糟糕的是,在全屏模式中,当鼠标到达屏幕边缘的时候,它会直接停下来,而不会继续注册事件.根据应用程序的需要,可能需要相对鼠标移动.好在,更新鼠标输入类以支持相对鼠标移动并不难. RelativeMouseInput类位于javagames.util包中,构建于前面示例中的类的

《Java 2D游戏编程入门》—— 1.6 修改显示模式

1.6 修改显示模式 要创建全屏的应用程序,需要修改显示模式.DisplayModeTest如图1.4所示,它使用了Swing组件.这个示例也位于javagames.render包中.如果你还没有编写过任何的Swing程序,一些代码可能会看上去很陌生.有很多相关的图书和教程可供参考,并且如果要详细介绍Swing所提供的所有功能,需要比这本书更大的篇幅. 这个示例应用程序列出了所有可用的屏幕分辨率,这允许用户在全屏模式之间来回切换,以使用任何可用的显示模式.这个示例不仅展示了使用Swing组件编程

《Java 2D游戏编程入门》—— 2.3 处理鼠标输入

2.3 处理鼠标输入 SimpleMouseInput类位于javagames.util包中,它和前面小节中开发的键盘输入类非常相似.处理鼠标按键的方式与处理键盘按键的方式相同.实现MouseListener接口的类包含了如下的方法: mouseClicked(MouseEvent e) mouseEntered(MouseEvent e) mouseExited(MouseEvent e) mousePressed(MouseEvent e) mouseReleased(MouseEvent