从该代码的最后两行可以看到,游戏区域的尺寸(7×15个宝石)包含在两个常量BOARD_
GEMS_ACROSS及BOARD_GEMS_DOWN中(它们将在后面的程序清单8-8中进行定义)。如果想修改游戏区域的尺寸,通过修改这两个常量可以很轻松地实现。
此代码看似简单,但它完成了一些非常重要的工作:它设置了一个抽象的坐标系。我们可以在屏幕上绘制宝石而不用考虑屏幕的分辨率,也不用考虑加载的是哪个图形集。要得到绘制宝石的坐标,只需要将坐标(_boardLeft, _boardTop)在x轴上的位置值乘以_gemWidth值,在y轴上的位置值乘以_gemHeight值即可。这种方式为我们省去了程序中不少复杂的计算。
8.2.4 创建宝石游戏对象
接下来,我们将注意力转移到GemDrops游戏所包含的两个游戏对象之一——宝石上。它在CObjGem类中实现,每个实例都代表了游戏中的一个宝石。宝石可能是安放在游戏区域中,可能是在玩家的控制中,甚至是显示在“Next piece”区域中,在后文中我们会讨论如何在这些不同的情形中使用该对象。
CObjGem类继承自GameEngine.CGameObjectGDIBase类。我们将向其中添加一些额外的属性,使我们能够按照自己的想法来配置宝石。目前我们感兴趣的属性如程序清单8-4所示。
程序清单8-4 CObjGem类的属性
// Our reference to the game engine
private CGemDropsGame _game;
// The color of this gem
private int _gemColor = 0;
// The X position within the board (in game units, so from 0 to 6)
private int _boardXPos = 0;
// The Y position within the board (in game units, so from 0 to 14)
private int _boardYPos = 0;
这些属性提供了我们需要的宝石的一些基本信息:它是什么颜色?它位于什么位置?在表示位置时使用的是游戏区域中的x坐标和y坐标,而不是像素坐标或类似的东西。
此外,还有一个对CGemDropsGame对象的强类型的引用,这样不需要转换成适当的类型就可以与它进行交互。
接下来是该类的构造函数。除了默认的构造函数之外,我们还想在创建该类的时候能指定宝石的位置和颜色,如程序清单8-5所示。注意,在这个重写中调用了默认的构造函数,而不是基类中的构造函数,所以最终还是将游戏引擎的引用存储到类级别的变量_game中。
程序清单8-5 CObjGem类的构造函数
/// <summary>
/// Constructor
/// </summary>
public CObjGem(CGemDropsGame gameEngine)
: base(gameEngine)
{
// Store a reference to the game engine as its derived type
_game = gameEngine;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="boardX">The x position for the gem</param>
/// <param name="boardY">The y position for the gem</param>
/// <param name="color">The color for the gem</param>
public CObjGem(CGemDropsGame gameEngine, int boardX, int boardY, int color)
: this(gameEngine)
{
_boardXPos = boardX;
_boardYPos = boardY;
_gemColor = color;
}
有一点需要注意的是,并非像在以前的例子中所做的那样在构造函数中设置Width或Height属性。稍后介绍这些属性的重写时就会看到这样做的原因。
宝石本来需要能够渲染自己。大多数情况下,宝石只需要设置一种颜色即可,我们将用图8-7中相应的宝石图形来渲染它。然而,彩虹宝石不停地循环变换颜色,这种效果使得它在其他普通的宝石中显而易见。如果宝石的颜色指示它是一个彩虹宝石(它的_gemColor为常量GEMCOLOR_RAINBOW),我们会每隔0.1秒执行一次渲染,渲染时采用不同的实际宝石颜色,Render函数的代码如程序清单