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

1.3 使用主动渲染

前面的示例使用了一种叫做被动渲染(passive rendering)的技术。该应用程序在paint()方法中重新绘制自身,但是,由Swing库来决定什么时候调用该方法。事件分派线程处理Swing组件的渲染,而这并不由你来控制。尽管这对于常规应用程序来说很好,但对于游戏不推荐这么做。

要处理渲染,可以使用BufferStrategy类,但这需要对应用程序的结构做一些修改。这将允许应用程序把渲染代码放在一个单独的线程中,并且由整个进程来控制。

把游戏代码放在paint()方法之外,通常有3个理由。首先,在paint()方法中不应该有任何需要很长的执行时间或阻塞时间的代码,因为这会阻止GUI接受绘制事件。其次,要使用全屏独占模式的话,渲染代码需要在一个不同的线程中。最后,并且也是最重要的原因,当从头开始处理绘制的时候,渲染代码会更快一些。为了利用主动渲染的好处,不管是在窗口还是全屏模式下,都要创建一个定制的渲染线程。

正如你在第一个示例中看到的那样,没有什么实用的方法将绘制代码放入到一个JPanel绘制方法中,却从定制的渲染线程调用该代码。为了在一个定制的循环中处理绘制,我们可以使用BufferStrategy类。这个类用来执行双缓冲(double-buffering)和页交换模式(page-flipping)。

如图1.2所示,双缓冲用来避免在进行绘制的时候,看到一幅图像的实际绘制过程。在内存中绘制图像,然后一次性复制整个图像,这样,绘制的过程就不会被看到。

可以在全屏独占模式下使用的页交换模式也采用了同样的思路,但是,它保持了两个离屏图像,并且直接从一个缓冲到另一个缓冲交换视频指针。通过这种方式,没有绘制到屏幕上的那个图像,可以被清除并重绘。当绘制完成的时候,指针再次交换,将新的图像绘制到屏幕上,如图1.3所示。

通过使用BufferStrategy类,程序是全屏模式并使用页交换模式,还是程序是窗口模式并使用双缓冲,都无关紧要了——这些技术都会在幕后处理。为了在一个渲染循环中使用BufferStrategy,用getDrawGraphics()方法创建一个图形对象。这个图形对象将会绘制到离屏表面。一旦这个图形对象变得可用,它的使用方法完全像传入到JPanel类的paint()方法中的图形对象一样。

调用contentsLost()来确保离屏表面可用,这一点也是很重要的。一些操作系统允许用户通过Alt-Tab方式离开全屏应用程序,这会导致离屏图像变得不可用。

show()方法执行双缓冲/图像复制或者页交换模式/指针交换来显示图像。注意,这段代码包含在try/finally语句块中。和其他绘制代码不同,因为这个图形对象已经创建了,所以当渲染循环完成的时候,必须要丢弃它。不调用Graphics.dispose()方法的话,将会导致内存泄露以及程序崩溃。

应当总是确保调用dispose()来清理图形对象。

// The bs object is a BufferStrategy object, and
// will be explained later in the chapter
public void gameLoop() {
    do {
      do {
        Graphics g = null;
        try {
          g = bs.getDrawGraphics();
          g.clearRect( 0, 0, getWidth(), getHeight() );
          render( g );
        } finally {
          if( g != null ) {
            g.dispose();
          }
        }
      } while( bs.contentsRestored() );
      bs.show();
    } while( bs.contentsLost() );
时间: 2024-08-02 12:00:57

《Java 2D游戏编程入门》—— 1.3 使用主动渲染的相关文章

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

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

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

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

《Java 2D游戏编程入门》—— 1.7 全屏显示模式中的主动渲染

1.7 全屏显示模式中的主动渲染 位于javagames.render包中的FullScreenRenderingExample,包含了主动渲染框架和切换到全拼模式的显示模式代码:它创建了一个简单的全屏游戏框架.这个示例包含了前面各部分中展示的很多代码.此外还可以直接给JFrame设置背景颜色并且忽略重绘,以及设置setUndecorated()标志.由于在前面的示例中应用程序是从窗口模式切换到全屏模式的,因此没有设置该标志:但是当只使用全屏模式的时候,应该对JFrame进行该项设置. 保存当前

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

1.4 创建定制的渲染线程 除了使用前面的代码来执行定制的渲染外,还需要一个定制的渲染线程.为了只是关注线程问题,位于javagames.render包中的RenderThreadExample实际上不会在屏幕上绘制任何内容,它只是在渲染代码应该出现的地方打印出"Game Loop".下面的示例将RenderThreadExample和前面的代码组合起来,创建了一个主动渲染的应用程序. 在RenderThreadExample中,首先需要注意的是,它实现了一个可运行的接口.这个可运行的

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

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

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

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

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

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

《Java 2D游戏编程入门》—— 2.1 处理键盘输入

2.1 处理键盘输入 在大多数应用程序中,软件都不需要处理键盘事件.当某些事情发生变化的时候,由任意的组件(如文本框)来处理输入并通知软件.但是,大多数计算机游戏使用键盘不是为了录入,而是为了游戏输入.根据游戏的不同,虽然可能会有录入,但键盘按键常用做方向键和发射激光武器.很多计算机游戏具有不同的输入配置,并且有些游戏甚至允许用户根据自己的意愿来设置按键.不管游戏如何使用键盘(并且它可能采用一种全新的方式来使用键盘,监听键盘事件的常用方法都不适用于游戏循环程序设计. Swing组件允许在实现了K

《Java 2D游戏编程入门》—— 8.5 原型Bullet类

8.5 原型Bullet类 PrototypeBullet代码位于javagames.prototype包中,这是一个最简单的原型游戏源代码.除了绘制圆以便可以调整屏幕大小外,没有其他任何值得讨论的内容. package javagames.prototype; import java.awt.*; import javagames.util.*; public class PrototypeBullet { private Vector2f velocity; private Vector2f