Developing FallFury was a fun and educational activity. Besides the fact that I got to work with an amazing team of people who were willing to assist me with the testing and development, I learned some important points about the development process as a whole and have outlined them in this article. Check out the video for this article at https://channel9.msdn.com/Series/FallFury/Part-12-Project-Conclusion. For a complete, offline version of this series, you may download a nicely formatted PDF of all the articles.
Go Outside Your Comfort Zone
This past summer, I decided to tackle a new challenge—game development. Never before had I built a game from the ground up. Moreover, as I could already find my way around C# code, I decided that I wanted to make C++ the language of choice, and so worked with DirectX instead of XNA. Additionally, the project needed to be constructed with Windows 8 as the target platform and I’d have to rely on the WinRT stack.
The concepts were new to me, but I figured that learning about a new platform and a new language would be more interesting than sticking to my comfort zone. Through FallFury I extended my knowledge about pointers, trigonometry, how DirectX handles a lot of the graphics legwork, and how to write HLSL shaders.
It was a challenging but very rewarding experience.
The most important part of any project is communication. There are always people who know more than you in one field or another, so don't hesitate to reach out to other developers and ask questions. Your code is not perfect, so talk about best practices used in production and how you can improve on what you already have—communication should not be limited to your team, floor, or even building.
One bonus of my experience at Microsoft was discovering that a lot of developers, when not in a meeting or in the middle of an important assignment, are more than happy to help a fellow employee with a piece of advice or some code review.
Plan the Small Details
Before you even touch the keyboard to write your first line of code, outline the components of your application and have a general idea of how you’ll implement those components as well as how they’ll interact with each other. It is tempting to start coding and then add or modify features, but doing so will create more problems than it will solve.
Build Small Prototypes
FallFury is a complex project composed out of blocks such as:
- XML level/metadata reader and writer
- The Share and Settings charm components
- SpriteBatch sub-system
- Level renderer
- Screen sub-system
- Menu interaction sub-system
Each block is responsible for its own set of tasks and each can be individually tested with either mocked data or a loose connection to the existing codebase. The necessity for small prototypes comes from individual requirements tied to the platform and possible integration scenarios. For example, when I began development, I created a non-hybrid DirectX project, which meant that if I needed to introduce XAML integration, I had to rewrite small parts of my swap chain preparation stack as well as work with a lot of XAML content in the code-behind. The Settings charm integration heavily relied on XAML, and I would have had to write the popup and control-related code in C#.
Obviously, that was not an option, so I created a hybrid project instead and ported most of my code into the new solution. Lesson learned here: prototype—and prototype early—in order to make sure that what you plan to implement will be implemented in an efficient manner.
Test Often, Test with Other People
When working on an application, it is important to understand the needs and expectations of your target audience, and a big part of this is making sure that the application provides a way for the user to easily learn about an action without a helper booklet. The menu system is a good example of this in FallFury. As I was designing the buttons on my screens, I tried to implement the approach used in games such as Dance Central—the user simply slides the button-panel and it takes him to the screen that was linked to that specific button. However, as I was testing the application with the local development crowd, I noticed a pattern—people were attempting to simply tap the button instead of sliding it. To avoid this confusion, I added a pulsating arrow on the right side of the button in order to highlight the fact that the button should be displaced in order to be activated.
The XML level loading system is another example of how secondary testing improved FallFury. Initial element positioning relied on a given level length, as well as on a ration-based placement. For example, if I wanted to put a button in the middle of the screen, I could position it with a value, such as .5. The level loader would then translate this value relative to the screen size. Rick Barraza was creating some test levels when he notified me about a big flaw—as the level extended, some elements were mis-positioned by a large margin compared to the original intended location. This was because when a level length was reset, the ratio was applied on a larger/smaller value, and some elements would therefore overlap. Ultimately, I rewrote the level structure to rely on pixel values, and designed the level-length to calculate automatically based on the included elements and their size.
Test on Different Hardware
FallFury started with portable hardware in mind. Its original design targeted Windows 8 tablet devices, though it was later decided that the project should support desktop machines as well. That automatically added thousands of possible hardware combinations on which the game might potentially run. Here are just some of the test machines we got to use:
- Samsung Series 7 Slate
- ARM Developer Tablet (Microsoft Surface)
- ASUS EP121 Slate
Each of these machines came with its own specific conditions that had to be accommodated. While Samsung Series 7 Slate featured an accelerometer, at the time of development the ASUS EP121 tablet did not have Windows 8 drivers for its sensor. When I sideloaded the game, I noticed that I could no longer control the character the way I wanted to. Also, though FallFury has keyboard controls, I had to develop controls for machines without keyboards. This is why I came up with the concept of touch-based, on-screen controls.
Moving on to the ARM device, first and foremost I noticed that my shader configurations were not compatible with the platform capabilities. All my testing was done on a machine that supported DirectX Feature Level 10, which was not the case for a low-power ARM machine that supports DirectX Feature Level 9.1. I had to work with some MSDN samples to find a way to properly modify the required shaders so they would work on Windows RT. ARM devices are built with battery life in mind. Therefore, their capabilities are reduced compared to those of a full-sized Windows tablet. This had an impact on the general game performance—some parts of the game, such as particle rendering, were working fine on a desktop machine, but were quite laggy on the ARM tablet. Knowing the possible source of the problem, I had to optimize the particle storage and rendering stack to ensure they didn’t affect the user experience on Windows RT hardware.
There Is Never Enough Time - Learn To Cut
When I started planning FallFury, I worked up a huge list of features. As the deadline approached, however, I noticed that I somewhat underestimated the allocated project time—a lot of time was spent on testing and eliminating bugs in existing features. That was the point at which I had to cut my feature set.
When designing the feature list for your app, make sure that you have a clear vision of which features get the priority and which can be cut if necessary. For example, FallFury was originally planned to be a multiplayer game. Although it was tempting to start working on it as such from the very beginning, I knew that it wasn’t a core feature and that it wouldn’t necessarily affect the general play experience on release day. Ultimately, multiplayer capability was dropped from initial development along with a number of other not-immediately-integral features.
Expect the Unexpected
When allocating time for the project, anticipate situations that might derail the process and cause a delay in the planned delivery date. It is easy to estimate that creating an accelerometer-based motion system will take you a day or two, but you also need to allow for the potential possibility of your code not working as expected, hardware accidents, natural disasters, etc. Doing so will help you focus on the right features at the right time while diminishing the risk of missing the deadline.
Platform Samples Are the Best Documentation - Learn to Read Others’ Code
While building the core of FallFury, I leveraged multiple features that hadn’t yet become mainstream among Windows developers. Therefore, the documentation was scarce and in some instances the only help I could get was internal. Luckily, Microsoft bundled hundreds of samples that demonstrate what the new platform can do. A lot of the development approaches gained during my internship were learned from looking at the official, publicly released sample code. The lesson here: if it's not on MSDN or blogs, check the official developer samples. For example, I used the DirectX sprite drawing sample to see how to build a proper sprite rendering mechanism with behavior similar to the one available in XNA.
When I started, source control wasn’t new to me, but there were proper usage practices that I didn’t apply before the internship. One of them is atomic commits, which I learned from Clint Rutkas.
With every new addition to the application, chances are something might go wrong. It could be a faulty third-party assembly, a misplaced class, or a broken reference that brings down the entire solution. If the commits include longer time intervals, for example, you will ultimately have to roll back to a build without a lot of the new functionality. Using atomic commits, however, you’ll be able to avoid unnecessary, redundant work in the case that something goes wrong during development.
A Non-standard Approach Is Not Necessarily a Bad Approach
For loading high scores, I needed the UI layout to display the registered items. To do so, I had could either use data binding or write a simple routine that would generate XAML items on the fly in the code-behind. Data binding is a pretty common practice among XAML developers, so my initial thought was to use that, but I would have had to create a C++ binding harness in addition to the existing data retrieval code. The second approach was much cleaner because it didn’t require me to rewrite or add much code. The lesson here: pick the best approach for the job and don’t blindly follow programming trends.
Focus on the User Experience
At the end of the day, the user doesn’t care whether you wrote the application in native DirectX or XNA, whether you applied the MVVM pattern, or whether you have easily readable code. The user cares about having a great time while playing the game, regardless of its backbone. It’s your goal as a developer to deliver that user experience and ensure that the user feels comfortable with the product. This means that the development cycle goes beyond simply writing code. In FallFury, levels are dynamic, which means the source code doesn’t necessarily need to be modified in order to create a different playable experience. But that experience matters in any case, and level design is a huge part of FallFury’s final product. Users need to be immersed in the game world, so levels must be planned in such as way that the user returns to the game and doesn’t abandon it after a couple of lost rounds.
FallFury was my first major project that I wrote almost entirely in C++, targeting the newly released Windows 8 operating system. Although the development process was challenging, it was proven to be a great educational experience that taught me about the approaches and practices that are used internally at Microsoft.