您可能会问为什么右边的边框小一些,而且这些值是如何取得的。其实这里的值都是随意定义的,它们会在最终的游戏里做最合理的调整。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).
// 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(60, 60, 60, 128)); // Empty Color }// for for
/**////<summary> /// The actual grid, contains all blocks, /// including the currently falling block. ///</summary> BlockTypes[,] grid =new BlockTypes[GridWidth, GridHeight];
// Randomize block type and rotation currentBlockType = (int)nextBlock.SetNewRandomBlock(); currentBlockRot = RandomHelper.GetRandomInt(4); // Get precalculated shape int[,] shape = BlockTypeShapes[currentBlockType,currentBlockRot]; int xPos = GridWidth/2-shape.GetLength(0)/2; // Center block at top most position of our grid currentBlockPos =new Point(xPos, 0); // Add new block for ( int x=0; x<shape.GetLength(0); x++ ) for ( int y=0; y<shape.GetLength(1); y++ ) if ( shape[x,y] >0 ) { // Check if there is already something if (grid[x + xPos, y] != BlockTypes.Empty) { // Then game is over dude! gameOver =true; Sound.Play(Sound.Sounds.Lose); }// if else { grid[x + xPos, y] = (BlockTypes)currentBlockType; floatingGrid[x + xPos, y] =true; }// else }// for for if
// Try to move floating stuff down if (MoveBlock(MoveTypes.Down) ==false|| movingDownWasBlocked) { // Failed? Then fix floating stuff, not longer moveable! for ( int x=0; x<GridWidth; x++ ) for ( int y=0; y<GridHeight; y++ ) floatingGrid[x,y] =false; Sound.Play(Sound.Sounds.BlockFalldown); }// if movingDownWasBlocked =false;
// Check if we got any moveable stuff, // if not add new random block at top! bool canMove =false; for ( int x=0; x<GridWidth; x++ ) for ( int y=0; y<GridHeight; y++ ) if ( floatingGrid[x,y] ) canMove =true; if (canMove ==false) { int linesKilled =0; // Check if we got a full line for ( int y=0; y<GridHeight; y++ ) { bool fullLine =true; for ( int x=0; x<GridWidth; x++ ) if ( grid[x,y] == BlockTypes.Empty ) { fullLine =false; break; }// for if // We got a full line? if (fullLine) { // Move everything down for ( int yDown=y-1; yDown>0; yDown-- ) for ( int x=0; x<GridWidth; x++ ) grid[x,yDown+1] = grid[x,yDown]; // Clear top line for ( int x=0; x<GridWidth; x++ ) grid[0,x] = BlockTypes.Empty; // Add 10 points and count line score +=10; lines++; linesKilled++; Sound.Play(Sound.Sounds.LineKill); }// if }// for // If we killed 2 or more lines, add extra score if (linesKilled >=2) score +=5; if (linesKilled >=3) score +=10; if (linesKilled >=4) score +=25; // Add new block at top AddRandomBlock(); }// if
Move block#region Move block publicenum MoveTypes { Left, Right, Down, }// enum MoveTypes /**////<summary> /// Remember if moving down was blocked, this increases /// the game speed because we can force the next block! ///</summary> publicbool movingDownWasBlocked =false; /**////<summary> /// Move current floating block to left, right or down. /// If anything is blocking, moving is not possible and /// nothing gets changed! ///</summary> ///<returns>Returns true if moving was successful, otherwise false</returns> publicbool MoveBlock(MoveTypes moveType) { // Clear old pos for ( int x=0; x<GridWidth; x++ ) for ( int y=0; y<GridHeight; y++ ) if ( floatingGrid[x,y] ) grid[x,y] = BlockTypes.Empty; // Move stuff to new position bool anythingBlocking =false; Point[] newPos =new Point[4]; int newPosNum =0; if ( moveType == MoveTypes.Left ) { for ( int x=0; x<GridWidth; x++ ) for ( int y=0; y<GridHeight; y++ ) if ( floatingGrid[x,y] ) { if ( x-1<0|| grid[x-1,y] != BlockTypes.Empty ) anythingBlocking =true; elseif ( newPosNum <4 ) { newPos[newPosNum] =new Point( x-1, y ); newPosNum++; }// else if }// for for if }// if (left) elseif ( moveType == MoveTypes.Right ) { for ( int x=0; x<GridWidth; x++ ) for ( int y=0; y<GridHeight; y++ ) if ( floatingGrid[x,y] ) { if ( x+1>= GridWidth || grid[x+1,y] != BlockTypes.Empty ) anythingBlocking =true; elseif ( newPosNum <4 ) { newPos[newPosNum] =new Point( x+1, y ); newPosNum++; }// else if }// for for if }// if (right) elseif ( moveType == MoveTypes.Down ) { for ( int x=0; x<GridWidth; x++ ) for ( int y=0; y<GridHeight; y++ ) if ( floatingGrid[x,y] ) { if ( y+1>= GridHeight || grid[x,y+1] != BlockTypes.Empty ) anythingBlocking =true; elseif ( newPosNum <4 ) { newPos[newPosNum] =new Point( x, y+1 ); newPosNum++; }// else if }// for for if if ( anythingBlocking ==true ) movingDownWasBlocked =true; }// if (down) // If anything is blocking restore old state if ( anythingBlocking || // Or we didn't get all 4 new positions? newPosNum !=4 ) { for ( int x=0; x<GridWidth; x++ ) for ( int y=0; y<GridHeight; y++ ) if ( floatingGrid[x,y] ) grid[x,y] = (BlockTypes)currentBlockType; returnfalse; }// if else { if ( moveType == MoveTypes.Left ) currentBlockPos =new Point( currentBlockPos.X-1, currentBlockPos.Y ); elseif ( moveType == MoveTypes.Right ) currentBlockPos =new Point( currentBlockPos.X+1, currentBlockPos.Y ); elseif ( moveType == MoveTypes.Down ) currentBlockPos =new Point( currentBlockPos.X, currentBlockPos.Y+1 ); // Else we can move to the new position, lets do it! for ( int x=0; x<GridWidth; x++ ) for ( int y=0; y<GridHeight; y++ ) floatingGrid[x,y] =false; for ( int i=0; i<4; i++ ) { grid[newPos[i].X,newPos[i].Y] = (BlockTypes)currentBlockType; floatingGrid[newPos[i].X,newPos[i].Y] =true; }// for Sound.Play(Sound.Sounds.BlockMove); returntrue; }// else }// MoveBlock(moveType) #endregion
这里有三种类型的移动:向左、向右和向下,每种移动都放在单独的程序块中进行检测。在详细研究这个方法之前,有两点需要注意。首先,在方法之前定义了一个movingDownWasBlocked变量。使用该变量是为了加快检测方块是否落地的过程,它作为类级别的变量可以方便Update方法的调用(可能是若干帧之后),and make the gravity code you saw earlier update much faster than in the case when the user doesn’t want to drop the block down right here. 这是游戏非常重要的部分,因为如果每个方块落地时立即被固定,那么游戏会变得很难,并且随着游戏速度变快以及网格被填得越来越满,游戏的乐趣也就消失了。