Listing 7.9. Controlling Blocks
///
/// Retrieve the block color
///
public BlockColor BlockColor
{
get { return colors[colorIndex]; }
}
///
/// Sets whether or not the block should pulse
///
public void SetBlockPulse(bool pulse)
{
shouldPulse = pulse;
}
///
/// Sets the current total time on a block
///
public void SetBlockTime(float totalTime)
{
time = totalTime;
}
///
/// Sets the block velocity after game over
///
public void SetBlockVelocity(Vector3 vel)
{
velocity = vel;
}
public void UpdateBlock(float elapsed)
{
// Update the block position based on velocity
Vector3 velocityFrame = velocity;
velocityFrame.Normalize();
velocityFrame.Scale(velocity.Length() * elapsed);
// Move the block
pos += velocityFrame;
}
You obviously need a way to get the color of any given block (which is used to check whether the level was completed), and you also want a way to set whether the block should "pulse." The blocks that are the incorrect color pulse slightly to give the player a visual cue about what blocks still need to be switched. You use the time variable to control the effect of the pulse.
When the game is over, you want all the blocks to "explode" away, to really let the user know he or she failed. You create this explosion by assigning a random velocity to the block. The UpdateBlock method uses a similar method to what you used when you moved the player around. The velocity is normalized and then scaled to the correct velocity based on the elapsed time. The position of the block is then updated with this new velocity. This method is called only after the game is over and only when the level was lost.
These methods all use some variables that haven't been declared yet, so declare them now:
private float time = 0.0f;
private bool shouldPulse = false;
private Vector3 velocity;
With all of this done, you still need a way to render the blocks. You will find the render method in Listing 7.10.
Listing 7.10. Rendering Blocks
///
/// Render the current box using instance settings
///
public void Draw(Device dev)
{
// Set the device's material to the color of this box
dev.Material = material;
// Move the box into position
if (shouldPulse)
{
float scaling = (float)Math.Abs(Math.Sin(time * MaxBoxScaleSpeed));
scaling *= MaxBoxScale;
float scaleFactor = 1.0f + scaling;
dev.Transform.World = Matrix.Translation(pos) * Matrix.Scaling(
scaleFactor, 1.0f, scaleFactor);
}
else
{
// Move the box into position
dev.Transform.World = Matrix.Translation(pos);
}
// Turn off any texture
dev.SetTexture(0, null);
// Draw the box
boxMesh.DrawSubset(0);
}
The rendering of the block is pretty easy to see. To ensure that the block is the correct color, you first set the material. Then you determine whether the block should pulse; if it shouldn'tit's easyyou simply translate the box into position. If the block is pulsing, though, there is a slight difference because you also scale the box. You achieve the pulse effect by quickly scaling the box between normal size and slightly larger using a standard sine wave. After the transformation is complete, you simply use the DrawSubset call to render the box.
The Block class is almost done; you have only one more thing left to do. You need a way to make the block move to the next color when it is stepped on. Include the method from Listing 7.11 in your class.
Listing 7.11. Selecting Next Block Color
public void SelectNextColor()
{
// Are we at the end, and can wrap? If so, reset the color index
if ((colorIndex == (colors.Length - 1)) && (canWrap))
{
// Reset color index
colorIndex = 0;
}
// Otherwise, if we're not at the end, increment the color index
else if (colorIndex != (colors.Length - 1))
{
// Increment color index since we haven't gotten to the last one yet
colorIndex++;
}
// Update material
SetBlockColor(colors[colorIndex]);
}
Here you need to first check whether the color can wrap. If it can, and your index is already on the last color in your list, simply reset the index back to the first. Otherwise, if you haven't made it to the last color in your list, simply increment your index to select the next color. If you are on the last color in your list and you can't wrap, you won't do anything. Next, call the SetBlockColor method to update the material for your block.
|