Let there be Light (and Sound)

Adding Music

Used Mario Paint Composer to create simple title music and stage music.  It really gives the game a classic feel, and it’s really easy to create great sounding tracks with the tool.  I spent about 30 minutes trying to record the audio from the desktop (tried Fraps, then tried connecting the audio jack output to the mic input), but I couldn’t get Audacity to record even though I saw activity from the mic input in the Control Panel sound control.  Finally, I just held my USB headset mic up against the PC speaker and recorded using Audacity.  The sound is a little muffled, but it does the job for now.  At first, I used Audacity export the music into MP3 format.  I did some research to see what what other formats XNA accepts, because I don’t want to risk the possibility of paying royalties for using MP3.

I’ve never had a formal class in music writing, but I was in the band for many years in high school, so this will be my first attempt at writing music for a game.   The GameBoy icon beeps make a nice sound, but I found that too many of them can get annoying, especially when the song is on a loop.  The GameBoys should be using sparingly, like sprinkles on a cupcake.  I found that the Piranha Plant, Coin, ShyGuy, and Boo make the most soothing sounds, so I’ll probably be using those the most.  On my stage 1 song, I have an intro and four melodies.  The intro has the most GameBoy beeps, then it is phased out in the later melodies.  Using the Arranger in Mario Paint Composer, the sequence I used looks like this:  Intro, Intro, Melody A, Melody A, Melody B (transition), Melody C, Melody C, Melody D, Melody D, Melody C, Melody D, Melody C, Melody D.

 

To be on the safe side, I went ahead and converted my raw music files to WAV using Audacity.  I can convert them to WMA later if needed.  I don’t want to run the risk of having to pay royalties by using the MP3 format.  One trick is that in the IDE you have to change the ContentProcessor of the WAV resource to Song, otherwise it will default to SoundEffect which will cause the program crash when it is played as a Song object.

Adding Lights/LEDs

Created the GamePieceLight class which subclasses the GamePiece class.  Currently, it just overrides the draw method, so that it draws a light (circle sprite) instead of a wire.  The lights are not playable pieces, meaning that the user can not place lights on the game board.  The lights are placed on the board at the start of the level.  Learned that you can’t just simply override a method by redefining it like in Java.  In order to override, the method in the superclass must be declared virtual, and the override keyword must be used when defining the method in the subclass.  After fixing those, I was able to add the light pieces by using the setPiece method in the constructor of the GameLevel class, for each light to be placed on the board.  The great thing about OO (object oriented) programming is that the light automatically inherits all of the properties of the GamePiece class, which was the basic wire.  Therefore, it automatically fills the adjacent wires just as a regular wire does, and its isFilled property is automatically set when the FILL_MAX value is reached.  In order to make these superclass instance variables accessible to the subclass, they must be declared protected instead of private.  This makes the variables visible to subclasses, but not visible to other classes.  Before the light is filled, I use White as the color parameter for drawing the light sprite.  Yellow is used as the color parameter when it is filled.  The maximum “bust” value for the light will be added later.

Adding Resistor Pieces

Added instance variables to the GameLevel class, which hold the currently selected piece and the maximum number of selectable pieces.  The current selected piece is initialized to zero (wire) and the maximum number of pieces is set to two.  In the future, I will just create a list or array of piece types, and derive the maximum value from the array length.  I am currently incrementing the selected piece value when the user presses the action button (default X).  If the selected piece value is greater than or equal to the number of pieces, then it is set back to zero.  In the future, I may have one button specifically for laying wires and another button for placing other pieces like resistors.  Changing the selected piece will also probably be handled by the shoulder buttons.  I have displayed the selected piece index on the game screen for now.  When the selected index is 1, then pressing the confirm button will lay down a 2-resistor.  I made the Elex variable in the superclass protected, so that I can subtract 2 from its value.  A method was created in the GamePiece called pieceFilled which is called when the piece’s fill value reaches the max value.  This method is overridden in the GamePieceResistor subclass, calling base.pieceFilled() first to set the filled boolean values in the superclass.  Then I subtract the Elex value in the sublcass, since that is specific to the GamePieceResistor subclass.  When the resistor is not filled, I use the Gray as the third color value in the blit method, giving the resistor a faded appearance.  When the resistor is filled, White is used as the color parameter which makes it appear brighter.  Currently, there is no check to see if the resistor will lower the Elex value below zero.  I could make it so that the flow stops when the flow gets to zero.

As the screenshot shows, the Elex value is lowered from 8 to 6 as it passes through the first resistor, because the 2-resistor lowers it by 2.  When it passes through the second resistor, it lowers again to 4.

Creamy Filling

(The video distortion clears up around 0:14)

Pause Problem

Noticed a problem that when the direction pad was pressed, sometimes the cursor would not move until the pad was pressed multiple times.  Increased the PAUSE_FRAMES to 360 (6 seconds at 60 fps) to make this obvious to help with debugging the problem.  The PAUSE_FRAMES constant is the number of frames to wait before moving the cursor again, if the directional button his held down.  The pause value should be set back to zero after a direction button is released, because the cursor should be moved immediately when the button is first pressed down.  As I mentioned in my previous post, the pause value is necessary to keep the cursor from zipping across the screen (moving one cell for each frame).

Used this article to add text to the game, which allowed me to print out the pause value.  Found that I needed to check if the velocity was non-zero before doing the bounds checking for moving the cursor.  The velocity should be non-zero if the cursor is moving.  An x velocity of -1 means the cursor is moving left and 1 means the cursor is moving right.  A y velocity of -1 means the cursor is moving up and -1 means the cursor is moving down.  When the pause value hits zero, then the velocities are added to the cursor’s row and column values.  The problem was that it was doing the bounds checking even if the velocity was zero, then moving the cursor using a zero velocity value, and then setting the pause value back to the PAUSE_FRAMES value.  Therefore, the pause value was continually being set back to the maximum value.  Fixing that problem, along with setting the pause value to zero on direction button released got the cursor working properly.  Set PAUSE_FRAMES value back to 10, so that it doesn’t wait 6 seconds to move the cursor when a direction button is held down.

Filling the Wires

Added a variable in the GameLevel class to track how many frames to wait until filling the first piece on the board.   Also added variables to define the start cell (where the flow begins) and end cell (must be connected to win).

Created new images for filled wires and resistors, which will be overlayed on top of the objects on the game board.  Hopefully, I can specify just a portion of the sprite to blit on top of the existing piece, so I can give the appearance of the piece filling, using the piece’s fill value.  I made these overlays white, so that I can programmatically change the color using the color parameter of the SpriteBatch draw method.  For now, I am just displaying the I-wire as the default piece, and I overlay the I-wire fill using the yellow parameter to designate a filled wire.  The starting piece is currently set to row 0 column 5.  I could change the starting location for each level, or make the starting location random.

 

I changed the SpriteFont variable to an array of SpriteFonts, so that multiple fonts can be easily defined and used.  Currently, I’m passing the SpriteBatch object, textures (sprite) array, and font array to each object that needs to draw itself.  It may have been simpler to just have those defined as public variables (or use getter methods) so that any object that needs to draw can obtain it from the main ResistorGame object.  However, then every object that needs to draw would need a reference to the ResistorGame object, so it may be more efficient to just create a GameContent object which holds all of the textures and fonts, which could be passed to each drawable object.

After I got the filling to work for the first piece, I had another decision to make.  Once a piece has been filled, should the piece call beginFill on its neighbors?  In order to do that, then the current piece would need a reference to all of the adjacent (neighbor) pieces.  Alternatively, the GameLevel could check for all pieces that have been filled, and then start filling the neighbors of those pieces.  In that case, the GameLevel would need to keep track of the filled/unfilled status of each piece before calling update.  That sounded like the simplest solution, so that is the approach that I took.  For testing purposes now, a piece will fill all of its neighbors (north, south, east, west).  I will start checking for the actual output side variables soon.  I created a fillAdjacentPieces method in the GameLevel class, which takes the current piece’s row and column as paramters, and begins filling the adjacent pieces.  Each piece now displays its fill value in green and Elex value in blue in the cell.  A check has also been added to ensure that a piece is not being added to a cell that is already occupied (not null).

 

After doing testing with the current setup, the game seemed really fun (to me at least) just laying the wires and seeing them fill.  The queue of pieces and rotating may be too complex, since this is supposed to be an educational game.  I’m now thinking that the player should just have a generic wire, and the wire will shape and split ifself as needed, based upon its neighbors (adjacent cells).  Think of how the roads in SimCity would “fix” their shape based on the layout of the road peices, so that the player didn’t have to worry about using curve or intersection pieces of road.  Just giving the player the ability to cycle through a wire and the available resistors may be the best way to implement this.  If it seems too simple in the end, then I can always add a piece queue or rotation after.  The action button or shoulder button can be used for selecting the component to place.

Changing Wire Images

Decided that the GameLevel class should determine the wire image to use for each piece, since it can find the adjacent cells for a specified cell.  Created wire images for each case.  I can rotate the I, T, and L wire images later for efficiency if needed, but for now each rotation is a separate image.  Created methods for accessing the piece to the north, south, east, and west of a specified cell, which handles all of the array bounds checking.  Using those methods, I created a method for returning the image ID that should be used for the piece at a specified cell based on the adjacent pieces.  This image ID is passed to the draw method of the piece.  Therefore, a piece never knows its image ID value because it is derived each time the board is drawn.  I did this because there are too many cases to handle to keep track of the adjacent cells in the GamePiece objects themselves.  I changed the color of the wire sprites to white, that way I could make them any color (including black) eliminating the need for separate filled and unfilled sprites.

 

Go With the Flow

Below are  flowcharts illustrating the main state transitions in the game.

The following flow chart shows the transitions in the main game loop.

Mobile Version

Due to the simplicity of the game, it may make a good mobile game.  I know I have more than enough screen real estate just at 640×480.  I’m not sure how difficult it would be to port the code to Andriod or iOS.  I know there is the capability to build a Windows Phone 7 app from the Visual C# Express IDE.

More GamePad Tweaks

Added code to handle the Start button press on the title screen, which currently just transitions to the game loop, just as the confirm button does.  I created a simple test on the title screen to display the X value of the left thumbstick.  This told me that it registers a float value between -1.0 and 0 when pressing the stick left, and between 0 and 1.0 when pressing the stick right.  I pressed the stick about half way left, and it displayed a value close to -0.5.  Therefore, I’m going to use 0.5 as a threshold for registering a directional press.  I know some of my older controllers will register a move when the stick is not moved, just because the controller is old.  When that happens, the controller is probably reporting a very small value (like 0.00001), but the game sees that as a non-zero value and will move whatever object is being controlled.  That’s why I believe there needs to be some threshold value defined, and not create an action until that threshold is passed.  Noticed that the Y axis is inverted from the standard screen coordinate system, so that pressing up on the stick actually returns a positive value and pressing down returns a negative value.

Egg Carton Problem

Piece Placement

Added a new GamePiece class to the project, which represents one of the components that can be placed on the board.  I intend for this class to be subclassed for each of the specific types of components (wires, resistors, etc).  The GameLevel class represents the game board and the piece queue.  I could have created a separate GameBoard class, but I decided otherwise since it is just a 2D array of GamePiece objects.  Each GamePiece has a fill value (how many frames until the flow goes to the adjacent cell(s)), an Elex value, and booleans for keeping track of which sides accept flow.   Author and date information have been added as a header comment in each of the code files.  It just looks odd not seeing the GPL there.

I had two alternatives.   I could have just created a list of pieces that have been placed on the board, having each piece know its row and column location on the board.  That is the method used in many 2D games, where each player and enemy knows its own x-y coordinate position.  The approach I took is creating the 2D array of pieces, which represent each cell on the board.  If a cell does not contain a piece, then null is stored for that array location.  I think the 2D array approach will work better when trying to determine the connections between wires.  It’s like Easter eggs in an egg carton.  There’s really no reason for each egg to know it’s x-y coordinate.  The egg carton just needs to know which egg goes into which slot.  The location of the egg can be derived by it’s slot in the egg carton, so it’s really redundant for each egg to also keep track of its position.  The 2D array approach shouldn’t be any more memory intensive, since storing null in a cell doesn’t require memory to be allocated.

Button Presses

Four new methods have been added to the GameLevel class:  confirmButtonPressed, cancelButtonPressed, actionButtonPressed, and optionButtonPressed.  These correlate to the A, B, X, and Y buttons on the XBox controller respectively.  I wanted to keep everything in the GameLevel class platform independent, and keep all of the platform specific code in the ResistorGame (formerly Game1) class.  This will make it easier if I want to add keyboard controls or give the user the ability to customize the controls.  Since this is a simple game, the confirm button will be used to drop a piece to the board, and the cancel and action buttons will be used to rotate the piece.  Resistors and I wires can only be rotated in two positions.  L wires (aka elbow wires) can be rotated in four positions.

XBox Testing

One difficulty that I’m having is that every time I want to test on the XBox (after it has been shut off), I have to Reset All Connections in the XNA Game Studio Connect and remove then re-add the XBox device in XNA Game Studio Device Center using the new code generated on the XBox.  I’m not sure if there is a way to keep from having to do this every time.

Adding Pieces to the Board

When the confirm button is pressed, I simply add a GamePiece object (just a new one for now) to the GamePiece array in the GameLevel class using the setPiece method, passing the piece, row, and column as parameter.  That method simply adds the passed-in piece to the game piece array at the specified row and column.  When the draw method is called, it loops through each cell in that array, and if it is not null (i.e. contains a piece), then it calls the draw method on the GamePiece object.  Since the GamePiece object will be subclassed, it should correctly draw whatever component it is.  For now, it just draws the regular tile using a red shade.  One problem that I had to fix was when the user held down the confirm button, then it would continually drop pieces to the board until that button is released.  Therefore, I added code to detect when the A button was pressed and released, then only called confirmButtonPressed when the A ButtonState went from Released to Pressed.