Selecting Game Character
After creating the main menu screen, you are probably an expert at this. The code is simple, and encapsulated, and it should be easy to create a new UI screen. This screen will be at least slightly different than the last one, mainly because not only do you render the UI, but you also need to render the character model. Before you get to that, however, you should add the class in Listing 6.7 to your UiScreen.cs code file.
Listing 6.7. The Character Selection Screen
///
/// The screen to select the Loopy character
///
public class SelectLoopyScreen : UiScreen, IDisposable
{
private Texture buttonTextures = null;
private Texture messageTexture = null;
private UiButton okButton = null;
private UiButton leftButton = null;
private UiButton rightButton = null;
// Events
public event EventHandler Selected;
///
/// Clean up in case dispose isn't called
///
~SelectLoopyScreen()
{
Dispose();
}
///
/// Clean up any resources
///
public override void Dispose()
{
GC.SuppressFinalize(this);
if (messageTexture != null)
{
messageTexture.Dispose();
}
messageTexture = null;
base.Dispose();
}
}
Obviously, this code looks relatively familiar, so there is no need to go through it again. The only major differences between this and your previous UI screen are the number of buttons (four instead of two) and the fact that the buttons' texture isn't cleaned up in the Dispose implementation. The buttons' texture isn't cleaned up here because the Yes button is shared between this screen and the quit screen. Rather than create two instances of the same texture, which wouldn't be efficient, you create only one, in the game engine. Because the game engine creates the texture, the game engine is responsible for ensuring that it's cleaned up properly.
Before you write the constructor for this class, you should add some more variables, mainly to hold the character mesh. Add these now:
private Mesh loopyMesh = null;
private Texture loopyTexture = null;
private Material loopyMaterial;
private Device storedDevice = null;
private PlayerColor loopyColor = PlayerColor.Min;
The character's representation consists of the mesh (which holds all the geometry data), the texture (which determines the character's color), and the material. You've seen each of these before when you were loading and rendering your sky box, but this part is loaded slightly differently. Because switching to a different version of Loopy will in reality simply update the texture the model is currently using, you need a reference to the rendering device, which is why you need to store one. The last type you haven't even created yet, but it is essentially going to be an enumeration that contains the possible colors of Loopy. Add a new code file to your project called player.cs now, and add the code in Listing 6.8 to this new code file to declare this enumeration.
Listing 6.8. The Player Colors
///
/// The color of the player model
///
public enum PlayerColor
{
Blue,
Green,
Purple,
Red,
Gray,
Yellow,
Min = Blue,
Max = Yellow,
}
Aside from the colors that Loopy can be, you'll also notice Min and Max items in the enumeration. These values are used to determine when you've made it to one "edge" of the enumeration to enable wrapping. For example, if you're currently on Blue and you scroll left, you want to go to Yellow, and scrolling right from there gets you back to Blue. Back in your SelectLoopyScreen class, add the constructor in Listing 6.9.
Listing 6.9. Creating the Select Loopy Screen
public SelectLoopyScreen(Device device, Texture buttons, int width, int height)
: base(device, width, height)
{
// Store the device for texture creation
storedDevice = device;
// Store the textures for the buttons
buttonTextures = buttons;
// Create the loopy mesh
loopyMesh = Mesh.FromFile(GameEngine.MediaPath + "Loopy.x",
MeshFlags.Managed, device);
// Create the loop texture
CreateTexture(device);
// Create a material
loopyMaterial = new Material();
loopyMaterial.Diffuse = loopyMaterial.Ambient = Color.White;
// Create the texture for the background
messageTexture = TextureLoader.FromFile(device, GameEngine.MediaPath +
"Select.png");
StoreTexture(messageTexture, width, height / 2, true);
// Create the ok button
okButton = new UiButton(renderSprite, buttonTextures, buttonTextures,
new Rectangle(SmallButtonWidth,SmallButtonHeight * 3,
SmallButtonWidth,SmallButtonHeight),
new Rectangle(0,SmallButtonHeight * 3,
SmallButtonWidth,SmallButtonHeight),
new Point((width - SmallButtonWidth) / 2,
height - (SmallButtonHeight * 2)));
okButton.Click += new EventHandler(OnSelectButton);
// Create the yes/no buttons
leftButton = new UiButton(renderSprite, buttonTextures, buttonTextures,
new Rectangle(SmallButtonWidth,0,SmallButtonWidth,SmallButtonHeight),
new Rectangle(0,0,SmallButtonWidth,SmallButtonHeight),
new Point(SmallButtonWidth / 2,
height - (SmallButtonHeight * 2)));
leftButton.Click += new EventHandler(OnLeftButton);
rightButton = new UiButton(renderSprite, buttonTextures, buttonTextures,
new Rectangle(SmallButtonWidth,SmallButtonHeight * 1,
SmallButtonWidth,SmallButtonHeight),
new Rectangle(0,SmallButtonHeight * 1,
SmallButtonWidth,SmallButtonHeight),
new Point(width - (SmallButtonWidth + (SmallButtonWidth / 2)),
height - (SmallButtonHeight * 2)));
rightButton.Click += new EventHandler(OnRightButton);
}
First, you take the rendering device and the texture for the buttons and store them for later use. Once that's done, you can create the mesh for Loopy. Notice that when you call the method this time, you're not using the overload that returns the materials. Although it is possible to use this method here as well, because you switch the character's texture at will and define your own material, it's really not necessary, so you might as well just skip it.
After you create the model for Loopy, you create a texture that defines his overall color; however, you also use this method for the Next and Previous buttons. You define the CreateTexture method to handle that in a few moments. You also want to ensure that you have a material for Loopy because you need to add lights to this scene before you're done. Materials define how the lights interact with the object. Because you want Loopy to have the light affect him "normally," you set the material to a simple white material.
The background texture for this user screen is slightly different as well. After it is created, notice that the StoreTexture method is called just as before, but there is one major difference in the call. You don't want the background image to interfere with the selection of Loopy, so you scale down the height of the window when you pass it to this method to only the top half of the screen. The majority of the screen "real estate" displays Loopy when the user selects the one he or she wants.
The button creation is similar to the ones you did in the main screen earlier; you just change the source of the buttons and the locations onscreen and use the small button constants instead. Notice that the left button is in the bottom left of the screen and the right button is in the bottom right of the screen. The Yes button appears directly between them in the center of the screen.
|