Keep on Trucking

Laundry List

I’m getting the feeling that this is the point where a lot of my other game projects have died out.  A core game and fancy title graphics.  I have rarely taken the time to go back and add all the bells and whistles, such as sound effects and flashy graphical effects.  Plus, I’m really not a fan of level design.  It really feels arbitrary to me, but it does take expertise to make good levels in a puzzle style game.

Therefore, to keep myself on track I made a laundry list of the next things to complete in the game.  Some will require a little research since this is my first XNA game, such as saving the game status.

  • Hold Confirm button to keep placing wires
  • Zoom in for letters on title screen
  • Game over screen delay / graphics
  • Display level/stage before starting a level
  • Transitions between screens (such as fade out)
  • Show player ranks for stages on level select
  • Don’t allow levels that haven’t been completed to be selected on level select
  • More levels; different array sizes
  • Colored backgrounds for level screens
  • Save levels completed along with ranks
  • Render objects in Blender
  • Add graphics/sound effects on level complete screen
  • Keyboard controls so that others who don’t have XBox can play test

The first task I tackled was the hold confirm button to keep laying pieces.  This is a core gameplay change, so I felt it was most important.  Basically, I just required a new instance variable in the GameLevelScreen class, which tracks if the confirm button is being held down.  On each update, it checks to see if the button is held down, and if it is, then it tries to set a piece at the current cell.  Therefore, it is constantly trying to set a piece at the current cell (but can’t since no more than one piece can be assigned to a cell), so there may be room for optimization here later.  Anyway, the controls feel MUCH better and less jerky now with this in place.  I think I need to put a cooldown on resistor usage, because the player can select a resistor and just spam it all over the board to quickly complete the level.  It’s okay for the wires to not have a cooldown, because spamming wires will likely cause the player to bust an LED and lose.

Continuing to resolve the tasks that required the most programming first, I decided to implement the record display on the level select screen.  To do this, I had to create a PlayerRecords class, which holds the records of each completed level.  This object is populated with the level ranks after each level is completed.  The level select screen uses this to display the ranks for each level.  Currently, if a level is replayed, then the ranks are overwritten each time the level is completed, which should be fixed later.  For now, the level select screen just shows the integer values associated with each rank, but these will be changed to the rank graphics in the near future.  Plus, I will need to implement a way to scroll through the higher levels.

 

In the level select screenshot above, I played through level 1 getting ranks C, S, B.  Then I selected level 5 and got ranks S, C, B.  Noticed an error which caused the game to crash.  After completing the fifth level (level index 4), it would actually go to level index 5 (which didn’t exist but used the layout of level index 0 as default).  When that level was completed, it would go to level index 1 (level 2) next.  So it appeared that it was looping back to level 1 (level index 0), but it really wasn’t.  Therefore, when it tried to save the statistics for level index 5, it reported an error because I only allocated the array in the PlayerRecords class to hold values for five levels (level index 0 through 4).  I went ahead and added the level index to the game level display, but I will probably create a method to convert that index to a stage number.

New Levels

Next I started working on adding new levels.  Before churning out new levels in the Mappy tile editor, I wanted to make sure that new levels can be easily added to the game.  I added two new List variables to the LevelDefinition class, to hold all of the tile maps and object maps.  This will eliminate the if/elseif statement mess that was in the getter methods that return the object arrays, tile arrays, and rank arrays for the currently selected level.  I really need to create a Map object to hold those values for each level, but I don’t want to have too many classes right now, so I don’t think it’s worth the time and effort to rework that code now.  The only benefit is that it would eliminate potential problems of managing five parallel Lists, but instead it would just be one list of Map objects.  I added additional checks in each of the methods that return ranks in the LevelDefinition class, so that it doesn’t try to index a position in one of the rank arrays if the level parameter is greater than the size of one of the rank lists.  This shouldn’t ever happen unless the NUM_LEVELS constant in the LevelDefition class is set to a value higher than the size of the rank Lists.  If this happens in the object or tile array getter methods, then it just returns the array information for level 1 (index 0).  I didn’t add any checks to see if the object and tile arrays were completely empty, because I thought that would be obsessive.  I may have to think about the ability to add an expansion to the game later, which may conflict with the PlayerRecords definition.

I used the Mappy tile editor to create more levels for the game, bringing the total to 20.  I wrote a small Ruby script to loop through all the files in the map export directory, and it does some minor modifications to prepare those arrays to be used in the game, then it writes out the results so that I have all the arrays in one file instead of 40 different files.  Made another minor modification to the rank code, which was preventing it from saving the ranks for the first stage (index 0).

  

 

More Title Screen Updates

Got side tracked and spent about an hour getting the letters on the title screen to zoom in.  After all letters are displayed, then there is a 5 second pause, then the letters zoom in again.   I’m not sure how much more time I will want to spend on the title screen.  Gameplay is most important, but the title screen is the first thing that people see.  I definitely wanted to display the title screen as soon as possible.  I am so sick of seeing idiotic Game Studio Logos on startup that just waste my time.

So now I think I just need to re-do the font for the menu items to match the title font, and then have a new menu item selected image (the default tile has been there for a while).  I’m thinking of just using another portion of the computer card images that I already have, and maybe apply a brighter white color and a drop shadow.

Junk Food Blaster

Junk Food Blaster is a game that I created for the GM48 23rd game jam.

Blast the junk food and keep your heart rate below 200! Walking and jumping will slowly raise your heart rate. Junk food will significantly raise heart rate!

Standing still will drop your heart rate back to normal.

Hot dogs move in a straight direction. Hamburgers float in the air.

Time Lapse Video

Post Mortem

Junk Food Blaster is the first game that I’ve created using GameMaker Studio 2.  I bought this version of GameMaker from Steam during the summer sale.  I was disappointed to discover that I am not able to make HTML5 web builds, however I can make builds for Windows, MacOS, and Ubuntu (Linux).

The theme for this GameMaker game jam was “Sacrifice”.  After I had heart problems four years ago which required as stent placement, one of the things I’ve had to sacrifice is fast food.  I know some of us in the Knoxville Game Design group joked about me making a heart attack game before, so this seemed like a good opportunity to make that game.

I used to eat fast food regularly, but I’ve scaled it back dramatically to avoid having heart problems again.  Going to the emergency room in the middle of the night with chest pains is not an enjoyable experience.  I was planning on having many of the types of foods that I have given up (or scaled back).  Time ran short for me on this game jam, so I only included hotdogs and hamburgers.  I was also planning on having pizza as an enemy in the game which would throw pepperonis at you.

As with other game jams, all of the assets have to be created in 48 hours, ending at 8pm Eastern Time on Sunday.  This includes art, sound effects, and music.

As with my Miner Madness game, I decided to use vector based SVG art created in Inkscape, which I animate in Spriter.  However, this time I learned how to use bones in Spriter to animate various parts.  This was necessary to keep the right arm and the gun together.

Some parts of GameMaker 2 proved to be very frustrating to me.   I liked the ability to switch between DnD (drag and drop) mode and GML code.  However, sometimes the action toolbox would not display in DnD mode.  Plus, the camera and viewport system has been completely redone, so most of the information on the Internet on moving a camera in viewport is out of date.

I didn’t like the method for navigating in GameMaker 2 either.  Too many instances of windows in windows in windows.  Moving around in the workspace felt like a chore.  There are no scrollbars, so you have to press the middle mouse button down to move around.  The zoom-in feature on the code windows was annoying, because it made some really distracting anti-aliasing effects which are fine for graphics, but makes text difficult to read in an editor.  I did finally find the magnifying glass with equal sign which makes everything in its original size.

The panning around in the workspace when selecting different objects also got annoying after awhile.  I would rather just have one window with tabs like every other IDE.

One the complaints I have about Spriter Pro is not being able to set the dimensions of the generated sprite sheet for an animation in pixels.  You have to specify the size in percentages, which means you have to figure out the size in Gimp first and use a calculator to get the percentage.  I also had issues with the animation playing too fast in the Spriter Pro editor, and it has an annoying step of pressing the set length button after setting the maximum number of frames.  It’s like my gripe with Inkscape with having to press Export to generate a png image after pressing Export As and pressing the Save button.  You would think that Save means that it is going to write the png file, but it doesn’t.

I had problems with the jump animation, because there is no straight forward way to make an animation not loop.  I had to keep track of the last frame, and then set the animation speed to zero until the player touches the ground.  The gun shooting animation had a similar issue, but I just made sure that the animation frames (15) were the same number as the shooting delay.  Since the game runs at 30 frames a second, it takes half of a second for the shooting delay.

Another issue that I had was the game looping back to the level screen after the game over screen, when it was supposed to go to the title screen.  After some thinking, I realized it was because it was registering the space key down on the frame after it was pressed to leave the game over screen.  To fix this, I put a 60 frame (2 second delay) on the title screen.  One important thing that I added was an offset to the title text based on the delay value, which makes the text rise upward.  When the title text stops, then the user can press space to load the game.  Otherwise, it will make it feel laggy because the user has no visual cue of why they weren’t able to continue by pressing space before.

I would like to add more types of food to the game as enemies.  As I mentioned earlier, pizza which would shoot projectiles.  I’m thinking about adding fries as well.  My cardiologist says that keeping my sodium intake low is one of the most important things to keeping my blood pressure low and avoiding another heart attack.  Salty foods like fries contain a lot of sodium.

When I made the hamburger enemy, I joined two circles together and took the difference with a rectangle to make the bun.  Then I duplicated that piece and flipped it vertically to make the bottom piece of bun.  I cut a rotated square in half to make a piece of cheese.  Originally, I just had one piece of cheese, but then I added a second and it looked like fangs!  I definitely didn’t plan it that way, but it looked so good I had to keep the two pieces of cheese.

I would like to add powerups to make the gun shoot farther and maybe add other abilities.  The game needs additional levels as well, since this is probably one of my shortest games.  The problem I have with gamemaker is that the collision detection is done by specifying the name of the object, which means I would have to update the code to add a new type of wall objects.  There is probably a better way to do this that I don’t know about yet.  I know there is a tile layer, which I should probably be using instead of instantiating individual wall squares.

I used BFXR for generating the sound effects.  The enemy death sound effect reminds me of Bill Cosby’s marker sound on Picture Pages.

I felt like I could have done better with the music.  I made a slower more relaxing theme this time.  It has one background pattern then a slow moving theme.  I cut the theme a slowed the tempo for the title music.  I did have some background ambience tones, but those came out way too loud after I exported the mp3 from my MacBook Pro to my PC desktop, so I ended up removing that track.

I knew I wanted to have a representation of the hearts health as the player’s life value.  I thought about using blood pressure, but heart rate seemed more appropriate.  On my last GM48 game jam, one of the categories that I was graded lowly in was originality.  So for this game I made it so that running and jumping added to your heart rate.  If your heart rate reaches 200, then it’s cardiac arrest and game over.  I originally wanted to have a graphical heart rate monitor that would speed up and possibly change color as you approach the maximum heart rate value.  If you stand still, your heart rate gradually lowers back to a minimum of 100.  Colliding with a hot dog or hamburger will significantly increase your heart rate, by 20 and 40 respectively.  Walking increases your heart rate by 0.2 for every frame.  By default, your heart rate lowers by 0.1 per frame, so I had to make walking  more than default to see an increase.  Jumping raises heart rate by 5.  Looking back, I would probably make it so that the player can’t die from walking or jumping, so that the player would actually have to collide with the enemy for the game to be over.  Otherwise it just feels strange by dying from walking or jumping.  An audio cue or speed up in game music would also let the player know they are reaching a dangerous level, although I didn’t see any way to increase the tempo or speed of the music in GameMaker like is possible in Unity.

One problem is that sometime the player can rapidly jump in the wall when holding down the jump button.  I think this is because the collision boxes on each sprite animation (standing, jumping, walking, shooting) are different sizes and there is no easy way to make them the same.  It would be nice to have just one collision box for an object, and just change the animation.  I did see an option to use a different collision box for a sprite, so I will need to learn more about that option.

The background was also made in Inkscape.  One of the difficulties was making it wrap around.  I figured out how to make the background tile across the entire viewport.  I used the number of horizontal blocks in Super Mario Bros level 1-1 as the size of my level.  I had to adjust the horizontal size of my viewport to take account of the larger size of my times.

I figured out how to get the camera to follow the player by enabling the viewport and setting the appropriate camera size and setting the player object as the thing to follow.  The difficult part was getting the status text with the heart rate value to anchor at one spot on the screen, since it wanted to scroll with everything else.  After much trial and error, I finally found the correct values to use camera_get_view_x(camera_get_active()).  If you want the text to follow the player, you can just use the player object’s x value.

Controls

  • A,D or arrow keys – move
  • Space – jump
  • Left mouse button, F, or Ctrl – shoot

Tools used

  • Engine – GameMaker Studio 2 Desktop
  • Graphics – Inkscape 0.91
  • Graphics – Spriter Pro 11
  • Graphics – Gimp 2.8.18
  • Sound Effects – Bfxr 1.4.1
  • Music – GarageBand 10.1.1

 

Released

Jukebox

I thought I would implement something relatively simple tonight, so I decided to work on audio.  I already have two songs that play for the title screen and level screen, but the logic is built into my main game class which isn’t ideal.

For this game, I decided to take a new approach with the music.  Instead of manually starting and stopping songs when needed, I decided to assign a Song to each Screen class.  When the current Screen is changed, then the music is changed to match that screen.  I may have to make some exceptions, for instance in the case of a boss battle.  The player would still be on the GameScreen instance, but the music would need to change.

To implement this, I added a new Jukebox class to my ResistorKit library.  This will hold the references to all songs and sound effects.  Songs and sound effects are still loaded in the LoadContent method of the main game class, but after each has loaded it is added to the Jukebox object using the addSong and AddSoundEffect methods that I created.  The one drawback is that each Screen needs a reference to the Jukebox.  I can set the Jukebox in the current screen on each call to Update, but I will need to double check in the Screen to ensure that the Jukebox reference is not null before calling any methods on it.  I also created an instance variable in the Jukebox class to keep track of the currently playing Song.  The Song is only changed if the current song instance variable is changed, since there may be multiple screens with the same Song.  Overall, I like this method much better because it keeps the references to all audio objects in one class.  The beauty of this is that a Song identifier only has to be set for a Screen once, and then the music for that screen is automatically played whenever that screen becomes active.

In my main game class, I created an enum called GameSongs which holds identifiers for all of the Songs.  This is much cleaner than all of the int constants that I have been using.  I will want to go back and convert my Texture2D constant int identifiers to enums as well.  The only problem is that my Jukebox class in ResistorKit is not aware of the enum in my game.  I’d rather not put the enum or a reference to it in my library, because that would prevent other projects with different song identifiers from using the library.  I was able to solve this problem by casting the enum identifier to an int when calling the addSong method on the Jukebox object.

After adding the Jukebox to the game and making the necessary updates, I was able to use it to play the sound files.  One issue that I noticed was that since the Attract screen is displayed first, the setCurrentScreen method never gets called since it does not transition from another screen state, so the music wasn’t playing.  As a quick fix, I set the next screen state to the Attract screen in the constructor of the Attract screen, just so that the setCurrentScreen method gets called when it is first displayed.  This change made the music play correctly.  Since the Title Screen has the same Song, the music continued to play without breaking during the transition from the Attract screen to the Title screen which is what I wanted.

screen104

Finally, I pulled one of the sound effects from Resistor to use for the gun.  I just needed a temporary sound effect to use to see if the play method for sound effects in Jukebox is working.  I have to say, the Windows Media Player for Windows 8 is really horrible, because it is full screen with no way to change the size.  The Windows 8 music interface forces you to look at a bunch of advertisements from musicians I’ve never heard of and musicians that I really don’t like.  Fortunately, installing Audacity is a really fast and simple process.

screen105

One thing that is easy to forget is to set the Jukebox object in the Screen class to protected, so that the objects that subclass the Screen class can use the Jukebox object.  Fortunately, this only has to be set in the library, so the Jukebox will automatically be accessible to any implemented subclass.  Also, it is necessary to set the enum in the main game class to public so that any implemented Screen subclass can reference the sound effect identifiers.  However, the enum does not need to be set to static or constant.

After making these changes, the gun sound effect plays correctly when pressing the fire button.  However, the sound effect would play even if the player does not have a gun equipped and a projectile is not shot.  I would rather not put the sound effect playing code into the model.  I noticed that I already had a LifeTime variable defined in the projectile class, which keeps track of how many frames the projectile has lived.  Therefore, I just added a getter method for that variable, and I play the sound effect if the LifeTime variable is one (first frame).  I moved the code to play the sound from the button press method to the loop that draws the projectiles, and now it only plays the sound if a projectile is shot.  Having the sound play on the first projectile frame will give me the ability to play different sounds based on the projectile type (fire, ice, et cetera), since the projectile is already instantiated.