Tightening up graphics, and the other subsystems

– This post has been a hold-over for a few weeks, but I decided it’s now time to flush it to the screen! –

After coming to grips with my shortage of artistic inspiration, I’ve decided to go on full steam ahead with my game features and underlying systems. More menus, more screens- including the ubiquitous Pause screen- a continuous rebuild of the underlying system that controls them, and I even did some touch-ups with the visuals. Bubble Tower is slowly but surely becoming more polished in gameplay and presentation.

First I want to talk about the visuals, because it’s will just be a short overview. There are no graphics other than menu text, bubbles, and backgrounds, but I’m moving on to using more with 3D rendered graphics for a lot of the stuff. So I start with the most obvious, the bubbles. The original spritesheet contained 8 bubbles, one for each color. I decided to stick with this principle but generating the spritesheet at runtime by drawing the mesh to a render target with 8 different colors and viewports. I get to keep the original code that splits up the spritesheet and select the appropriate colored bubble to draw.

What’s nice about this is that the bubbles can be animated, or they can be replaced with another mesh. After working on a shader to get the highlights and shading looking just right on the bubbles, I messed around with some other geometric meshes, and found one that I got stuck on. I was inspired by the gem puzzle games and wanted to use more interesting shapes. Mine look more like some sort of paper origami balls than bubbles now, but I actually like the look. So after all it looks like I am getting somewhere with the visuals. Afterwards I just stuck in a wallpaper as a test background.

Improving the screen system

The more I try to make the screens do what I want, the more bugs I was finding, but I’m smoothing out the screen system as I keep progressing. The screens have the ability to transition in and out of view, with user-defined times (as far as user-defined animations I’m working on it). This added a lot of code bloat to the GameScreen class, so I isolated all this transition stuff into its own Transition class. Now every screen just has a Transition that it can use internally.

I’ve also made a new type of screen, the Splash Screen. Splash Screens are non-interactive, stay on for a fixed amount of time on the center of the screen, and leave. They can have text or an image. In the essence of time, I initially reused a class to display menu text, but broke it down further because it wasn’t using the button click functions.

It’s also possible to load a series of splash screens, each following in succession, with just one function call. The trick is passing a string array with your text in it, and storing it in the splash screen. The first splash screen uses the first string of text, removes it from the array and when it’s going to exit, passes the shorter array to a new SplashScreen constructor. If there is a transition time, you will see the text/images smoothly crossfade between each other. This feature is great for displaying several game logos in a row, or  having a visual countdown with your own text. I would not use it for long still-frame cutscenes, though. The player doesn’t have control of the splash screens, so not being able to skip through them would be very annoying.

Rules and control flow

Adding new splash screens on top of interactive screens have made the control flow a tad unpredictable, because I would want some splash screens to take away some control from the player, but not some others. I initially decided to make a distinction between interactive screens and non-interactive screens, and loop through the interactive screens to read input events, but that just made the results more confusing.

Here is the current list of screen classes that are used in this game:

  • GameScreen
  • GameMenu
    • MainMenu
    • LevelSelectMenu
    • PauseMenu
    • GameOverMenu
  • MainGameMode
  • LevelEditorMode
  • BackgroundScreen
  • LoadingScreen
  • SplashScreen

The menus may seem redundant in distinction, but I won’t need many menus anyways, and totally fine hard-coding the pathways in them instead of using external scripts. On the quest to make the screen manager more robust, here are some rules I’ve set to implement:

  • If a new screen is added, start reading input (if it’s interactive)
  • If the new screen is marked “exclusive”, stop updating/reading input for other screens
  • If an exclusive screen is removed, read input from the other screens again
  • Screens may start reading input as soon as they’re entering, or when they’ve completely entered
  • Screens should stop reading input as soon as they’re leaving

Pretty straightforward stuff. Here’s where the rules become more involved:

All screens undergoing transitions should be allowed to complete the transition phase.

What this basically means is, if a screen is exiting or entering, the transition timer that counts down or up must not be stopped at any cost. Just keep it going. To accomplish this, the transition updates need to be decoupled from the user-defined update code.

The reasoning behind this is, sometimes, an exclusive screen may enter at the same time other screens are entering. The exclusive screen wants to stop the others from updating, but if the transitions are ran in the Update function, those other screens will never get to complete their transitions! Decoupling that from the Update function would be the way to go, so I moved all the transition logic to an UpdateState function, which will always get called no matter what.

Avoid adding or removing screens while other screens are being queued for updates/input reading.

The screen manager has two special lists, ScreensToUpdate and ScreensToReadInput. ScreensToUpdate is a mainstay from the XNA code sample for game state management- it simply tells the manager to call Update on the screens in it. ScreensToReadInput was added later, and this tells the manager to HandleInput from the screens on that list. This action is done before calling Update on all the screens.

Here is the order of functions that are called in the game’s main loop:

  • Read input from screens
  • Update screen events
  • Draw each screen

There is no particular spot that says where AddScreen or RemoveScreen is called. They may be called one or multiple times where screens are updated or reading input. That can have undesirable effects and can lead to subtle bugs if we’re not being careful.

Suppose that in one screen inside the ScreensToReadInput list, a key press was detected which will tell the screen manager to remove this screen and then add another one. That would potentially modify the list while it’s still looping inside of it! This would throw an exception if done in a foreach loop, so you have to use a for loop to iterate through instead. Still, modifying a list of screens while screens are updating can lead to unexpected behavior.

Updating screen lists

To resolve this problem, screens should not use AddScreen or RemoveScreen at all. These two functions can be made private, and there are two new functions to supplement them: PushToAdd and PushToRemove. Those would be the functions that screens can call, to notify the screen manager that there are new screens waiting to be added or removed.

Both functions would add a screen to one of two new lists: ScreensToAdd and ScreensToRemove. They are a sort of waiting list for the screen manager to go through. The purpose of this to move AddScreen and RemoveScreen calls inside a separate function, away from updating and reading input. The new loop of functions would look like this:

  • Add or remove screens
  • Read input from screens
  • Update screen events
  • Draw each screen

The ScreensToAdd and ScreensToRemove lists are guaranteed to be cleared by the time the screen manager is done with the first step. Now we would know exactly where new screens are pushed or removed from all the lists.

Determining screen priority

Why not just have the topmost screen receive input, you might ask? Sometimes you’d want more than one screen at a time being interactive, like a group of menus for a strategy game. Or the aforementioned splash screens that would still allow player control of screens underneath, I’d have to give them a special flag or property that says they are not “exclusive”. I plan to use splash screens more in this way, such as displaying larger score numbers or messages for clearing certain groups of bubbles.

Once I have all these problems sorted out, though, I can go back to adding more game-centric features, and hopefully adding a two-player mode. Still don’t know how I’ll work that one out, as I am just using a keyboard and don’t even have an Xbox controller to hook up. I can always take the more daring route and start coding an AI to play against the player. That would certainly be another challenge, but most likely I will just start out making the “AI” fire bubbles at random times in random directions, then gradually mold its crazy mind into something more coherent. But for now, on to polishing more menus!

Advertisements

Making a flexible level selection menu: Part 2

Continuing off from last time, we’re going to improve on the Level Selection menu made using the Game State Management sample. If you haven’t done so already, read part 1 of the article so you can catch up.

For any other game modes you would want, you do need other classes that differ from GameplayScreen to some extent, because they’ll need to run different code, for different game rules and settings. But do we also need to make another class like the LevelSelectScreen class, displaying the same list of level choices, but change the Select event so it loads these other game modes? Not really, and that would be too much repetition. Instead, the menu screen can be re-purposed to recognize different entry and exit points and load the appropriate game mode.

The end result would be making the Level Select menu reusable. It will load a different GameScreen from the Level Select menu, depending on what item you selected in the Main Menu.

Main Menu -> Select “Play Game” -> Select a level -> Gameplay on selected level

Main Menu -> Select “Level Editor” -> Select a level -> Level Editor on selected level

Suppose you’re tired of coding those levels by hand and you finally want to start working on a fancy level editor. All its functions and logic will neatly reside in a LevelEditorScreen class. We can use GameplayScreen as a starting point. So let’s copy GameplayScreen.cs and rename it to LevelEditorScreen.cs, and also rename the class as such.

You may notice that it carried the new constructor and parameters that we introduced into GameplayScreen class with it. These will be used for the Level Editor as well. To distinguish it visually from the Gameplay screen, replace the "Playing level " text in the Update and Draw functions with "Editing level ", noting the trailing space at the end.

Now, let’s add another entry to the Main Menu screen. Just below the playGameMenuEntry, add another new MenuEntry with the text “Level Editor”. Add it to the MenuEntries list and assign an event handler to it as well. Copy the PlayGameMenuEntrySelected method and rename it to LevelEditorMenuEntrySelected, this will be the method to attach the event to. Here is the class, only showing the constructor and methods we just updated:

// MainMenuScreen.cs

        public MainMenuScreen()
            : base("Main Menu")
        {
            // Create our menu entries.
            MenuEntry playGameMenuEntry = new MenuEntry("Play Game");
			MenuEntry levelEditorMenuEntry = new MenuEntry("Level Editor");
            MenuEntry optionsMenuEntry = new MenuEntry("Options");
            MenuEntry exitMenuEntry = new MenuEntry("Exit");

            // Hook up menu event handlers.
            playGameMenuEntry.Selected += PlayGameMenuEntrySelected;
			levelEditorMenuEntry.Selected += LevelEditorMenuEntrySelected;
            optionsMenuEntry.Selected += OptionsMenuEntrySelected;
            exitMenuEntry.Selected += OnCancel;

            // Add entries to the menu.
            MenuEntries.Add(playGameMenuEntry);
			MenuEntries.Add(levelEditorMenuEntry);
            MenuEntries.Add(optionsMenuEntry);
            MenuEntries.Add(exitMenuEntry);
        }

        /// Event handler for when the Play Game menu entry is selected.

        void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
			ScreenManager.AddScreen(new LevelSelectScreen(), e.PlayerIndex);
        }

		/// Event handler for when the Level Editor menu entry is selected.

		void LevelEditorMenuEntrySelected(object sender, PlayerIndexEventArgs e)
		{
			ScreenManager.AddScreen(new LevelSelectScreen(), e.PlayerIndex);
		}

We now have two menu choices that take you to the Level Select menu. But Level Select still takes you to the Gameplay screen no matter where you came from. Let’s change that! The Level Select menu needs to know where to go next. To do that, we’ll have to pass the Type of the GameScreen as a new parameter to LevelSelectScreen’s constructor.

The two event handlers of the Main Menu that take you to the Level Select menu use this updated constructor, and each call to AddScreen will pass to the constructor a different Type. For selecting “Play Game”, GameplayScreen is passed, and for “Level Editor”, it is a LevelEditorScreen.

// MainMenuScreen.cs

        /// Event handler for when the Play Game menu entry is selected.

        void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
			ScreenManager.AddScreen(new LevelSelectScreen(typeof(GameplayScreen)), e.PlayerIndex);
        }

		/// Event handler for when the Level Editor menu entry is selected.

		void LevelEditorMenuEntrySelected(object sender, PlayerIndexEventArgs e)
		{
			ScreenManager.AddScreen(new LevelSelectScreen(typeof(LevelEditorScreen)), e.PlayerIndex);
		}

// LevelSelectScreen.cs

        Type gameScreenType;

		public LevelSelectScreen(Type gameScreen)
            : base("Select a Level")
        {
            gameScreenType = gameScreen;
        /* ... */
        }

        /// Event handler for when the Play Game menu entry is selected.

		void MenuEntrySelected(object sender, PlayerIndexEventArgs e, int currentLevel)
        {
			LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
				(GameScreen)Activator.CreateInstance(gameScreenType, currentLevel));
        }

The LevelSelectScreen class now takes in a Type parameter and for the selection event handler, an Activator creates a new instance of the GameScreen, casting it down and passing the currentLevel parameter. Since the type is chosen from the Main Menu, we can always make sure that any GameScreen that gets passed from it must take an extra parameter for the level.

Our new menu gives you two possible choices to access the Level Select menu from, but you can add more if you want. Nothing more needs to be done to the Level Select menu- the menus are already linked at this point. All you need to do is, for every GameScreen that you would want to load a level, create a new menu entry for the Main Menu and pass along the type for the GameScreen.

You can try improving the Level Select menu in other ways, like showing a different list of levels depending on what game mode you choose. To start out, you may set a condition to offset the level ID in the menu.

A more complex problem would be to display an extra selection screen before the “final” screen at the end of the selection process. In racing games, you often would select a vehicle in addition to the track you’ll race on. The logic from the Level Selection screen is flexible and bare-bones enough so you can duplicate it to make a menu for selecting characters, vehicles, etc. It’s pretty much open from there, so hopefully you’ll be able to find better uses for the menu, and make it easier to manage your menu code. Let me know if you have other ideas to improve it.

Making a flexible level selection menu: Part 1

Lately, most of my work on Bubble Tower has been on creating a menu system. The menu will need to support multiple game modes, options, and a screen to select levels with. Since I am basing this off the XNA Game State Management sample, a lot of the work has been done. But my game uses a separate system to handle game states, so I modified to code to keep menus and game states as different kinds objects.

I have finished the first step of building a working level select screen for the game, and notice that it’s pretty easy to do, but it does need a few modifications in the logic. I will show you how to make your own level selection screen with the Game State Management sample, and have it be reusable for as many game modes as you like. This way it’s possible to load a level -whether it’s for a single player game, multiplayer, or for editing- by going through the same menu as an intermediate step.

I won’t be teaching you how to actually load your level data into the game. This article is mainly to show how to create a flexible menu that can pass any parameters you wish to any game screen/state so you can do whatever you want with it. Whether your levels are hard-coded or stored in separate files doesn’t matter.

Adding a new menu

The GameStateManagement sample takes you to the Gameplay screen with the following steps:

Main Menu -> Select “Play Game” -> Gameplay

We’ll add a menu which will change the course of action to the following:

Main Menu -> Select “Play Game” -> Select a level -> Gameplay on selected level

For brevity, all these graphs ignore the Loading screen.

The first thing we’ll do is to copy the MainMenuScreen.cs file from the sample project, and rename the new file LevelSelectScreen.cs. In it, rename the class to LevelSelectScreen and remove all methods except for PlayGameMenuEntrySelected. This will be renamed to MenuEntrySelected. We’ll also make changes to the menu entries to replace with level names, and modify the MenuEntrySelected method. The class should look like this so far:

// LevelSelectScreen.cs

    class LevelSelectScreen : MenuScreen
    {
        public LevelSelectScreen()
            : base("Select a Level")
        {
            // Create our menu entries.
            MenuEntry level1Entry = new MenuEntry("Level 1");
			MenuEntry level2Entry = new MenuEntry("Level 2");
			MenuEntry level3Entry = new MenuEntry("Level 3");

            // Hook up menu event handlers.
			level1Entry.Selected += MenuEntrySelected;
			level2Entry.Selected += MenuEntrySelected;
			level3Entry.Selected += MenuEntrySelected;

            // Add entries to the menu.
			MenuEntries.Add(level1Entry);
			MenuEntries.Add(level2Entry);
			MenuEntries.Add(level3Entry);
        }

        ///
<summary>
        /// Event handler for when a menu entry is selected.
        /// </summary>
        void MenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
                               new GameplayScreen());
        }
}

A lot of repetition going on, but we’ll fix this soon. Now in the MainMenuScreen class we’ll change the PlayGameMenuEntrySelected method to match this:

// MainMenuScreen.cs

        void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
			ScreenManager.AddScreen(new LevelSelectScreen(), e.PlayerIndex);
        }

If we run the code right now, we should see the “Play Game” entry in the main menu have a different function. Instead of taking you to the Gameplay screen, it should load the new menu we just made. This will let you choose between three options, which do load the Gameplay screen. But still, the options call the same exact method with no differences in them. This is where the next step comes in.

Choosing the level

The MenuEntrySelected method must have some way of knowing what level it needs to load. We will add a parameter to the method that will pass the level number, and in turn the Gameplay screen will also need to be modified to take that info and load the specified level.

Back in the LevelSelectScreen class, update MenuEntrySelected so it takes an integer, the selectedEntry from the MenuScreen class, for an extra parameter. The parameter will also be passed into the GameplayScreen constructor so change that as well:

// LevelSelectScreen.cs

		void MenuEntrySelected(object sender, PlayerIndexEventArgs e, int currentLevel)
        {
            LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
                               new GameplayScreen(currentLevel));
        }

Now there’s a problem. Because of the extra parameter, there’s no method overload that currently matches the delegate. To have the event handlers recognize the new method, let’s add an anonymous function. We’ll have to replace MenuEntrySelected on each event handler with the following delegate:

level1Entry.Selected += delegate(object sender, PlayerIndexEventArgs e)
				{ MenuEntrySelected(sender, e, selectedEntry); };

To do this on each handler will be repeating the same code. Since all the menu entries are linked to the same method, we can rewrite the LevelSelectScreen constructor to take in the entries as an array. To keep things simple, we’ll assume our game has a fixed number of levels and the array is hardcoded in. Here is the complete code for the constructor:

// LevelSelectScreen.cs

		public LevelSelectScreen()
            : base("Select a Level")
        {
			int totalLevels = 3;
			MenuEntry[] levelEntries = new MenuEntry[totalLevels];

            // Create our menu entries.
			for (int i = 0; i < totalLevels; i++)
			{
				// Add entries to the menu
				levelEntries[i] = new MenuEntry("Level " + (i + 1));
				MenuEntries.Add(levelEntries[i]);

				// Hook up menu event handlers
				levelEntries[i].Selected += delegate(object sender, PlayerIndexEventArgs e)
				{
					MenuEntrySelected(sender, e, selectedEntry + 1);
				};
			}
        }

Another problem remains, but it’s much simpler to fix. selectedEntry is part of the MenuScreen class, and can’t be accessed anywhere else. Changing it from private to protected will fix this. It will also make other custom menus that derive from MenuScreen more flexible.

Finally, we’ll put that selectedEntry parameter to use in GameplayScreen. Edit the constructor and add a variable to store the parameter as a sort of level ID:

// GameplayScreen.cs

	int currentLevel;

        /// Constructor.

        public GameplayScreen(int level)
        {
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);

			currentLevel = level;
        }

To see the effect in having the level being chosen for this screen, replace both instances of the string "Insert Gameplay Here" found in the Update and Draw methods with "Playing level " + currentLevel. If you want, you can also remove the “//TODO” text just so the context makes more sense. Run the code, and go through the Level Select menu to choose a level.

Level selection screen

Gameplay screen

The above screens are an example of what you’ll see with the new Level Select menu fully implemented. The Gameplay screen knows what level it’s running, and therefore can load contents specific to that level, and apply its Update and Draw logic to the level as it is played.

Extending the menu further

Normally, we would be done with the menu at this point, but it can still be improved and taken to another level (sorry). What if we wanted to have two or more different game modes for playing the same levels? Maybe it’s a racing game and you’d want to go for a time trial, or play head to head with other players on the same track. Or, maybe even introduce a level editor that can be used right in the game. Suddenly we have more than one reason to use the Level Select menu. In the second part of this article I’ll show you how to reuse the same menu for different GameScreens to load levels with.

Messing around with menus

The menu system is a whole different beast that I need to tame. Many months ago I downloaded the Game State Management code from the official XNA code samples, and found much of it helpful, if a bit too much for my needs. The code sample organized everything in “screens”, and any different game mode in it is a screen, whether it’s a loading screen, a menu, or a gameplay screen.

I found it odd that the menu should be a screen itself, and to me it made more sense to separate the Menu objects from the concept of the screen. So over time, I reworked the code so instead of screens, it just deals with the menus and the interactions from the user. In my game, I use a game state system completely different from the XNA sample, where each game state is a class derived from an abstract GameState object. This system doesn’t use stacks at all and just runs one state at a time. The game tells the current state to update itself, and the state is responsible to change the current state of the game when needed.

Menus are just an optional thing that the game states can have, and each one has a MenuManager (altered from the sample’s ScreenManager) in its base class. Those menus only belong to that particular GameState. It’s also possible to have multiple menus in each class, and the menu events can tell other menus to load. This feature is close to the one in the sample code, and it’s the one I chose to keep the most. Menu events can also tell the current GameState to replace itself with a different one, but that’s as far as it goes to being connected with them.

Getting the menus to play nice with the system I had already in place was a bit of chore. They wouldn’t communicate with all the objects very well, and I had some crashes where the game state would change, but failed to load the resources for the menus because the Content Manager wasn’t set. I also didn’t like the fact that it communicated with the Game object for a lot of things. Long story short, I changed the menu manager so it only needed the content and graphics services, which is all it really needs to begin with.

Skins for my menus

Finally, a more interesting feature comes along: menu skins. This is all custom-made feature I made just to mess around with the look of the menus. The original menus use SpriteFont to write the text to the screen. A menu skin class looks for an XML file with a particular name, loads it and parses the data to determine the SpriteFont, colors, and sprite dimensions of each text item.

This is all well and good, but I wanted to make it a bit more flashy. In each menu entry, I saved the text to a render target texture, then when it comes to draw the complete menu, draw all the textures to separate quads. Now you can add sorts of crazy effects to the text through shaders, having them activate when one is selected. But that STILL wasn’t enough for me 😛 Afterwards I applied a perspective projection before drawing the quads, so you can now render the menus with a 3D perspective! Here is a very exciting screenshot with a sample menu:

Title screen with skinned menu

I know, I desperately need some artistic assets, but I hope the picture is clear enough to show what it does. I intentionally added solid rectangles to make the perspective effect easier to see, but by default the background behind the text is transparent. So to recap, here’s what the menu system does from the presentation side:

  • Loads the XML file to determine style properties of the menu
  • Sets a render target for each menu item
  • Renders the text, and then off to the next item
  • After all items are done, a perspective projection is applied
  • All the menu item textures are drawn to different quads
  • This menu itself can be saved to its own render target texture, so it’s separate from whatever else is on the screen

That’s a lot of texturing and drawing to do. Right now it’s not optimized to re-use textures, or use texture atlases/primitive batching etc, but I will get to that eventually. For now it works fine for basic menus containing a small number of items, which is fine by me. One thing I want to point out is that the menu item text is not set in the XML. I intentionally left it this way to separate content with presentation.