XNA 4.0 Game Development by Example Beginner's Guide(Visual Basic Edition)
上QQ阅读APP看书,第一时间看更新

Time for action – updating GameBoard to support animated pieces

  1. In the declarations section of the GameBoard class, add three Dictionaries, shown as follows:
    Public FallingPieces As Dictionary(Of String, FallingPiece) = 
        New Dictionary(Of String, FallingPiece)
    Public RotatingPieces As Dictionary(Of String, RotatingPiece) = 
        New Dictionary(Of String, RotatingPiece)
    Public FadingPieces As Dictionary(Of String, FadingPiece) = 
        New Dictionary(Of String, FadingPiece)
  2. Add methods to the GameBoard class to create new falling piece entries in the Dictionaries:
    Public Sub AddFallingPiece(x As Integer, y As Integer,
                               type As String, verticalOffset As Integer)
        FallingPieces.Add(
            x.ToString() + "_" + y.ToString(),
            New FallingPiece(type, verticalOffset))
    End Sub
    
    Public Sub AddRotatingPiece(x As Integer, y As Integer,
                                type As String, clockwise As Boolean)
        RotatingPieces.Add(
            x.ToString() + "_" + y.ToString(),
            New RotatingPiece(type, clockwise))
    End Sub
    
    Public Sub AddFadingPiece(x As Integer, y As Integer, type As String)
        FadingPieces.Add(
            x.ToString() + "_" + y.ToString(),
            New FadingPiece(type, "W"))
    End Sub
  3. Add the ArePiecesAnimating() method to the GameBoard class:
    Public Function ArePiecesAnimating() As Boolean
        If (FallingPieces.Count +
            FadingPieces.Count +
            RotatingPieces.Count) = 0 Then
            Return False
        Else
            Return True
        End If
    End Function
  4. Add the UpdateFadingPieces() method to the GameBoard class:
    Public Sub UpdateFadingPieces()
        Dim RemoveKeys As Queue(Of String) = New Queue(Of String)
    
        For Each thisKey As String In FadingPieces.Keys
            FadingPieces(thisKey).UpdatePiece()
            If FadingPieces(thisKey).AlphaLevel = 0 Then
                RemoveKeys.Enqueue(thisKey)
            End If
        Next
    
        While RemoveKeys.Count > 0
            FadingPieces.Remove(RemoveKeys.Dequeue())
        End While
    End Sub
  5. Add the UpdateFallingPieces() method to the GameBoard class:
    Public Sub UpdateFallingPieces()
        Dim RemoveKeys As Queue(Of String) = New Queue(Of String)
    
        For Each thisKey As String In FallingPieces.Keys
            FallingPieces(thisKey).UpdatePiece()
            If FallingPieces(thisKey).VerticalOffset = 0 Then
                RemoveKeys.Enqueue(thisKey)
            End If
        Next
    
        While RemoveKeys.Count > 0
            FallingPieces.Remove(RemoveKeys.Dequeue())
        End While
    End Sub
  6. Add the UpdateRotatingPieces() method to the GameBoard class as follows:
    Public Sub UpdateRotatingPieces()
        Dim RemoveKeys As Queue(Of String) = New Queue(Of String)
    
        For Each thisKey As String In RotatingPieces.Keys
            RotatingPieces(thisKey).UpdatePiece()
            If RotatingPieces(thisKey).rotationTicksRemaining = 0 Then
                RemoveKeys.Enqueue(thisKey)
            End If
        Next
    
        While RemoveKeys.Count > 0
            RotatingPieces.Remove(RemoveKeys.Dequeue())
        End While
    End Sub
  7. Add the UpdateAnimatedPieces() method to the GameBoard class as follows:
    Public Sub UpdateAnimatedPieces()
        If (FadingPieces.Count = 0) Then
            UpdateFallingPieces()
            UpdateRotatingPieces()
        Else
            UpdateFadingPieces()
        End If
    End Sub

What just happened?

After declaring the three Dictionary objects, we have three methods used by the GameBoard class to create them when necessary. In each case, the key is built in the form X_Y, so an animated piece in column 5 on row 4 will have a key of 5_4. Each of the three Add... methods simply pass the parameters along to the constructor for the appropriate piece types, after determining the key to use.

When we begin drawing the animated pieces, we want to be sure that animations finish playing before responding to other input or taking other game actions (like creating new pieces). The ArePiecesAnimating() method returns true if any of the Dictionary objects contain entries. If they do, we will not process any more input or fill empty holes on the game board until they have completed.

The UpdateAnimatedPieces() method will be called from the game's Update() method and is responsible for calling the previous three different update methods (UpdateFadingPiece(), UpdateFallingPiece(), and UpdateRotatingPiece()) for any animated pieces currently on the board. The first line in each of these methods declares a Queue object called RemoveKeys. We will need this because Visual Basic does not allow you to modify a Dictionary (or List, or any of the similar generic collection objects) while a for each loop is processing them.

A Queue is yet another generic collection object that works like a line at the bank. People stand in a line and await their turn to be served. When a bank teller is available, the first person in the line transacts his/her business and leaves. The next person then steps forward. This type of processing is known as FIFO (First In, First Out).

Using the Enqueue() and Dequeue() methods of the Queue class, objects can be added to the Queue (Enqueue()), where they await processing. When we want to deal with an object, we Dequeue() the oldest object in the Queue, and handle it. Dequeue() returns the first object waiting to be processed, which is the oldest object added to the Queue.

Tip

Collection classes

The .NET Framework provides a number of different collection classes, such as the Dictionary, Queue, List, and Stack objects. Each of these classes provide different ways to organize and reference the data in them. For information on the various collection classes and when to use each type, see the following MSDN entry: http://msdn.microsoft.com/en-us/library/6tc79sx1(v=VS.100).aspx

Each of the update methods loops through all of the keys in its own Dictionary, and in turn calls the UpdatePiece() method for each key. Each piece is then checked to see if its animation has completed. If it has, its key is added to the RemoveKeys queue. After all of the pieces in the Dictionary have been processed, any keys that were added to RemoveKeys are then removed from the Dictionary, eliminating those animated pieces.

If there are any FadingPieces currently active, those are the only animated pieces that UpdateAnimatedPieces() will update. When a row is completed, the scoring tiles fade out, the tiles above them fall into place, and new tiles fall in from above. We want all of the fading to finish before the other tiles start falling (or it would look strange as the new tiles pass through the fading old tiles).

Fading pieces

In the discussion of UpdateAnimatedPieces(), we stated that fading pieces are added to the board whenever the player completes a scoring chain. Each piece in the chain is replaced with a fading piece.