现在的位置: 首页 > 综合 > 正文

《XNA高级编程:Xbox 360和Windows》4-5

2012年05月25日 ⁄ 综合 ⁄ 共 4761字 ⁄ 字号 评论关闭

4.5 Tetris,Tetris,Tetris!


     关于辅助类和游戏组件已经讨论很多了,现在我们就来编写一个很酷的游戏。正是借助于这些辅助类,在这个新的游戏中,我们才能非常容易地在屏幕上输出文本,绘制
sprites,处理用户输入以及播放声音特效。

     在深入到Tetris游戏逻辑细节之前,仔细考虑一下游戏元素的布置会很有帮助,就像您在前几章所做的那样。起初我们并不是把所有的游戏组件都输出到屏幕上,而是只显示背景边框,看看即将输出那些内容。这里的背景再一次沿用之前的太空背景图(我保证,这将是最后一次)。背景边框是一个新的素材,并且有两种显示模式(如图4-7所示)。它用来区分不同的游戏组件,这样可以让这些组件输出到屏幕上更好看。由于左右两边的显示尺寸不一样,如果使用同一个素材的话会很难看,所以需要把该素材修改成不同的尺寸来使用。

图4-7

4-7

渲染背景

     此处再次使用SpriteHelper类来渲染这些背景边框,并使用下面的单元测试:

public static void TestBackgroundBoxes()
{
    TestGame.Start(
"TestBackgroundBoxes",
        
delegate
        
{
            
// Render background
            TestGame.game.background.Render();
            
// Draw background boxes for all the components
            TestGame.game.backgroundBigBox.Render(new Rectangle(
                (
512 - 200- 1540 - 12400 + 23, (768 - 40+ 16));
            TestGame.game.backgroundSmallBox.Render(
new Rectangle(
                (
512 - 480- 1540 - 10290 - 30300));
            TestGame.game.backgroundSmallBox.Render(
new Rectangle(
                (
512 + 240- 1540 - 10290 - 30190));
        }
);
}
 // TestBackgroundBoxes()


     该测试的输出如图
4-8所示:

图4-8

4-8

     您可能会问为什么右边的边框小一些,而且这些值是如何取得的。其实这里的值都是随意定义的,它们会在最终的游戏里做最合理的调整。First, the background is drawn in the unit test because you will not call the Draw method of TetrisGame if you are in the unit test (otherwise the unit tests won’t work anymore later when the game is fully implemented).

     左上角的区域用来显示下一个要显示的方块,中间的区域用来显示Tetris网格,右上角的区域用来显示记分板。

处理网格

     现在我们来填充上述边框的内容。首先从主要组件TetrisGrid开始,它负责显示整个游戏的网格区域。它还处理用户的输入、移动下落的方块以及显示所有既有的数据。在讨论游戏组件的小节中已经说了TetrisGrid类使用了哪些方法,在渲染网格之前您应该检查一下该类定义的一些常量:

Constants


     还有很多其它有趣的常量,不过现在您只需要网格的尺寸,这里定义了
12列和20行。借助于Block.png素材(就是一个正方形方块),您可以很方便地在Draw方法中绘制出完整的网格区域:

// Calc sizes for block, etc.
int blockWidth = gridRect.Width / GridWidth;
int blockHeight = gridRect.Height / GridHeight;
for (int x = 0; x < GridWidth; x++)
    
for (int y = 0; y < GridHeight; y++)
    
{
        game.BlockSprite.Render(
new Rectangle(
             gridRect.X 
+ x * blockWidth,
             gridRect.Y 
+ y * blockHeight,
             blockWidth 
- 1, blockHeight - 1),
             
new Color(606060128)); // Empty Color
    }
 // for for


     其中变量
gridRect是在主类中传递过来的,用来定义绘制网格的区域。它和背景边框使用的是同一个矩形区域,当然会稍微小一点点以便更好地填充背景。这里您首先要做的就是计算方块的宽度与高度,然后遍历数组,使用SpriteHelper.Render方法来绘制方块,并使用半透明黑色,来展现一个空的背景网格。如图4-9所示。正是因为使用了游戏组件,在单元测试中您都不用去写所有这些代码。单元测试只绘制了背景边框,然后调用TetrisGrid.Draw方法来显示结果(参见TestEmptyGrid单元测试)。

图4-9

4-9

方块类型

     在向网格上渲染东西之前,您需要考虑一下游戏中都将使用哪些种类的方块。标准的Tetris游戏有7种方块类型,它们都是由四块更小的方块彼此连接在一起组合而成的(如图4-10所示)。其中最受欢迎的当然是直线型的,因为它可以同时消去四行方块,而且得分也最多。

图4-10

4-10

     这些方块类型必须在TetrisGrid类中定义。方法之一就是使用枚举来定义所有可能的方块类型。该枚举还定义了空类型的方块,可以应用于整个网格,因为网格中的每一个小方格要么包含预定义方块的一个部分,要么为空。下面来看一下TetrisGrid类中定义的其它常量:

/// <summary>
/// Block types we can have for each new block that falls down.
/// </summary>

public enum BlockTypes
{
    Empty,
    Block,
    Triangle,
    Line,
    RightT,
    LeftT,
    RightShape,
    LeftShape,
}
 // enum BlockTypes
/// <summary>
/// Number of block types we can use for each grid block.
/// </summary>

public static readonly int NumOfBlockTypes =
            EnumHelper.GetSize(
typeof(BlockTypes));
/// <summary>
/// Block colors for each block type.
/// </summary>

public static readonly Color[] BlockColor = new Color[]
{
    
new Color( 606060128 ), // Empty, color unused
    new Color( 5050255255 ), // Line, blue
    new Color( 160160160255 ), // Block, gray
    new Color( 2555050255 ), // RightT, red
    new Color( 25525550255 ), // LeftT, yellow
    new Color( 50255255255 ), // RightShape, teal
    new Color( 25550255255 ), // LeftShape, purple
    new Color( 5025550255 ), // Triangle, green
}
// Color[] BlockColor
/// <summary>
/// Unrotated shapes
/// </summary>

public static readonly int[][,] BlockTypeShapesNormal = new int[][,]
{
    
// Empty
    new int[,] 0 } },
    
// Line
    new int[,] 010 }010 }010 }010 } },
    
// Block
    new int[,] 11 }11 } },
    
// RightT
    new int[,] 11 }10 }10 } },
    
// LeftT
    new int[,] 11 }01 }01 } },
    
// RightShape
    new int[,] 011 }110 } },
    
// LeftShape
    new int[,] 110 }011 } },
    
// LeftShape
    new int[,] 010 }111 }000 } },
}
// BlockTypeShapesNormal

     其中BlockTypes就是之前我们讨论的方块类型枚举,它包含了所有可能的类型,并用于NextBlock游戏组件中随机生成新方块。网格区域在开始时都被空类型的方块填充,网格的定义如下:

/// <summary>
/// The actual grid, contains all blocks,
/// including the currently falling block.
/// </summary>

BlockTypes[,] grid = new BlockTypes[GridWidth, GridHeight];

     另外,NumOfBlockTypes则向您展示了枚举类的好处,您可以很方便地知道BlockTypes枚举中有多少种类型。

     接下来为每种方块类型定义了颜色,这些颜色在生成NextBlock的预览时使用,也用于渲染整个网格。每一个小方格都包含一个方块类型,您可以把枚举类型转换为整型来方便地使用BlockColor

抱歉!评论已关闭.