Foreword

Witty prose with glowing praise from a Xamarin team member, a MonoGame founder, or Andrew goes here.

{pagebreak}

Acknowledgements

Thanks to all the little people go here.

{pagebreak}

Special Thanks

This work relies heavily on resources and in-game assets provided by the following folks.

  • Kenney Vleugels (@KenneyWings)
    http://kenney.nl/
    Awesome assets. Most of the art in the examples for this volume came from Kenney. I discovered Kenney while browsing for art on OGA - http://opengameart.org/users/kenney. That’s another great resource for assets, but Kenney’s my favorite contributor by far.
  • Sergiu Muresan (@muresan_sergiu)
    http://sergiumuresan.com/
    Mr. music, himself. I met him through a friend when he was working on Creatures and Castles for iOS. Don’t let his modesty fool you, he’s a great resource for music.
  • Andrew Rollings (@hiive)
    http://www.hiive.com/
    An accomplished programmer and author, Andrew is the one who commissioned the works from Sergiu for his own games. Andrew graciously allowed me to use those assets in some of the examples in this book.
  • Daniel Cook (@danctheduck)
    http://www.lostgarden.com/
    Another great resource for game design, illustration, and (of course) free assets. I used some of Danc’s art in my first book. I plan to do the same in this series.
  • Joseph Hall (@groundh0g)
    http://www.moreoncode.com/
    That’s me! If there’s art or other assets in the examples that you don’t particularly care for, they were likely created by yours truly. I enjoy drawing, but I haven’t put in the hours required to master it.

{pagebreak}

About the Author

{width=45%,float=right} Me and my reasons for being.

Joseph Hall has been a professional software developer for nearly 25 years. He worked as a programmer for Microsoft and IBM, and he was the software architect for a Fortune 500 bank before starting his own consulting company in 2006. Joe makes his living writing desktop, web, and mobile device applications for businesses and governmental agencies, but game programming is his passion, and it was gaming that got him into programming in the first place.

Joe was a member of the original Xbox team and he joined the Visual Studio .NET team just after the Xbox was released in 2001. He is the author of XNA Game Studio Express: Developing Games for Windows and the Xbox 360, which was published in 2007. In this new series of books Joe applies his unique blend of development experiences to help you explore the exciting arena of cross-platform game development using Xamarin Studio and MonoGame.

Joe lives with his wife of more than twenty years and his three daughters in Montgomery, Alabama. Every summer, Joe teaches high school students how to write games during an intense weeklong course in North Carolina for Landry Academy. He occasionally does the same for local kids in his hometown.

In his free time, Joe dabbles in sketching, cartooning, and creating 3D models. When you see his artistic creations, you’ll understand why he makes his living as a programmer.

{pagebreak}

About the Series

After my first book was published, people often asked if I would ever write another. My somewhat-joking response was, “My wife says I won’t.” It takes a special kind of numbskull to take on such a huge undertaking that promises so few rewards. I spent a year of my life, locked in my home office or sitting at Starbucks, working on those 760+ pages. All the while, I was working more than 40 hours a week at my “day job” (consulting). That’s a lot of missed cheer camps, soccer games, basketball games, and general veg time with the wife and kids.

Still, it’s an experience that I wouldn’t trade. Writing scratches a creative itch for me. There’s something fulfilling about completing such a large project. Especially when it is so well received by the readers. Thanks, guys!

The first time around, I learned a lot about what it takes to make a good game-programming book. I put that knowledge to use while creating these titles. I appreciate all the feedback I received. This work has benefited from it greatly.

In this series, I follow the same general principles that drove the first book. I write the books that help the beginner without boring the more-experienced readers to tears. I write the books that contain examples that go beyond rainbow triangles and 3D cubes with crate textures. In short, I write the books that I, as a hobbyist game developer, would want to read. If you enjoy the book as well (and I sincerely hope you do), I consider that an added bonus.

There was so much content to cover in this new work that I decided to break it into five separate volumes (plus a sixth volume for my annual summer camp on game programming). Each book stands on its own. As much as possible, later volumes don’t assume that you own the previous volumes. If, for example, you want to dive into 3D and you have a few XNA or MonoGame game projects under your belt, then, by all means, jump straight to Volume 3: 3D Genre Studies.

Volume 1: Building Blocks

This book provides a solid foundation upon which to build your own games using MonoGame by exploring the background of the underlying technologies, providing an overview of those technologies, and reinforcing what you learn with working examples. Whether you’re a C# programmer who has never written a game before or you’re an XNA veteran, this volume will help you build great games for a variety of devices.

Best of all, it doesn’t matter if you’re developing on a Mac (using Xamarin Studio) or a PC (using Xamarin Studio or Visual Studio). You will find examples (including three fully-functional games) that will get you up and running quickly.

Volume 2: 2D Genre Studies

This book builds on what you learned in Volume 1 (or from Google, if you decided to skip the first book) to write seven actual games - from scribbles on a napkin, to packaged games that are ready to push to a variety of app stores.

Volume 3: 3D Genre Studies

Volume 3 injects Volume 2 with steroids, and then microwaves it on full power for 42 seconds. From concept to creation, you’ll learn the tools and techniques for taking your games into the 3rd dimension.

In this book, after a fairly detailed introduction to 3D programming concepts, you are taken through the process of building six fully functional games. If you happened to work through Volume 2, you’ll find that a few of these games may seem familiar. Several of the chapters focus on creating 3D versions of 2D games. This is a great illustration of the separation of the game world from the view (the data from the rendered view of the data).

Volume 4: Multiplayer Games

This book gives you the tools and knowhow to make your games more social. This volume explores several facets of multiplayer game modes. From simple AI, to single-device multiplayer support, to LAN-connected games, to internet-connected games, you will learn how to take your creations to the next level. Along the way, we will discuss spit-and-polish concepts like chat, leaderboards, and 3rd-party matchmaking (e.g. Twitter and Facebook authentication).

Volume 5: Tasty Bits

This book explores more advanced concepts like threading, performance tuning, and localization. This is my vanity volume. It’s a collection of topics that interest me greatly. I hope they interest you as well, but if there’s any one book in the series that was written with me as the intended audience, this is it. In addition to the typical technical yadda yadda, this volume includes a couple of chapters on version control and team collaboration.

Volume 6: Code Camps

This book is a stopgap measure to get content into the hands of my students as quickly as possible. I’ve been teaching game programming to teens and tweens since 2011. Each year, we’ve used XNA as our platform, and my 2007 book on XNA as the reference. As of 2014, XNA support was officially dropped. This book is a collection of the games my students have created, with some tweaks and polish, modified to target MonoGame.

While Volume 6 is the first out of the gate, I plan to use my copious free time to work on the remainder of this multi-volume set of books that teach game programming in greater detail, with greater depth.

{pagebreak}

About the Reader

I would love to say that you should buy this book if you have a pulse and you’re able to read and comprehend written text. I would love to say that you can pick up a book and a compiler and start writing games after just a weekend of reading. I can’t say that, though. I’ve made every attempt to make sure that someone who is new to game programming can easily follow the progression of ideas and concepts from introduction to implementation, while still keeping the interest of those programmers who have dabbled in game development or have written complete games, but this book will not teach you how to program.

If you have had any experience with writing programs (on any platform, in any language) you should be able to follow the examples in this book without any problems. If you don’t know what loops, variables, methods, and arrays are, then it’s time to pick up a good introduction to the C# language to which you can refer as you read this book. Games are frequently trivialized since they lie squarely within the realm of recreation and entertainment, but game programming is actually one of the most cerebral forms of programming that you’ll ever do.

I hope that I haven’t scared you off. If you have a passion for games, and you have a vision that you would like to see come to life, then I firmly believe that you can make it happen, and I believe that this book will help you. I just don’t want you to think that you’ll be developing the next Gears of War or Gran Turismo in a weekend, especially if you’ve never written a line of code in your life. Read the book. Answer the review questions. Work through the exercises. Modify the example code. By testing your assumptions, you’ll be able to know when you’ve mastered the material. Then you can combine those core concepts in different ways to create great games.

{pagebreak}

Contact Me

If you have any questions, notice any errors, have general feedback, or have suggestions for topics that you would like me to cover in future editions of this book, a new book, or in an article on my website, please email me at xnabook@codetopia.com. I’ll try my best to reply to every email that I receive.

I’m fairly active on Twitter (@groundh0g), and Facebook (http://fb.com/groundh0g). My main website is http://www.moreoncode.com/. That’s where my blog lives. I plan to post articles, provide downloadable content, and host a forum for questions about the books.


About the Examples

The examples from this book are generally derived from the games that my students have designed and written. But, it is my book, so I might throw an example or two in there that I’ve unsuccessfully lobbied for in the past. In particular, I’m a huge fan of puzzle games and I’d like to write an example based on one of the music hero games.

The examples in this book will be cleaned up, follow a more structured design, and use assets that are freely available.

Why “Clean Up” the Examples?

The answer to that question is twofold: code quality and asset licensing.

Code Quality

In the years that I’ve been teaching game development, only one student had any prior programming experience. The camps last just one week. The first day is spent installing tools and brainstorming ideas. Five days later, we have to demonstrate a working game in front of the other students at the camp.

Our design document is a whiteboard sketch with a bullet list of features that are added on day one, and crossed out as the deadline marches ever closer.

Regardless of the game we plan to tackle for the week, we start with loading an image, moving that image, then controlling the image with the gamepad. Features from the whiteboard are then prioritized, and implemented in order. The class can only move as fast as the slowest typer, so features necessarily get cut.

Asset Licensing

The first game programming camp, in 2011, used characters from the Angry Birds™ franchise, which is owned by Rovio Entertainment Ltd. An argument could be made that using the birds and pigs would be allowed by the “Fair Use” clause of the Copyright Act of 1976 in a classroom setting.

I don’t know if the same would apply to a book. I would essentially be distributing the intellectual property of an entity without their permission. I’d rather use assets that I create, or those from the public domain, removing any doubts surrounding the legality.

Thankfully there are many talented artists out there who contribute to the game development community. Most notably in the context of this book, Kenney, Danc, and Sergiu, who were mentioned in the Special Thanks section.

{pagebreak}

About My Motivation

Since 2011, I have been teaching teens and tweens how to write video games using XNA. Now that XNA support is officially being dropped, I need a new reference for the class - one that’s centered on MonoGame.

That’s So 2007

My XNA book was written in 2007. While I kept the sample code updated through the latest XNA version (4.x), I never wrote a second edition.

Contrary to popular belief, the major impedance for an update wasn’t laziness on the part of the author. I realized that printed text just cannot keep pace with the velocity of technical change. My book (one of the first four XNA books) was practically out-of-date when it hit the shelves. The book targeted version 1.0 of XNA, but as it was headed to the presses, XNA 1.0 Refresh was released.

I was able to add a chapter to cover the differences between the two versions, but XNA was updated regularly. I decided early on that my time would be best spent updating the examples on my website and documenting the changes between each release on my blog.

This time around, I’ll try to make the text more future proof by focusing on the timeless aspects of game design and mechanics, rather than the details of a particular implementation based on a specific MonoGame version.

Classroom Media

My XNA book had review questions and exercises for each chapter. That made it a popular choice for high schools and colleges. But, I never created a media pack for the content.

This time around, my focus is on using this in a classroom setting. So, you can expect to see some slideshows, answers to the questions, and examples for the exercises - separate from the book, of course.

{pagebreak}

About This Volume

This volume introduces the basic concepts behind writing cross-platform MonoGame games.

As you work through this volume, be sure to experiment with the example code. Don’t just read the chapter text and follow the examples verbatim. You’ll do your best learning when you test your assumptions and find them to be invalid. Working through issues will ingrain what you’ve learned much better than merely reading some printed text.

“Our greatest glory is not in never failing, but in rising up every time we fail.”
– Ralph Waldo Emerson

I believe we learn best from failure. Success teaches us precious little. We learn what works by stumbling, fumbling, and floundering over that which does not work. If you never make a mistake, you are not learning. You are simply following someone else’s recipe for success. I can confidently assure you that the author of the recipe did not create it on their first attempt, complete and without error.

As you read each chapter in this volume, don’t focus too much on how something was done; try to understand why it was done a certain way. In programming, there are many paths that lead to the same result, each with its own pros and cons. You may think of a better way to accomplish a given task. Use the code from these chapters as a starting point for your own creations.

As you progress in your understanding of MonoGame and of writing managed code, take this concept a step further and try to understand why the framework APIs were designed using the interfaces that you see. What do you think those APIs are doing with your data? How do you think they’re processing your requests? How would you have written the API? What interfaces would you have used to expose that functionality to other developers? Why do you think the XNA framework developers (the inspiration for MonoGame) made the design decisions that they made?

{pagebreak}

Chapter Overviews

The following text provides an overview of the content you will find in this book. I recommend that you read chapters 1 through 4 before attempting later chapters. Once you have laid that foundation, you can skip around as much as you like.

Chapter 1: A Brief History

This chapter provides a good overview of the technologies upon which MonoGame is based. MonoGame, Xamarin Studio, Visual Studio, DirectX, OpenGL, Mono, and the .NET Common Language Runtime (CLR) are introduced, and each component’s role in the game development process is described, along with its history.

Chapter 2: Your Development PC

This chapter takes you through the steps of configuring your development environment and making sure that everything is working properly. This chapter also discusses several content creation tools that you can install and use to generate audio, graphics, and 3D models for your games.

This chapter also walks you through the basic features of Xamarin Studio. You will learn how solutions and projects are laid out, how to build your games, and how to identify and troubleshoot problems within your game code. If you’ll be primarily developing your games on a Mac, this is the IDE for you.

This chapter additionally walks you through the basic features of Visual Studio Express Edition. You will learn how Visual Studio solutions and projects are laid out, how to build your games, and how to identify and troubleshoot problems within your game code. If you’ll be primarily developing your games on a Windows PC, Visual Studio is an attractive alternative to Xamarin Studio.

Visual Studio is arguably the best IDE on the planet. I’m a Mac guy, though, so I primarily use Xamarin Studio. Even if you’re a die-hard Mac user, you will (at the time of this writing) still need to use Visual Studio for some of the more advanced features, such as shader effects where the content pipeline of MonoGame isn’t quite complete. You’ll also need to fire up Visual Studio if you plan to write games that target Windows Phone 8.

Chapter 3: The Crash Course

If there is only one thing you will take away from this chapter, it’s “Update, Draw, Update Draw, Update, Draw, Update, Draw, …” That’s the game loop. It’s the heartbeat of every game you’ll ever design, build, or play.

We begin with a blank screen, load an image, move the image programmatically, then use player input to move the image. Once the basics are covered, we’ll build our first game - a top-down scroller where you pilot a starship, firing lasers at asteroids and aliens.

After you complete this chapter, you’ll be able to jump to any of the following chapters that capture your interest. But you might want to take a look at the next chapter first. It gives a little insight into the dreaded “last 20% of the project” - the bells and whistles.

Chapter 4: Spit and Polish

We built a playable game in the previous chapter, but it’s not exactly store-worthy. I’m not saying that it ever will be, but there are some obvious changes that we can make to give the game a more professional feel.

Building on the game from the last chapter, we’ll add music, sound effects, visual effects, and multiple screen types. We’ll also introduce the concepts of sprite sheets and basic particles.

After you complete this chapter, you’ll be able to jump to any of the following chapters that capture your interest.

Chapter 5: Camp 2011 - Side Scroller

The player will control a super hero, defending a nameless city from evil robots who fire a seemingly endless barrage of rockets. This chapter builds upon the fundamentals of the previous chapters to showcase slightly more sophisticated visual effects.

Chapter 6: Camp 2012 - Survival

This game supports one to four players who fight of wave after wave of baddies. Since this is our first multi-player game, we’ll need to add a new screen type - one where each player can select their avatar.

Players can move left or right, and away or towards the screen. And … pause for effect … they can jump! So this marks the first time we’ll need to track three components for location - X, Y, and Z. Even though this is a two-dimensional game, we’ll track all three dimensions, where Z is the distance between the player and the ground during their jump.

Chapter 7: Camp 2013 - Runner

need content

Chapter 8: Camp 2014 - Castle Crawler

Building on what we learned in Chapter 6, this game supports one to four players who explore a castle filled with baddies and treasure. They must fight their way to the castle’s keep and defeat the monster therein.

Chapter 9: Class 2013 - Platformer

need content

Chapter 10: Class 2014 - Tower Defense

need content

Chapter 11: Class 2015 - Real-Time Strategy

need content

Chapter 12: Author’s Choice - Puzzle

Most game genres have a fairly narrow demographic to which they appeal. Typically, that demographic is young males. Puzzle games are one of those rare categories of games that cross gender and age barriers. Their simple, yet addictive game play seduces the casual gamer and the hard-core gamer alike. They even appeal to many people who wouldn’t consider themselves “gamers” at all. With a focus on problem solving, and having their roots in logic and math, puzzle games prove that simple games can be fun, even without a multi-million-dollar development budget or a big-name intellectual property license.

In this chapter, we will develop a simplified clone of my new favorite puzzle game - GungHo’s Puzzle & Dragons.

Chapter 13: Author’s Choice - Artificial Intelligence

Board games are another of those categories of games that have mass appeal, and many of the most popular board games have been around so long that copyright issues are no longer a concern, so they can be a great source of inspiration for your original titles.

In this chapter, we will develop a simple version of a popular board game that originated in England around 1880 - Reversi. And to support folks like me who don’t have any friends, this game will feature a CPU opponent. You can pass-and-play against a friend, or play against the game’s AI.

Chapter 14: Odds and Ends - GamePadEx

The mouse, keyboard, touch screens, and game pads are very different devices, each requiring specialized code. In this chapter we’ll develop a helper class that allows you to use the keyboard as a controller. That’s useful when you’re working on a game from your laptop and don’t have a controller handy, or if your game supports multiple players and you only have one controller with you.

Chapter 15: Odds and Ends - TouchPanelEx

need content

Chapter 16: Odds and Ends - Collision Detection

Nothing irritates players more than thinking that they hit an opponent and the hit doesn’t register, or thinking that they dodged a bullet only to find that they’ve lost a life. For most game programming tasks, “close enough” is perfectly fine. Collision detection isn’t one of those tasks, though.

In this chapter, we will develop a reusable class to help us manage pixel-perfect 2D collision detection.

Chapter 17: Odds and Ends - Particles

Individual particles are usually rather insignificant. But collectively, particles can be used to great effect, with minimal resource consumption. In this chapter you will create a simple 2D particle system that we can use to give our games a little flair.

Particles are light-weight game objects that act as independent entities. Global forces like gravity and wind may affect particles, and they may vary their color or opacity over time (for example a burning ember may fade to nothing). Particle systems are used in a wide variety of game genres, for a wide variety of in-game effects. Some examples include: sparks from a racecar as it scrapes the wall, wash from a snowboard when it slides to a stop, smoke trails behind missiles, exploded fragments of a game object, auras surrounding a mage as she casts a spell, embers from a fire, splash from an object that hits the water, and many more effects.

{pagebreak}

NAQs

The book hasn’t been published, so this is a list of Never Asked Questions.

Why did you write “Volume 6” first?

I’ve been using my 2007 XNA book to lead the game programming camp since 2011. XNA was officially mothballed in 2014, so I wanted to have a new reference for my 2015 camp. I’ve made a few contributions to an opensource project, called MonoGame, that provides an an API-compatible replacement for XNA.

My ultimate goal is to write an encyclopedic series with more detailed explanations and more elaborate examples. That effort will take longer than a year, but camp is coming up quickly. So, Volume 6 is a stopgap measure to get me through my 2015 obligations.

What tools do I need?

I personally use a MacBook Pro, but the vast majority of my students use Windows PCs. As for software, I’ll walk you through a list of tools for game development in Chapter 2.

But, the two most important tools are your desire and dedication. If you have those, the rest will come in time.

Can I get the game that the students created?

Absolutely. I’ll include the unaltered code alongside the examples from this book so that you can compare the two.

Can I really make my own games and sell them?

Yep. In many cases, you can develop and test your games for free. When your game is ready to publish, there may be licensing fees, depending on the platform(s) you’re targeting.

{pagebreak}

This page was intended to be blank, until I wrote this sentence on it.


Chapter 1: A Brief History

Overview

This chapter provides a good overview of the technologies upon which MonoGame is based. MonoGame, Xamarin Studio, Visual Studio, DirectX, OpenGL, Mono, and the .NET Common Language Runtime (CLR) are introduced, and each component’s role in the game development process is described, along with its history.

What is MonoGame?

MonoGame is an open source implementation of the Microsoft XNA 4.x API that can be used to create cross-platform games (or to easily port existing XNA-based Windows, Windows Phone, and Xbox 360 games to other platforms) using the C# language. Currently supported platforms include Windows GL, Windows Phone, Windows 8, Mac OS X, Linux, Android, iOS, PlayStation Mobile, and the OUYA console.

Under the covers, MonoGame is powered by OpenTK (a C# library that wraps OpenGL, OpenCL, and OpenAL), SharpDX (a C#-compatible wrapper to the DirectX APIs), and Lidgren.Network (a C#-compatible networking API). These technologies are what enable MonoGame to support so many disparate platforms.

What is XNA?

In 2005, Microsoft released a line of products for hobbyists, students, and novice computer programmers, distributed under the “Visual Studio Express” moniker. Since their initial release, Microsoft has continued to provide updates to the Express line of development tools as their commercial counterparts (the industry-standard IDEs for Windows development) are released.

These free tools allow the average home user to explore and experiment with software development without having to invest a lot of (or in most cases, any) money. You can develop utilities, desktop applications, websites, relational databases, and more using tools that have traditionally retailed for hundreds of dollars.

In the summer of 2006, Microsoft released another Express tool, targeting aspiring hobbyist and student game developers. That new tool was called XNA Game Studio Express. XNA provided a suite of tools and APIs that combined the power of DirectX with the ease-of-use of the .NET Framework, all accessed via managed code, using the C# programming language.

Popular among hobbyists, enthusiasts, and independent game development studios, XNA has been actively developed by Microsoft through four major versions, and it remains a supported toolset for game development on Windows, Windows Phone, and the Xbox 360 game console.

Why Not Just Use XNA?

The main reason to favor MonoGame over XNA is that XNA only runs on Microsoft platforms. MonoGame supports those same platforms, plus a slew of others.

Another reason to move from XNA is revealed in an internal Microsoft email, leaked in early 2013, which makes it clear that XNA Game Studio’s current version, Game Studio 4.0 Refresh, released in late 2011, will be the last.

“Presently the XNA Game Studio is not in active development … further value and engagement cannot be offered to the MVP community. As a result, effective April 1, 2014 XNA … will be fully retired from the MVP Award Program.”

Gamasutra.com and Polygon.com, both referencing an article from ComputerAndVideoGames.com entitled, “Microsoft ‘to axe XNA’,” offered a more official announcement of XNA’s demise that contained the following information.

A spokesperson for Microsoft at the PR firm Waggener Edstrom has insisted that… [Microsoft’s] move away from XNA will not affect games built with the development framework.

“DirectX is the world’s leading low-level interface for gaming and graphics. Microsoft is actively investing in DirectX as the unified graphics foundation for all of our platforms, including Windows, Xbox 360, and Windows Phone. DirectX is evolving and will continue to evolve. We have absolutely no intention of stopping innovation with DirectX.”

“XNA Game Studio remains a supported toolset for developing games for Xbox 360, Windows and Windows Phone. There are hundreds of XNA games available on Windows Phone and thousands of XNA titles available on Xbox 360. Games built with XNA run without changes on Windows 8 and Windows Phone 8.”

Microsoft is pushing DirectX as the unified graphics solution for all their platforms. That means that future games will need to be developed in native languages that target DirectX directly, or managed code that targets some 3rd-party abstraction to DirectX.

A Brief History of DirectX and XNA

When Windows first entered the PC consumer market, it addressed several very real needs. Before Windows, programs monopolized a PC’s resources. To run one application, you had to close another. Application developers had to write special-case code to support a wide variety of video cards, audio cards, and peripherals for all but the most basic of programs.

Windows provided a unified platform that application developers could target. This new platform provided (cooperative, at first) multi-tasking services and memory management services so that several applications could run simultaneously. This new platform also provided hardware abstractions that allowed application developers to target a single set of APIs for devices like printers, video cards, and audio cards.

For standard applications like spreadsheets and word processors, these abstractions were a godsend. They allowed the application developer to focus on the functionality of his application rather than the low-level inner-workings of the various hardware devices that were installed in his users’ PCs.

For game developers, however, these abstractions resulted in unacceptably slow interactions with the hardware. Most games in the early days of Windows required users to completely exit Windows and start the game from the command line.

Microsoft’s first attempt to address the performance needs of game developers was WinG, the predecessor of the DirectX APIs that we know today. DirectX provides a set of APIs, separate from the standard Windows APIs, to access hardware devices. These APIs, and their underlying device drivers, are highly optimized for performance.

While DirectX provides game developers with a means to write high-performance games that run within the Windows environment, it’s not the easiest API in the world to master. A veteran game developer can do amazing things with DirectX, but it can be a little intimidating to folks who are new to game programming. XNA Game Studio and the XNA Framework mask that complexity, allowing game developers to focus on their game’s content and game play.

What Is Managed Code?

On most development platforms, source code is compiled directly to native binaries that can be loaded and executed on the target processor (CPU) with no supporting runtimes or libraries. The executable file that’s created for these platforms contains the actual instructions for the targeted processor. For managed code, your source is compiled to an intermediate language (IL). This IL represents the instructions of a virtual, platform-agnostic CPU. This virtual CPU doesn’t actually exist anywhere but in software.

To run managed code on an actual CPU, there needs to be some intermediary between the managed executable and the physical processor. This intermediary, known as the runtime, is a program that was compiled to the target processor’s native instructions. The runtime then acts as a virtual CPU, emulating the non-existent, virtual CPU on the physical CPU.

This concept is illustrated in Figure 1-1.

Figure 1-1 Comparison of Native and Managed Executable Files

Emulating virtual CPU instructions sounds inefficient, doesn’t it? Actually for most applications, you would likely see only nominally lower performance over the same basic native code. But most managed code runtimes (Microsoft’s included) support a feature known as just-in-time compilation (JIT). The JIT compiler takes the intermediate language that was generated by the managed compiler and generates native code that’s optimized for the targeted physical CPU just before the code is actually executed on the physical CPU. While there is still some overhead imposed by having the runtime layer between your application and the physical CPU, JIT compilation closes the overall performance gap between your managed code and it’s native cousins.

That sounds interesting, but why include the additional complexity? What does targeting managed code offer an application developer that they wouldn’t normally have when writing native code?

A major benefit comes in the area of memory management. In traditional languages that compile to native executable files, memory leaks are a common problem. It’s easy for developers to forget to release system resources that they allocate, especially when complex code paths or exception handling are involved.

In managed code, like native code, memory is allocated as it’s needed. Unlike native code, the managed runtime keeps track of these allocations and any references to them. When the resource is no longer referenced by any of the live objects in your application, it’s automatically released by the runtime. There are still a few special cases where leaks can occur (especially when dealing with unmanaged resources from your managed code), but memory management basically comes for free in a managed environment. This feature of managed runtimes is known as garbage collection (GC).

Another benefit of managed code is platform agnosticism. Since your code targets a virtual CPU, it has no direct ties to the physical CPU on which it runs. That means that your managed code should be able to run on any platform that provides a runtime for it. For instance, (in theory) an application written in managed code could run on PCs, handheld devices, mainframes, or even game consoles.

Having code that can execute on any platform is neat, but without access to components beyond the CPU, your code won’t be able to do anything useful. In addition to the runtime, managed environments also include a set of APIs that allow you to access the native OS features via abstractions that won’t tie you to a specific platform. These APIs include classes that: allow you to access the file system to read and write files, utilize the user interface components of the operating system (like buttons, checkboxes, and menus), control peripherals (like printers), and access media components (like the sound system and screen).

What Is the Role of MonoGame?

Accessing the native host components through an abstraction layer is generally slower than accessing those same resources natively. In the case of the printer or file system, the performance difference isn’t very noticeable. The device itself is slower than the abstractions—your code spends much of its time waiting for the device to complete issued commands.

In the case of components like the graphics system, however, the cost of abstraction is much greater. Updating millions of pixels every second requires a lot of CPU power, even when using native code. Thanks to advances in graphics hardware, a lot of that graphics processing can be offloaded to the graphics card itself by way of specialized programs that run on a secondary CPU that’s embedded on the graphics card known as the graphics processing unit (GPU). By running these specialized routines on the GPU, your application is only responsible for coordinating the efforts of the GPU and for shuffling required data to and from graphic memory.

The MonoGame Framework includes a set of managed libraries that provides access to these advanced hardware features using a technology known as OpenGL. Whereas DirectX is a technology that is tied to Microsoft platforms such as Windows, Windows Phone, Zune, and the Xbox 360 game console, OpenGL provides the same abstractions to graphics hardware, in a cross-platform API (which happens to include support for the various flavors of Windows). As with DirectX, OpenGL provides APIs and underlying device drivers that are highly optimized for performance.

In addition to the graphics hardware, the MonoGame Framework supports input devices and audio via managed wrappers to the underlying native APIs.

MENTION CONTENT PIPELINE HERE?

The .NET Framework is fast becoming the leading platform for developing general-purpose Windows applications that run on the desktop, the web, and mobile devices. The MonoGame Framework relies on .NET Framework components like the Common Language Runtime and the core class libraries, but the MonoGame Framework has been specifically designed and optimized (based on XNA 4.x APIs) for developing games.

When you’re accessing the file system, managing threads, or dealing with collections of data, you’re using the .NET Framework. When you’re playing music, rendering 3D objects, or displaying a heads up display in your game, you’re using the MonoGame Framework. These two frameworks complement each other, greatly simplifying the Herculean effort of writing great games.

While you will still need to build separate packages for each targeted platform, MonoGame makes it possible to write code that is portable across a variety of devices and operating systems, with little or no modification.

What is Xamarin?

Mono is an open source implementation of Microsoft’s .NET Framework, based on the ECMA standards for the C# language and the Common Language Runtime (CLR). Mono enables the creation of applications on platforms such as Linux and Mac OS X using .NET technologies.

Xamarin is a company that sponsors Mono development, and is heavily invested in the future of Mono as an emerging technology. Xamarin offers a suite of tools and APIs that make it possible to write applications for Apple’s iOS devices and Google’s Android devices using the C# language. Platform-specific, native APIs are exposed as .NET bindings to your code that runs on the CLR implementations for iOS and Android that Xamarin created.

You can develop mobile applications using Xamarin’s own, full-featured IDE, Xamarin Studio, or you can leverage your experience in Microsoft’s Visual Studio to create, build, debug, and deploy your applications using the industry standard IDE for .NET development. I make my living writing Windows applications in Visual Studio. When I’m off the clock, though, I’m a Mac guy. On my MacBook Pro, I’m a big fan of Xamarin Studio for OS X, Android, and iOS development.

What Role Does Managed Code Play in Games Today?

As a standard for Windows application development, C# is often used as the language of choice for writing the tools that support game development. And C# has been used to write some really great Windows games. But for performance-critical applications, game developers typically use languages that target native code, like C and C++. Before the introduction of the XNA Framework, C# wasn’t really the best option for developing high-performance games like first-person shooters or 3D racing games.

While C# is a relative newcomer to the area of game development, managed code has been used to script game objects and AI for a while now. Many times, developers will embed script parsers for game logic, and use native code only for those areas of code where performance is critical.

Native game code is the domain of the expert programmer. Using scriptable objects makes it easier to have level designers implement basic object interactions and frees up the more experienced developers to handle the tricky, more technical areas of the code. As an added benefit, having your designers implement object interactions eliminates the communication barriers between the designers and the developers who often seem to speak different languages.

Of course, there’s a time investment in getting the designers started and in supporting them in their efforts; but typically, developers find that the designers are able to use the scripting engines in ways that they never envisioned, leading to incredibly creative and innovative level designs. And since the designers don’t need to rely on the developers to make changes to the code whenever they want to tweak their designs, the overall turnaround time is reduced, and the designers can try many more variations on their themes than would typically be possible in an often-too-tight product development cycle.

The MonoGame Framework makes it easier for individuals and small teams to reap the benefits of reduced development times and lower levels of complexity typically seen when using a scripting engine, while also gaining the performance benefits of native (JIT’ed) code that targets the OpenGL APIs.

Now you don’t need to be a veteran game developer to write great, commercially viable games. Of course, those veterans will be able to make the MonoGame Framework do things that a novice can only dream of, but in the realm of traditional native code, most entry-level developers would have a heck of a time just trying to get their game project off the ground.

What Platforms Does MonoGame Support?

Figure 1-2 Development Platforms

{pagebreak}

Summary

MonoGame and Xamarin Studio make game development easier and more approachable for novice, hobbyist, and student developers by providing out-of-the-box support for many of the most common game programming tasks. By using MonoGame and managed code, your ideas will move from doodles on a napkin to playable games on your PC or mobile devices faster than ever before. Your code will be more robust and resistant to crashes. And you’ll be able to do all of this without emptying your wallet.

In this chapter, you learned what MonoGame is and how it can help you to write games for a variety of platforms. You also learned what managed code is and how it can make life easier for game developers. In the next chapter, we will get these tools installed and prepare your development environment so that you can start bringing your game ideas to life.

Review Questions

Think about what you’ve read in this chapter to answer the following questions.

  1. What are two benefits of writing applications in managed languages like C#?
  2. Can I develop commercial games using MonoGame?
  3. What is DirectX? How does DirectX help me to write video games?
  4. What is OpenGL? How does OpenGL help me to write video games?
  5. What is the role of the MonoGame Framework with respect to OpenGL and DirectX?

Exercises

EXERCISE 1. Write down a game idea that you have. Try to be specific in your description of the game play. Where does the action take place? What entities and objects exist in your game world? How to they interact with each other. Don’t focus on the technical aspects; just document your idea from a game player’s perspective. As you progress through the book, consider how what you learn can be used to implement your idea. Revisit your notes frequently, revising them as you go. When you feel comfortable with the tools and technologies that you’re reading about, start fleshing out your design, and start writing a prototype —a playable, “proof of concept” of your game idea.

EXERCISE 2. Pick a game that you enjoy playing. As you progress through the book, start thinking about how that game was designed and written. How would you write it? When you’ve reached the end of the book, try to write a simple clone of this game. Don’t focus on the overall game. Try to break it down into smaller, more manageable components that you feel comfortable writing. Then put those components together to create the more complex whole. Don’t worry about making a commercial-quality game. Just try to capture the essence of what makes the game enjoyable.


Chapter 2: Your Development PC

Overview

This book is based on my work with the kids at camp. And, at camp, we only have five days of class time to conceive and build a working game. Most of the students have no prior experience with programming.

Day one involves installing the tools that we’ll use while discussing the game we’d like to make. Then we write a simple “game” to make sure that our development environment is properly configured.

Following that same model in the book, we will cover the installation of the tools in this chapter and then ensure our development environment is properly configured. We’ll actually build a simple game in the next chapter.

Supported Target Platforms

The whole point of MonoGame is to provide a single framework that runs on as many devices as possible. That list is large, and it will continue to grow.

To keep things simple in this book, I’ve decided to limit the discussions to running games on the three development platforms - Windows, Mac OS X, and Linux. The rationale was simple. You’re already using your development machine to write your game, and you’ll need to run and debug on that platform anyway.

NOTE: I may make one exception. I’m excited about writing code for my PlayStation Vita, and technically, it’s a different development platform (well, a different IDE on Windows).

Time permitting; I’ll add one or more chapters at the end of the book to cover the specific issues you’ll need to account for when targeting the other platforms. At a minimum, all of the examples should have buildable and runnable projects that you can download for all the platforms that I’m able to support.

The phrase, “that I’m able to support”, sounds suspicious. What do I mean by that? Well, it basically means two things:

  1. The MonoGame implementation for the target platform is stable enough to support my example game.
  2. The example makes sense on the platform – e.g. you’re probably not using a touchscreen and accelerometer with your Ouya, and you’re not likely to use a mouse with an iPhone.

Supported IDEs

I know that the MonoGame build process supports a Visual-Studio-driven workflow for Xamarin build tools (for example using Visual Studio to kick off Xamarin tools on a Mac to build and debug iOS apps from Windows), but I want to keep the scope of this volume narrow. I’m assuming that you’re using MonoDevelop (Xamarin Studio) as your primary development environment, running on one of the three OSes mentioned earlier.

Honestly, though. Once your development environment is configured (you know, by clicking Next, Next, Next, … from the installer), the game code is very similar. It’s just the application hooks that vary. And you really shouldn’t have to worry about that if MonoGame is doing its job well.

For the Mac OS X and Linux platforms, I recommend that you run the latest version of the operating system available. In fact, the primary development tool for OS X, XCode, won’t install unless your computer is running the latest version of the operating system. In the case of Windows, however, I’ll be the first to admit that I’m prejudiced. I just don’t like Windows 8, so I still use Windows 7 when developing for the various Windows platforms. I’ll be sure to test every example in the book within a Windows 8.x environment, though.

NOTE: I really hate detailing the installation process in a book. Technology moves so fast that the steps described in this chapter may be obsoleted by the time you read them. For example, MonoDevelop may have a kick-butt template system where you can generate new MonoGame projects out of the box with just a few clicks. That’s not the case today. So, I’ll fight my instincts and document the steps that I took when creating the examples for the book - including the steps to prepare my development environments.

A Note on Project Templates

I love project templates – when they work, that is. But templates have a tendency to become outdated and broken. For XNA, the project templates were a part of the release. When each new version came out, there was a new “click here, here, and here” to create an empty project for the new version of the APIs.

With MonoGame, the templates aren’t a part of the release. They’re maintained separately. That’s why I’ve decided to provide you with handcrafted “empty” projects for each platform. Each contains all the components required to write your game. MonoGame may move on (and likely will have moved on) to a new version by the time you get around to writing your next Cut the Rope killer, but it won’t matter. Everything that you need will be included in the project – including the version of the MonoGame framework that was used to build it.

After detailing the installation process for the tools, I’ll describe the process of creating empty MonoGame projects for each platform (hooray for Color.CornflowerBlue!) so that you know what’s going on under the covers if you’d like. You can feel free to skip those details for now. They’ll be here waiting for you if you need them later. In fact, I suggest that you do ignore the “Empty Project: {Target Platform}” sections for now. Come back after you have a few MonoGame projects under your belt. It should make more sense then.

NOTE: For the curious, my personal workflow is to build each example game in Xamarin Studio on my MacBook Pro. I then make sure the same example works in Windows, before moving on to the next. When all the examples have been written, I’ll return to spackle the gaping holes in platform support.

Along the way, I’ll test the odd example on one of the other platforms (like Android, Ouya, or PS Vita - since they’re free to deploy) just to make sure there aren’t any systemic flaws in the organization of the example games.

{pagebreak}

Installing the Tools: Mac OS X

If you do any OS X or iOS development, you’ll need to install XCode - the primary development environment for those platforms. As I mentioned earlier, XCode won’t install unless your computer is running the latest version of OS X. So, your first step may be to upgrade your OS. Luckily, it appears that Apple has decided to release their new OS upgrades for free.

To install XCode, just open the App Store and search for “xcode”. It should be the first app in the list. This would be a good time to freshen up your coffee. The download and installation of XCode can take a while.

Once XCode has been installed, you will need to run it once so that the components can be initialized. As soon as XCode finishes launching for the first time, you can close it. We’ll spend as little time in XCode as possible. Most of our tasks can be handled using MonoDevelop.

Speaking of which, now’s the time to download MonoDevelop (Xamarin Studio) and the Mono Development Kit (MDK). Both links can be found on the “Download” page of the MonoDevelop website using the following URL.

   http://monodevelop.com/

Once the downloads have completed, you’ll want to install the MDK first, and then MonoDevelop.

When those steps are complete, you should have a fully functioning development environment. Both Xcode and MonoDevelop (Xamarin Studio) should appear in both the OS X Launchpad and in the Applications folder.

Verify the Installation: Mac OS X

Go ahead and launch Xamarin Studio. Unless you change the default behavior in the settings, every time Xamarin Studio runs, it will check for updates. Chances are pretty good that there will be an update available the first time you open the application. So, give it a few minutes before you move on.

We begin by creating a new MonoMac project. Create a new solution by selecting File / New / Solution from the menu. The “New Solution” dialog will open. Expand the “Unsupported” option in the left pane. Select “MonoMac (OpenSource)”, and then select the “MonoMac Project” in the middle pane. Let’s name our new solution “MyFirstApp”. Click the OK button. In a few short seconds, you’ll have a shiny, new MonoMac application project.

Click the Play icon at the top, left of the IDE or select Run / Start Debugging from the menu. You’ll be rewarded with an empty gray window. Congratulations. You’ve just written your first MonoMac application.

The Mac OS X Development Tools.

{pagebreak}

Installing the Tools: Windows

Blah. Blah. Blah.

Verify the Installation: Windows

Blah. Blah. Blah.

{pagebreak}

Installing the Tools: Linux

Blah. Blah. Blah.

Verify the Installation: Linux

Blah. Blah. Blah.

{pagebreak}

Installing the Tools: Ouya

Blah. Blah. Blah.

Verify the Installation: Ouya

Blah. Blah. Blah.

{pagebreak}

Installing the Tools: PS Vita

Blah. Blah. Blah.

Verify the Installation: PS Vita

Blah. Blah. Blah.

{pagebreak}

Installing the Tools: iOS

Blah. Blah. Blah.

Verify the Installation: iOS

Blah. Blah. Blah.

{pagebreak}

Installing the Tools: Android

Blah. Blah. Blah.

Verify the Installation: Android

Blah. Blah. Blah.

{pagebreak}

Empty Projects

The team of developers that maintains the MonoGame project has created a new repository for sample games. Their goals were set forth in a post to the MonoGame blog from Simon Jackson on April 17, 2014.

… [T]he core MonoGame team set out with a purpose to being a new samples repository for the project. Its goals were simple:

The samples had to be of high quality. They had to work on ALL platforms not just one. Best practices had to be used where possible. They had to be testable and re-usable to test the latest builds (builds may not pass if samples tests failed) …

So, that sounds like a good place to start. When Simon posted the news item on the MonoGame website, there was a whopping one sample game – Platformer2D. But one is all we need. The samples repository can be accessed from the following URL.

   https://github.com/Mono-Game/MonoGame.Samples

Copy-and-Paste #1: Main.cs

We’ll be using the “Main.cs” from that example game for all our empty projects. It provides the launching point for all platforms using conditional compiler directives.

   using System;
   #if MONOMAC
   using MonoMac.AppKit;
   using MonoMac.Foundation;
   #elif IPHONE
   using MonoTouch.Foundation;
   using MonoTouch.UIKit;
   #endif
   
   namespace MyFirstGame
   {
      #if MONOMAC
      class Program
      {
         static void Main (string[] args)
         {
            NSApplication.Init ();
   
            using (var p = new NSAutoreleasePool ()) {
               NSApplication.SharedApplication.Delegate = new AppDelegate ();
               NSApplication.Main (args);
            }
         }
      }
   
      public partial class AppDelegate : NSApplicationDelegate
      {
         private MyFirstGame game;
   
         public override void 
         FinishedLaunching (MonoMac.Foundation.NSObject notification)
         {
            game = new MyFirstGame();
            game.Run();
         }
   
         public override bool 
         ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
         {
            return true;
         }
      }
      #elif IPHONE
      [Register ("AppDelegate")]
      class Program : UIApplicationDelegate 
      {
         private MyFirstGame game;
   
         public override void FinishedLaunching (UIApplication app)
         {
            game = new MyFirstGame ();
            game.Run();
         }
   
         static void Main (string [] args)
         {
            UIApplication.Main (args,null,"AppDelegate");
         }
      }
      #else
      #if !WINDOWS_PHONE
      /// <summary>
      /// The main class.
      /// </summary>
      public static class Program
      {
         static void Main()
         {
         #if WINDOWS || LINUX || PSM
            using (var game = new MyFirstGame ())
            game.Run();
         #else
            var factory = 
               new MonoGame.Framework.
               GameFrameworkViewSource< MyFirstGame >();
            Windows.ApplicationModel.Core.CoreApplication.Run(factory);
         #endif
         }
      }
      #endif
      #endif
   }

You can search and replace “MyFirstGame” with whatever your new project name is.

Copy-and-Paste #2: Game.cs

We’ll use the following Game.cs for all our empty game projects. I resisted the urge to include a simple implementation for LoadContent, Update, and Draw. I think that a blank, blue screen isn’t very impressive, but it’s the perfect canvas from which to start your own projects.

   using System;
   using System.Collections.Generic;
   using Microsoft.Xna.Framework;
   using Microsoft.Xna.Framework.Graphics;
   using Microsoft.Xna.Framework.Input;
   using Microsoft.Xna.Framework.Media;
   using Microsoft.Xna.Framework.Input.Touch;

   namespace MyFirstGame
   {
      public class MyFirstGame : Microsoft.Xna.Framework.Game
      {
         // Resources for drawing.
         private GraphicsDeviceManager graphics;
         private SpriteBatch spriteBatch;

         public MyFirstGame ()
         {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            #if WINDOWS_PHONE
            TargetElapsedTime = TimeSpan.FromTicks(333333);
            #endif

            //graphics.IsFullScreen = true;
            //this.IsMouseVisible = false;

            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 480;

            graphics.SupportedOrientations = 
               DisplayOrientation.LandscapeLeft | 
               DisplayOrientation.LandscapeRight;
         }

         protected override void LoadContent()
         {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: Load content
         }

         protected override void Update(GameTime gameTime) 
         {
            // TODO: Update world

            base.Update (gameTime);
         }

         protected override void Draw(GameTime gameTime)
         {
            graphics.GraphicsDevice.Clear (Color.CornflowerBlue);

            // TODO: Draw world

            base.Draw (gameTime);
         }
      }
   }

You can search and replace “MyFirstGame” with whatever your new project name is.

Empty Projects (About-Face)

I fully intended to document the steps for creating an empty project for each platform. But, once I got waste deep into the first platform, I realized how tedious and error-prone the process is. I’m going to provide empty projects for each platform on my website. If there’s enough demand, I’ll document the steps for one or two of the platforms as one or more blog posts.

In a nutshell, each platform is conceptually the same. You create an empty project, add in the cut-and-paste code snippets listed earlier (into Main.cs and Game.cs, creating them if they don’t exist), and then set some project properties.

I’ve written some helper classes to handle most of the platform voodoo, but they’re not referenced in the above snippets for the sake of keeping the code pure (pure MonoGame, that is).

Compiler directives that I pulled straight from the MonoGame Framework projects drive the “voodoo”. I’ll list them here for your convenience. Note that they are subject to change. So, you should check the latest values in the MonoGame repository if you’re having platform-specific issues.

Platform Constants
Android TRACE; ANDROID; GLES; OPENGL;
Linux LINUX; OPENGL;
MacOS MONOMAC; OPENGL;
Ouya TRACE; ANDROID; GLES; OPENGL; OUYA;
PSMobile DEBUG; PSM;
Windows DEBUG; TRACE; WINDOWS; DIRECTX; WINDOWS_MEDIA_SESSION;
Windows8 TRACE; NETFX_CORE; WINRT; WINDOWS_STOREAPP; DIRECTX; DIRECTX11_1; WINDOWS_MEDIA_ENGINE;
WindowsGL TRACE; WINDOWS; OPENGL;
WindowsPhone TRACE; DEBUG; SILVERLIGHT; WINDOWS_PHONE; WINRT; DIRECTX;
iOS IOS; GLES; OPENGL;

If you use my helper class PlatformHelper, you shouldn’t need to reference those via compiler directives, but they will need to be set in your game’s project options.

Using the helper, you can write code like the following.

   if(PlatformHelper.CurrentPlatform == Platforms.WindowsPhone) 
   {
      TargetElapsedTime = TimeSpan.FromTicks(333333);
   }

   graphics.IsFullScreen = PlatformHelper.IsMobile;
   this.IsMouseVisible = PlatformHelper.IsDesktop;

Without the helper, the conditional logic gets messy. For example, the property, PlatformHelper.IsMobile, knows that Ouya is not a mobile device, even though the ANDROID compiler directive is set.

There’s nothing special about the code that performs the various checks for you. You need not use my classes if you don’t want to. They’re just provided as a convenience.

{pagebreak}

Summary

Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah.

Exercises

Blah. Blah. Blah.


Chapter 3: Crash Course

Overview

This chapter presents the bare minimum that you need to know to understand the chapters that follow. If you would like to dive deeper into the concepts of programming, there are many good references out there. And, as always, google is a newbie’s best friend.

This book s based on my work with the kids at camp. And, at camp, we only have five days of class time to conceive and build a working game. Most of the students have no prior experience with programming.

Day one involves installing the tools that we’ll use, discussing the game we’d like to make, and making sure that our development environments are properly configured by writing a simple “game”.

We covered installing tools in the previous chapter, and you’ll be selecting your preferred game genre after this chapter. This is where we’ll make sure that our development environment is properly configured by building a simple game.

During that process, we will cover concepts such as variables, loops, objects, methods, and properties, along with many other techy buzzwords.

How a Program Works

All programs work basically the same way. They take input, process it, and generate output. Programs are written for specific tasks, though. So the way that input is collected, data is processed, and output is rendered varies greatly.

One of the simplest programs is the console app. You type a command, optionally pass in parameters, and (eventually) get output. For example, you might want to see a list of files in the current directory.

   josephs-mbp:~ groundh0g$ ls -lFa
   drwxr-xr-x+ 38 groundh0g  staff   1292 Sep 26 05:20 ./
   drwxr-xr-x   6 root       admin    204 Oct 28  2013 ../
   drwxr-xr-x   3 groundh0g  staff    102 Feb  5  2014 Applications/
   drwx------+ 32 groundh0g  staff   1088 Sep 26 07:06 Desktop/
   drwx------+ 21 groundh0g  staff    714 Aug 10 17:59 Documents/
   drwx------+ 67 groundh0g  staff   2278 Sep 23 19:12 Downloads/
   drwx------@ 64 groundh0g  staff   2176 Jun 12 11:14 Library/
   drwx------+  5 groundh0g  staff    170 Jul  4  2013 Movies/
   drwx------+  7 groundh0g  staff    238 Aug 31 12:55 Music/
   drwx------+  6 groundh0g  staff    204 May 16 02:05 Pictures/
   drwxr-xr-x  24 groundh0g  staff    816 Sep 16 19:06 Projects/
   drwxr-xr-x+  5 groundh0g  staff    170 Jul 23 15:06 Public/
   josephs-mbp:~ groundh0g$ 

A console application takes it’s input from the command line or from a file, processes the command and associated options, and generates output which is printed to the console. Requested actions are processed immediately.

A desktop application spends most of its time idle, waiting for you to click a button or menu item, type some text, or drag your mouse across a canvas.

A text editor, patiently waiting for a slow typer to take notes.

Desktop apps are event-driven. They wait for a user-generated event (e.g. clicking or typing) or system-generated event (e.g. a shutdown notification), and then respond to that event.

A service like a web server, waits for a command to arrive at a specific port (generally port 80), processes that command, and generates output (typically HTML or some static resource like an image).

For example, the web browser (a desktop application) might send the following request to a web server (a service).

   GET http://fpack.moreoncode.com/ HTTP/1.1

The server responds with HTML and images, which the browser uses to render the requested page. (Technically, each static resource, like an image, is retrieved with separate GET requests.)

Our requested webpage, beautifully rendered in the web browser. #shamelessplug

I could list countless examples, and each would follow the same basic model of receiving input, processing the input, and generating output. But, you’re reading this book because you’re interested in game programming. So, let’s take a look at how a game handles input, processing, and output.

Anatomy of a Program

Before we jump into MonoGame code, we need to cover the basic parts of a program.

   using System;
   
   namespace Chapter03.CrashCourse
   {
      public class SampleClass
      {
         public SampleClass () { }
   
         public static void Main (string[] args)
         {
            Console.WriteLine ("Hello, World!");
         }
      }
   }

In this case, we have a console program that ignores command line parameters (the input), doing absolutely nothing with them (the processing), and then prints a generic welcome message (the output).

A class is a representation of a (usually) real-world object. A namespace is analogous to a folder in a file system. So our class’ fully-qualified name is “Chapter03.CrashCourse.SampleClass”.

Classes may contain methods and properties. In our example, there are two methods - SampleClass and Main. The SampleClass method is a special method type known as a constructor. It’s called once, when an instance of the class is created in memory. That’s where the initialization logic lives. In our case, the constructor does absolutely nothing - much like its author.

Don’t worry about the details at this point. Just try to understand what the SampleClass is doing at a high level. As we work through this chapter, you’ll have plenty of opportunity to sweat the details.

How a Game Works

To recap:

  • Console applications are inactive until they’re invoked. They spring to life, process the request, and are unloaded from memory when their tasks are complete.
  • Desktop applications are launched (generally by a user), and then sit idly by, waiting for user or system events. Once an event is received, the application performs its tasks, and then returns to an idle state. The application runs until the system or (more likely) the user asks it to terminate.
  • Services are launched (generally by the system), and then sit idly by, waiting for a request to come in. Once a request is received, the service performs its tasks, and then returns to an idle state. The service runs until the user or (more likely) the system asks it to terminate.

Games are slightly different beasts. The user invokes them, and then they run continuously until they’re asked to terminate. Games have a heartbeat. It’s called the game loop. At regular intervals, two methods of a game are invoked - Update and Draw.

The interval varies based on the game, but it’s typically 1/60 of a second. 1/30 of a second is usually considered minimal for games, but your Draw calls can be made as infrequently as 1/12 of a second to provide smooth animations.

NOTE: For reference, most TV shows refresh at around 29.97 frames per second (assuming NTSC), most theatrical and animated films refresh at around 24 frames per second, and standard quality web animations refresh at around 12 frames per second. Of course, there’s a long list of specific frame rates for specific applications, but those are a common rule of thumb.

Another major difference between games and other applications is that the “take input” step is continuous. The game is constantly polling input devices, asking them if there’s been any change since the last query.

The “process input” step is handled in the Update method. Your virtual world is constantly updated based on a variety of factors, including player input. And the “generate output” step is handled by the Draw method, which renders the game visuals based on the current state of in-game objects that have been refreshed in the Update method.

NOTE: If you ever wondered why your laptop or smartphone battery drains faster when you’re playing video games, now you know. The game world is refreshed and redrawn 60 times per second. That means that your code is churning through (nearly) all your game world objects in 1/60 of a second, throwing the results to the display, and as soon as that frame has been rendered the entire process starts again.

Anatomy of a Game

Before we get started on our game for this chapter, lets cover the basic parts of the MonoGame game class.

   using System;
   using System.Collections.Generic;
   using Microsoft.Xna.Framework;
   using Microsoft.Xna.Framework.Audio;
   using Microsoft.Xna.Framework.Content;
   using Microsoft.Xna.Framework.GamerServices;
   using Microsoft.Xna.Framework.Graphics;
   using Microsoft.Xna.Framework.Input;
   using Microsoft.Xna.Framework.Media;

   namespace Chapter03.CrashCourse
   {
      public class Game1 : Microsoft.Xna.Framework.Game
      {
         GraphicsDeviceManager graphics;
         SpriteBatch spriteBatch;
   
         public Game1()
         {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
         }
   
         protected override void Initialize()
         {
            // TODO: Add your initialization logic here
            base.Initialize();
         }
   
         protected override void LoadContent()
         {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            // TODO: use this.Content to load your game content here
         }
   
         protected override void UnloadContent() { }
   
         protected override void Update(GameTime gameTime)
         {
            var buttonState = GamePad.GetState(PlayerIndex.One).Buttons.Back;
            if (buttonState == ButtonState.Pressed)
            {
               this.Exit();
            }
            // TODO: Add your update logic here
            base.Update(gameTime);
         }
   
         protected override void Draw(GameTime gameTime)
         {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            // TODO: Add your drawing code here
            base.Draw(gameTime);
         }
      }
   }

This is a fully functioning game. It renders a blue screen, at 60+ frames per second, and constantly asks the GamePad if the Back button is being pressed. When the Back button is pressed, the game exits. It’s no blockbuster, but it has all the plumbing that we need to start building our own games.

The first thing you’ll notice is that there are a lot more of those using statements. Those are references to the libraries (like MonoGame [a.k.a. Microsoft.XNA]) that we will be using in our game. By including the namespace path in a using statement, you save typing when you reference their classes.

The fully qualified name of this class is “Chapter03.CrashCourse.Game1”. It inherits all the methods and properties of its parent class, Microsoft.Xna.Framework.Game. That class does most of the heavy lifting for us, so that we can save hundreds of lines of code that perform the same tasks from game to game.

There are two member variables - graphics and spriteBatch. The former is used to query or alter the screen state. The latter is used to draw sprites (2D images). We don’t have any sprites in our game yet, but we soon will.

There are six methods:

  • Game1() - This is the constructor. It’s called once, when the game object is created. Constructors are generally meant to be lightweight and perform as few tasks as possible. So, the Game class provides an Initialize method where we can perform initialization tasks that might be a little meatier.
  • Initialize() - This is the place to set default values, and prepare any associated game data for use.
  • LoadContent() - This is where assets such as images, sounds, music, and others may be loaded. Typically, you will use the inherited Content member variable to load your assets. If that’s the case, you need not worry about “unloading” them.
    In general, you can assume that this method is called once. There are some exceptions, though. When the screen is destroyed and recreated, LoadContent will be called again. For example, when you drag your game from one monitor to another, the device context may be reset.
  • UnloadContent() - You’ll rarely use this method. It exists to handle housekeeping tasks associated with resources that you load outside of the normal mechanisms.
  • Update() - This is where your game word is updated.
  • Draw() - This is where you throw a view of your game world to the screen.

NOTE: All methods, except for the constructor, have the keyword override as a part of their method declarations. That means that there is a method already implemented in the parent class (Microsoft.XNA.Framework.Game), so this code replaces the parent’s implementation. If you want to use the parent’s implementation in addition to your own, you’d use the base.{MethodName}() syntax to call the existing code from within your own.

If there is only one thing you will take away from this chapter, it’s “Update, Draw, Update Draw, Update, Draw, Update, Draw, …” That’s the game loop. It’s the heartbeat of every game you’ll ever design, build, or play.

Take a few minutes to read the code above. It’s the simplest game there is for MonoGame - a blue screen. Over the course of the following chapters, we’ll build some pretty neat stuff based on this simple foundation.

Our Game

OK. That’s enough ivory tower crap. Let’s make a game. We’ll start simple, building a space shooter. The player will navigate an asteroid field while enemies are attacking him for no reason.

NOTE: OK. Maybe there’s a reason. For example, it could be two warring clans whose disputes age back several centuries. But who really cares about the backstory? I don’t know about you, but I just want to blow stuff up with lasers!

The player pilots a spaceship, steering left and right, moving ever forward. They’re not alone, though. Enemy forces occupy this region of space. And if that weren’t bad enough, there are asteroids to dodge as well.

The goal is to destroy enemy ships and asteroids in an effort to survive as long as possible. There’s no princess to rescue. There’s no bounty on the heads of your foes. Heck, you even have to pay for the maintenance and ammunition for your own ship - by collecting power ups. Life is tough. It’s best you learn that now.

Our hero battling enemies and dodging asteroids.

So. Where do we start? From the same place as we always start - a blank, cornflower blue canvas onto which we can create, manipulate, and even destroy entire worlds!

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 4: Spit and Polish

Overview

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sit amet fringilla augue. Integer justo lectus, fringilla sed tempus quis, accumsan ut mi. Duis ipsum quam, sodales ac fringilla at, gravida finibus ante. Fusce facilisis tellus et ultricies volutpat. Mauris eget tincidunt nulla. Vestibulum sodales nibh ipsum, nec euismod erat maximus id.

Our Game Enhancements

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sit amet fringilla augue. Integer justo lectus, fringilla sed tempus quis, accumsan ut mi. Duis ipsum quam, sodales ac fringilla at, gravida finibus ante. Fusce facilisis tellus et ultricies volutpat. Mauris eget tincidunt nulla. Vestibulum sodales nibh ipsum, nec euismod erat maximus id. Praesent posuere ultrices ultricies. Fusce bibendum vulputate mauris eu ultricies. Donec id laoreet ante, vel imperdiet dolor. Morbi suscipit lectus sit amet euismod imperdiet.

Nullam vulputate ipsum id maximus vulputate. Nullam tempor accumsan odio, ac accumsan tellus ultricies at. Nunc ex justo, egestas nec condimentum id, lobortis condimentum urna. Suspendisse potenti. Donec scelerisque leo quis felis facilisis bibendum. Etiam augue quam, varius nec enim dictum, imperdiet semper ex. Donec feugiat consectetur nulla, quis eleifend mauris vehicula ac. Duis pretium ac lacus vel gravida. Donec facilisis vestibulum venenatis. Donec odio arcu, rhoncus at semper vel, iaculis eu sapien.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 5: Camp 2011, Side Scroller

Overview

Landry Academy’s Computer Camp 2011 had seven students, ages 13 to 17, most of whom had never touched a compiler before this class. It was a great bunch of kids!

The 2011 Campers

They had a contagious passion that made the insane deadline (4 days from concept to demo) achievable. During almost every block of time that the camp had scheduled free-time for the kids, you’d find them in the classroom, hard at work on the project.

On the first day, we spent several hours installing the tools that we needed to create games. We had a brainstorming session that evening to plan what type of game we would build. The class was fairly evenly split between a scrolling shooter (like Defender or 1942) or an Angry Birds clone. We ultimately decided on an original game that combined the two concepts.

Four birds (controlled by four players) fly along, shooting pigs with seeds and dropping eggs on them. There are three types of pigs: normal pigs (on the ground and in trees), pig-a-troopers (who parachute in), and the king pig (who tosses baby pigs at you).

The game’s art is a mix of characters from the Angry Birds game, random images we found via Google searches, and some hills that were drawn the night before we gave our class presentation to the students from the other academic areas.

The 2011 Camp's Game

The students created all the in-game sound effects. I think the effects came out great, and I think they really add a lot to the final game. The music was downloaded from the website of a talented composer who recreated the Angry Birds theme in Garage Band.

The 2011 Camp game can be downloaded from the following URL:
http://camps.moreoncode.com/Camp2011/

Our Game

Our game will be a single-player side scroller featuring one of the lesser-known, ruggedly-handsome heroes, Super Joe! Super Joe will be battling robot enemies that look nothing like Iron Man™. Oh, and Super Joe in no way resembles any of the Powerpuff Girls™. Clearly. He has a cape, and he’s a dude.

While Chapter 4 introduced the concept of a scrolling background to give the illusion of movement through space. Our game will add layers of scrolling images to achieve an effect known as parallax scrolling. This will give the game depth. Images that are further from the player will appear to move slower than images that are closer to the player.

Our Game Concept

We won’t start most of our games with such a polished concept drawing. Expect whiteboard notes from now on. This is a screenshot from a test app I created and deployed to my Android tablet ages ago.

Since the proof-of-concept, I’ve decided that the hero will shoot lasers at his enemies, and that his enemies will fire rockets at him. That will allow us to add effects like smoke trails and explosions.

Super Joe will score some number of points for each enemy that he defeats, and a smaller number of points for each rocket he’s able to destroy before it reaches him. Contrary to popular belief, Super Joe is not invulnerable. When a rocket strikes him, he will take damage. When he takes enough damage, the game will be over.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 6: Camp 2012, Survival

Overview

Landry Academy’s Computer Camp 2012 had five students, ages 15 and 16, many of whom had never touched a compiler before this class.

The 2012 Campers

On the first day, we spent several hours installing the tools that we needed to create games. We had a brainstorming session while we waited for the installers to do their magic, planning what type of game we would build. I was campaigning for a Rock Band / Guitar Hero style game, but the class decided to design a platformer game (ala Super Mario Bros.).

A cartoony hero walks around a factory / lab complex jumping on the heads of killer robots to destroy them. There are two flavors of robot: the Hoverbot who quickly floats towards the player, and the Tankbot who moves a little slower, but fires missiles at the player at regular intervals. When a robot is destroyed, it drops a gear (likely) or a heart (less frequently). The player’s score is the number of gears collected.

The game’s art is a collection of doodles that I did in Adobe Illustrator, feverishly churning out assets each evening in an attempt to stay a step ahead of the class. The main character is the result of a tutorial that I followed over at idleworm.com.

The 2012 Camp's Game

The plan to make a platformer turned out to be too much work for a week-long project. We cut features, and ultimately decided to turn the project into a survival game.

The 2012 Camp game can be downloaded from the following URL:
http://camps.moreoncode.com/Camp2012/

Our Game

I’ll give you a break from my attempts at being a game artist. We’ll use Kenney’s assets to create a similar game. This new game will support one to four players. They will start off in the center of the screen as baddies approach from each side.

The waves of baddies increase in frequency and size as the game goes on. Players fight off the hordes until each meets their inevitable doom. The last player standing wins the game.

I said “one to four players”, didn’t I? I guess you could play this one solo, but you’ll always be the winner. I suppose you can play to see how long you last on your own, but at its core, this is meant to be a multiplayer game.

Oh, I almost forgot another important addition to this game. The players can move left and right, as you might expect, but also towards and away from the screen. Didn’t see that one coming, did ya?

Our oblivious heroes.

You’re probably thinking that we will just use the Y component of each player’s location to dictate their distance from the screen. And you’re quite right. But players can also jump in this game, so we’ll need to introduce a Z component to the players’ locations.

To keep it all from becoming too confusing for the player, each avatar will have a shadow below it so that you can easily tell their position in the game world, even when they’re jumping. The Z value will be combined with the Y value for the avatar when we draw them, but their shadow will ignore the Z component. The shadow simply shows the player’s relative X and Y to the other players and the enemies.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 7: Camp 2013, Runner

Overview

Landry Academy’s Computer Camp 2013 had five students, none of whom had used a compiler before this class.

The 2013 Campers

On the first day, I typically have a brainstorming session with the students while the tools are installing. With past classes, we compile a list of game genres that we might like to explore, come to a consensus on which to implement, then dive deeper into the details of the selected game.

This year, the students gravitated immediately to a concept based loosely on Temple Run. Rather than considering other genres, they kept tossing out ideas for the platformer-style game. It was obvious what our project would be early into the process. I keep campaigning for a Rock Band clone, but it never seems to take hold of anyone’s interest.

This year, in addition to art I created and images we scavenged from the web, we took video of one of the camp counselors in several poses, including a slow motion roll. The students cut the images from the still frames of the video, and the counselor (hi, Tim!) was our game’s main character.

The 2013 Camp's Game

The game supports two players, each of which has to run an identical gauntlet of obstacles. The player that makes it the furthest distance before losing three health points is the winner.

The original design included power-ups and more elaborate obstacles. In the end, we realized that the full game would to be too much work for a week-long project. We cut features, but the end result was still a very nice game.

The 2013 Camp game can be downloaded from the following URL:
http://camps.moreoncode.com/Camp2013/

Our Game

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sit amet fringilla augue. Integer justo lectus, fringilla sed tempus quis, accumsan ut mi. Duis ipsum quam, sodales ac fringilla at, gravida finibus ante. Fusce facilisis tellus et ultricies volutpat. Mauris eget tincidunt nulla. Vestibulum sodales nibh ipsum, nec euismod erat maximus id. Praesent posuere ultrices ultricies. Fusce bibendum vulputate mauris eu ultricies. Donec id laoreet ante, vel imperdiet dolor. Morbi suscipit lectus sit amet euismod imperdiet.

Nullam vulputate ipsum id maximus vulputate. Nullam tempor accumsan odio, ac accumsan tellus ultricies at. Nunc ex justo, egestas nec condimentum id, lobortis condimentum urna. Suspendisse potenti. Donec scelerisque leo quis felis facilisis bibendum. Etiam augue quam, varius nec enim dictum, imperdiet semper ex. Donec feugiat consectetur nulla, quis eleifend mauris vehicula ac. Duis pretium ac lacus vel gravida. Donec facilisis vestibulum venenatis. Donec odio arcu, rhoncus at semper vel, iaculis eu sapien.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 8: Camp 2014, Castle Crawler

Overview

Landry Academy’s Computer Camp 2014 had ten students - from CA, FL, GA, IL, LA, MD, PA, TX, and Mexico. Most had never touched a compiler before this class.

The 2014 Campers

On the first day, we spent several hours installing the tools that we needed to create games. We had a brainstorming session during that time to plan what type of game we would build. The class zeroed in on a side-scrolling smash’em up, similar to Castle Crashers. The design supports one to four players.

The players are aliens who are spooked and run into a haunted house. The group works their way through the house, battling all sorts of baddies.

The game’s art is a mix of characters and monsters from Kenney’s assets.

The 2014 Camp's Game

Unfortunately, as is the case with such tight deadlines, so many features were trimmed from the game that it became less a castle crawler and more of a survival game. The players remain in the starting room as baddies keep coming to them. We also didn’t have time to implement a boss screen, as originally planned.

There is no player select screen. The controller you’re using dictates which character you play. And however many controllers are plugged in (one to four, as limited by XNA) dictates how many avatars appear in the game.

To balance the game for a varying number of players, a single player gets four hits before death, two players get three hits, three players get two hits, and if there are four players, each may only receive one hit before they are removed from the game.

The 2014 Camp game can be downloaded from the following URL:
http://camps.moreoncode.com/Camp2014/

Our Game

Now that we have more time, we’ll build the game that the students wanted to build in the first place. The fact that we were able to trim some features and easily build a different game type should show you how similar a castle crawler and a survival game can be. In fact, a survival game is actually one component of a castle crawler.

The parts of a castle crawler.

The gameplay is fairly formulaic. Players move through the castle, killing baddies and collecting rewards. Every now and then, they’re stopped in their tracks by a horde of enemies that attack from both sides. Once the invaders are defeated, the players continue their journey through the castle.

At the level’s climax, the players encounter a new, more powerful enemy. This is the boss screen. There may be some minions that come to the aid of their leader, but the primary goal of this part of the game is to defeat the boss.

As you can see in the concept sketch, step two (“Battle Hordes”) is a survival game, but with an achievable end. The baddies don’t keep attacking forever. Even though it may feel that way in the heat of battle.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 9: Class 2013, Platformer

Overview

Landry Academy’s Computer Camp 2011 had seven students, ages 13 to 17, most of whom had never touched a compiler before this class. It was a great bunch of kids!

The 2013 Class

They had a contagious passion that made the insane deadline (4 days from concept to demo) achievable. During almost every block of time that the camp had scheduled free-time for the kids, you’d find them in the classroom, hard at work on the project.

On the first day, we spent several hours installing the tools that we needed to create games. We had a brainstorming session that evening to plan what type of game we would build. The class was fairly evenly split between a scrolling shooter (like Defender or 1942) or an Angry Birds clone. We ultimately decided on an original game that combined the two concepts.

Four birds (controlled by four players) fly along, shooting pigs with seeds and dropping eggs on them. There are three types of pigs: normal pigs (on the ground and in trees), pig-a-troopers (who parachute in), and the king pig (who tosses baby pigs at you).

The game’s art is a mix of characters from the Angry Birds game, random images we found via Google searches, and some hills that were drawn the night before we gave our class presentation to the students from the other academic areas.

The 2013 Class' Game

All the in-game sound effects were created by the students. I think the effects came out great, and I think they really add a lot to the final game. The music was downloaded from the website of a talented composer who recreated the Angry Birds theme in Garage Band.

The 2014 Camp game can be downloaded from the following URL:
http://camps.moreoncode.com/Camp2014/

Our Game

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sit amet fringilla augue. Integer justo lectus, fringilla sed tempus quis, accumsan ut mi. Duis ipsum quam, sodales ac fringilla at, gravida finibus ante. Fusce facilisis tellus et ultricies volutpat. Mauris eget tincidunt nulla. Vestibulum sodales nibh ipsum, nec euismod erat maximus id. Praesent posuere ultrices ultricies. Fusce bibendum vulputate mauris eu ultricies. Donec id laoreet ante, vel imperdiet dolor. Morbi suscipit lectus sit amet euismod imperdiet.

Nullam vulputate ipsum id maximus vulputate. Nullam tempor accumsan odio, ac accumsan tellus ultricies at. Nunc ex justo, egestas nec condimentum id, lobortis condimentum urna. Suspendisse potenti. Donec scelerisque leo quis felis facilisis bibendum. Etiam augue quam, varius nec enim dictum, imperdiet semper ex. Donec feugiat consectetur nulla, quis eleifend mauris vehicula ac. Duis pretium ac lacus vel gravida. Donec facilisis vestibulum venenatis. Donec odio arcu, rhoncus at semper vel, iaculis eu sapien.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 10: Class 2014, Tower Defense

Overview

Landry Academy’s Computer Camp 2011 had seven students, ages 13 to 17, most of whom had never touched a compiler before this class. It was a great bunch of kids!

The 2014 Class

They had a contagious passion that made the insane deadline (4 days from concept to demo) achievable. During almost every block of time that the camp had scheduled free-time for the kids, you’d find them in the classroom, hard at work on the project.

On the first day, we spent several hours installing the tools that we needed to create games. We had a brainstorming session that evening to plan what type of game we would build. The class was fairly evenly split between a scrolling shooter (like Defender or 1942) or an Angry Birds clone. We ultimately decided on an original game that combined the two concepts.

Four birds (controlled by four players) fly along, shooting pigs with seeds and dropping eggs on them. There are three types of pigs: normal pigs (on the ground and in trees), pig-a-troopers (who parachute in), and the king pig (who tosses baby pigs at you).

The game’s art is a mix of characters from the Angry Birds game, random images we found via Google searches, and some hills that were drawn the night before we gave our class presentation to the students from the other academic areas.

The 2014 Class' Game

All the in-game sound effects were created by the students. I think the effects came out great, and I think they really add a lot to the final game. The music was downloaded from the website of a talented composer who recreated the Angry Birds theme in Garage Band.

The 2011 Camp game can be downloaded from the following URL:
http://camps.moreoncode.com/Camp2011/

Our Game

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sit amet fringilla augue. Integer justo lectus, fringilla sed tempus quis, accumsan ut mi. Duis ipsum quam, sodales ac fringilla at, gravida finibus ante. Fusce facilisis tellus et ultricies volutpat. Mauris eget tincidunt nulla. Vestibulum sodales nibh ipsum, nec euismod erat maximus id. Praesent posuere ultrices ultricies. Fusce bibendum vulputate mauris eu ultricies. Donec id laoreet ante, vel imperdiet dolor. Morbi suscipit lectus sit amet euismod imperdiet.

Nullam vulputate ipsum id maximus vulputate. Nullam tempor accumsan odio, ac accumsan tellus ultricies at. Nunc ex justo, egestas nec condimentum id, lobortis condimentum urna. Suspendisse potenti. Donec scelerisque leo quis felis facilisis bibendum. Etiam augue quam, varius nec enim dictum, imperdiet semper ex. Donec feugiat consectetur nulla, quis eleifend mauris vehicula ac. Duis pretium ac lacus vel gravida. Donec facilisis vestibulum venenatis. Donec odio arcu, rhoncus at semper vel, iaculis eu sapien.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 11: Class 2015, Real-Time Strategy

Overview

Landry Academy’s Computer Camp 2011 had seven students, ages 13 to 17, most of whom had never touched a compiler before this class. It was a great bunch of kids!

The 2015 Class

They had a contagious passion that made the insane deadline (4 days from concept to demo) achievable. During almost every block of time that the camp had scheduled free-time for the kids, you’d find them in the classroom, hard at work on the project.

On the first day, we spent several hours installing the tools that we needed to create games. We had a brainstorming session that evening to plan what type of game we would build. The class was fairly evenly split between a scrolling shooter (like Defender or 1942) or an Angry Birds clone. We ultimately decided on an original game that combined the two concepts.

Four birds (controlled by four players) fly along, shooting pigs with seeds and dropping eggs on them. There are three types of pigs: normal pigs (on the ground and in trees), pig-a-troopers (who parachute in), and the king pig (who tosses baby pigs at you).

The game’s art is a mix of characters from the Angry Birds game, random images we found via Google searches, and some hills that were drawn the night before we gave our class presentation to the students from the other academic areas.

The 2015 Class' Game

All the in-game sound effects were created by the students. I think the effects came out great, and I think they really add a lot to the final game. The music was downloaded from the website of a talented composer who recreated the Angry Birds theme in Garage Band.

The 2011 Camp game can be downloaded from the following URL:
http://camps.moreoncode.com/Camp2011/

Our Game

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sit amet fringilla augue. Integer justo lectus, fringilla sed tempus quis, accumsan ut mi. Duis ipsum quam, sodales ac fringilla at, gravida finibus ante. Fusce facilisis tellus et ultricies volutpat. Mauris eget tincidunt nulla. Vestibulum sodales nibh ipsum, nec euismod erat maximus id. Praesent posuere ultrices ultricies. Fusce bibendum vulputate mauris eu ultricies. Donec id laoreet ante, vel imperdiet dolor. Morbi suscipit lectus sit amet euismod imperdiet.

Nullam vulputate ipsum id maximus vulputate. Nullam tempor accumsan odio, ac accumsan tellus ultricies at. Nunc ex justo, egestas nec condimentum id, lobortis condimentum urna. Suspendisse potenti. Donec scelerisque leo quis felis facilisis bibendum. Etiam augue quam, varius nec enim dictum, imperdiet semper ex. Donec feugiat consectetur nulla, quis eleifend mauris vehicula ac. Duis pretium ac lacus vel gravida. Donec facilisis vestibulum venenatis. Donec odio arcu, rhoncus at semper vel, iaculis eu sapien.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 12: Author’s Choice, Puzzle

Overview

Most game genres have a fairly narrow demographic to which they appeal. Typically, that demographic is young males. Puzzle games are one of those rare categories of games that cross gender and age barriers. Their simple, yet addictive game play seduces the casual gamer and the hard-core gamer alike. They even appeal to many people who wouldn’t consider themselves ‘‘gamers’’ at all. With a focus on problem solving, and having their roots in logic and math, puzzle games prove that simple games can be fun, even without a multi-million-dollar development budget or a big-name intellectual property license.

By far, the most popular title in this genre is Tetris, created by Russian mathematician Alexey Pajitnov (Pazhitnov) in 1985. Tetris, and the many clones and variants that it has inspired, has found its way onto nearly every platform imaginable. Most recently, puzzle games have found new life on smartphones, introducing many people who may otherwise never have been exposed to their addictive game play. And a new generation of puzzle games like Bejeweled, Candy Crush Saga, Cut the Rope, and Flow are doing their part to entice new players with this genre’s broad appeal.

In this chapter, you will learn how to:

  • Simultaneously manage the state of multiple on-screen game objects
  • Add simple, yet effective animations and visual effects to your game

Our Game

If you had asked me what my favorite puzzle game was less than a year ago, I would have quickly replied, “Tetris Attack!” It’s a simple, yet addictive little match-three game that pushes rows from the bottom. You clear pieces from the board by matching three or more tiles of the same color. The game’s pace quickens as you play. If the pieces reach the top of the game board, the game is over. I loved this game so much that it was the featured example game for the puzzle genre in my 2007 book.

For the last several months, I’ve had a new favorite - Puzzle and Dragons. It’s yet another match-three game with unique game mechanics (moving pieces has a huge influence on the game board) and an RPG element that makes this title more addicting than crack.

In this chapter we will develop a simplified clone of this game called Puzzle and Zombies. We’ll capture the game play mechanics, but won’t add in the RPG element.

Our game concept. Puzzle and Zombies!

The Architecture

Blah. Blah. Blah.

The GameBoard

Blah. Blah. Blah.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 13: Author’s Choice, Artificial Intelligence

Overview

Board games are another of those categories of games that have mass appeal, and many of the most popular board games have been around so long that copyright issues are no longer a concern, so they can be a great source of inspiration for your original titles.

In this chapter, you will learn how to:

  • Implement simple computer opponents to enhance single-player game play
  • Simultaneously manage the state of multiple on-screen game objects
  • Add simple, yet effective animations and visual effects to your game
  • Use threading to keep animations going while processing background tasks
  • Track and display a player’s score using a bitmap font

Our Game

In this chapter, we will develop a simple version of a popular board game that originated in England around 1880. Reversi gained wide-spread popularity in England towards the end of the 19th century, and it experienced a resurgence in popularity in the 1970s, when it was refined into its modern incarnation and banded with a new moniker - Othello.

In our version of the game, the action takes place on a 8-by-8 grid. Each player starts with two pieces, placed in the center of the grid. One point is awarded for each piece a player has on the grid. Players must place their piece on the board according to the following rules:

  • The grid cell into which the piece is placed must be empty.
  • The grid cell into which the piece is placed must be adjacent to one of the opponent’s pieces.
  • The player’s new piece, along with an existing piece, must “surround” at least one piece of the opponent, in a straight line (horizontally, vertically, or diagonally).

Players take turns placing pieces on the board in an attempt to capture their opponent’s pieces and maximize the number of grid cells that are occupied by their own pieces. When there is no legal move for a player, he forfeits his turn and play passes to his opponent. If neither player can make a legal move (as is the case when the grid is full), the game is over. The player with the most pieces on the board wins.

Our game concept. It's the CPU's turn. Valid moves are highlighted.

The Architecture

The basic design for this game is fairly simple. The game grid starts out empty and is gradually filled, one piece at a time. As pieces are added to the grid, we need to make sure that the additions satisfy the game rules. The basic components to handle these tasks are detailed in the following text.

The GameBoard

The GameBoard class contains a two-dimensional array of GamePiece objects. The dimensions of this array are determined by the GridWidth and GridHeight member variables. The GameBoard class is also responsible for making sure that any moves that are made by a player (human or CPU) conform to the rules of the game. This is done by determining the complete list of valid moves (stored in the ValidMoves array) whenever a game turn begins. Only moves in this list are allowed.

Determining Valid Moves

The UpdateListOfValidMoves method creates a list of all the grid cell locations where the current player may legally place his new game piece. New pieces may only be placed on the game board if they meet the three requirements of the game rules: the cell is empty, the cell is adjacent to an opponent’s piece, and the new piece (along with an existing piece) will surround at least one of the opponent’s pieces.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 14: Odds and Ends, GamePadEx

Overview

The mouse, keyboard, touchscreens, and game pads are very different devices, each requiring specialized code. There are times when it would be nice to play a game without hooking up a controller. But you don’t want to write code to support multiple devices every time you start a game project. Besides, some of the folks who want to play your game may not have a controller hooked up to their PC.

Also, there are many times (especially if you’re doing your development on a laptop) when it may not be convenient to carry a controller around. Wouldn’t it be nice to emulate a controller using your keyboard? You could just map some keyboard keys to the game pad buttons and play test your game without ever taking your hands off the keyboard.

NOTE: If you’d prefer to attract attention, plug your controller into your laptop at the local WiFi-enabled café. Before I implemented a similar helper class for keyboard support in my games, I had to use the controller. Most people assume you’re just playing games, but I did meet several aspiring game developers during that time. (Hi, JT!)

In this chapter, we’ll develop a reusable, keyboard-aware replacement for the standard GamePad classes. In addition to mapping keyboard keys to controller buttons, our new component will also relay the states of any actual controllers that are connected. We do this so that the new class can be used as a drop-in replacement for GamePad. The game developer won’t need to tweak their code to use our new component.

In this chapter, you will learn how to:

  • Intercept input states and modify them before the game has a chance to see them
  • Provide abstractions that allow you to utilize multiple devices with minimal impact to your game code

Caveats and Pitfalls

Of course, a keyboard isn’t a controller. So there are some caveats to note when using this new component.

No Analog Button Support

A physical controller supports several analog buttons. Since keyboard keys are digital (pressed or not pressed), we’ll need to map the analog buttons to their extremes when updating their state. In essence, the keyboard-emulated thumbsticks and triggers will behave like the directional pad on the real controller.

One of the following constants is reported to the calling code whenever a (always digital) key press is mapped to an analog game pad button:

   // extreme values for the analog GamePad buttons 
   public const float TRIGGER_MAX = 1.00f;
   public const float TRIGGER_MIN = 0.00f;
   public const float THUMBSTICK_MAX = 1.00f;
   public const float THUMBSTICK_MIN = -1.00f;

One Player; Maybe Two

The players who are using the keyboard are playing in a physically-constrained space - it’s not the best device to have four players use at the same time. To keep our design simple, we’ll restrict our new component to support just one player.

NOTE: The original design for this component, in my 2007 XNA book, provided support for up to two simultaneous players. That was when I knew my target audience was using a full-sized keyboard. I’m not. My MacBook Pro doesn’t have a number pad. If you’d like to add another emulated controller, contact me. If there’s enough interest, I’ll post a version of the code that supports two keyboard-bound players.

Since the keyboard is so cramped, we’ll only provide support for one of the analog thumbsticks - the left one - when two players are using the keyboard at the same time. And, as I mentioned earlier, the analog thumbsticks are treated as digital buttons, the left thumbstick will behave as a directional pad would.

Getting Started

This component was designed to mimic the functionality of the standard GamePad class of the MonoGame Framework, and it was written so that you can easily swap between the standard game pad APIs and the keyboard-aware game pad APIs by simply changing your declarations. In the vast majority of cases, you will not need to change your game’s input processing logic.

This helper class provides a keyboard-aware replacement for the standard GamePad APIs. If you’ve written a game that only accepts input from the game pad, you can tweak your member declarations to reference instances of the class that we will develop in this chapter, and your game will support the keyboard as an alternate controller “for free”.

Laying the Foundation

Our first step is to recreate the existing GamePad functionality.

using System;

namespace Microsoft.Xna.Framework.Input
{
   public static class GamePadEx
   {
      // extreme values for the analog GamePad buttons 
      public const float TRIGGER_MAX = 1.00f;
      public const float TRIGGER_MIN = 0.00f;
      public const float THUMBSTICK_MAX = 1.00f;
      public const float THUMBSTICK_MIN = -1.00f;

      // set the emulated controller index
      public static PlayerIndex? KeyboardPlayerIndex { get; set; }

      // is the specified playerIndex the one associated with the keyboard?
      private static bool IsKeyboardPlayerIndex(PlayerIndex playerIndex) 
      {
         return 
            KeyboardPlayerIndex.HasValue &&
            KeyboardPlayerIndex.Value == playerIndex;
      }

      public static GamePadCapabilities GetCapabilities(PlayerIndex playerIndex)
      {
         return GamePad.GetCapabilities(playerIndex);
      }

      public static GamePadState GetState(PlayerIndex playerIndex)
      {
         return GamePadEx.GetState (
            playerIndex, 
            GamePadDeadZone.IndependentAxes);
      }

      public static GamePadState GetState(
         PlayerIndex playerIndex, 
         GamePadDeadZone deadZoneMode)
      {
         return GamePad.GetState (playerIndex, deadZoneMode);
      }

      public static bool SetVibration(
         PlayerIndex playerIndex, 
         float leftMotor, 
         float rightMotor)
      {
         return GamePad.SetVibration (playerIndex, leftMotor, rightMotor);
      }
   }
}

It’s silly, but we now have a GamePadEx class that mimics the MonoGame GamePad class exactly. If we wanted to use our new class in place of the built-in class, we need only append an “Ex” to the type declaration. Everything would work exactly as it does today. The controllers would function as expected, and the keyboard would be ignored.

So, what do we need to tweak, and what can remain as-is?

Well, I’ve never owned a keyboard that had rumble motors. So we’ll leave SetVibration alone. That leaves GetCapabilities and two overloaded versions of GetState. One of those two overloaded methods simply calls the other, so it looks like we can add our extensions to just two methods.

GamePadEx.GetCapabilities

Let’s start with the seemingly easier of the two - GetCapabilities. If you open the MonoGame source file for “GamePadCapabilities.cs”, you’ll see that the GamePadCapabilities definition is a structure. That’s great. We should be able to just set some properties and be done with it.

But, wait. The public properties of the GamePadCapabilities are marked as public get, but internal set. That means that only the assembly that houses the structure can modify it (in this case, the MonoGame DLL). We cannot change any of the properties from our own code.

It looks like we’ll need to create another structure that mimics GamePadCapabilities. That’s not ideal, but should be easy enough to implement without requiring the caller (the game developer) to change their code that probes the capabilities of the device.

using System;

namespace Microsoft.Xna.Framework.Input
{
   public struct GamePadCapabilitiesEx
   {
      public bool IsConnected { get; set; }
      public bool HasAButton { get; set; }
      public bool HasBackButton { get; set; }
      public bool HasBButton { get; set; }
      public bool HasDPadDownButton { get; set; }
      public bool HasDPadLeftButton { get; set; }
      public bool HasDPadRightButton { get; set; }
      public bool HasDPadUpButton { get; set; }
      public bool HasLeftShoulderButton { get; set; }
      public bool HasLeftStickButton { get; set; }
      public bool HasRightShoulderButton { get; set; }
      public bool HasRightStickButton { get; set; }
      public bool HasStartButton { get; set; }
      public bool HasXButton { get; set; }
      public bool HasYButton { get; set; }
      public bool HasBigButton { get; set; }
      public bool HasLeftXThumbStick { get; set; }
      public bool HasLeftYThumbStick { get; set; }
      public bool HasRightXThumbStick { get; set; }
      public bool HasRightYThumbStick { get; set; }
      public bool HasLeftTrigger { get; set; }
      public bool HasRightTrigger { get; set; }
      public bool HasLeftVibrationMotor { get; set; }
      public bool HasRightVibrationMotor { get; set; }
      public bool HasVoiceSupport { get; set; }
      public GamePadType GamePadType { get; set; }
     
   // TODO: add a constructor to copy the values from 
   //       an existing GamePadCapatilities instance
   
   // TODO: add a constructor to populate the values for
   //       the keyboard; use it to create a static instance
   
   }
}

The only difference between the MonoGame implementation and ours is that the getters and setters are both now marked as public, so we’ll be able to tweak them for the keyboard, or copy an existing GamePadCapabilities structure’s values to our own.

Note the first “TODO:” in the comments. The following code implements a constructor that does just that.

   // TODO: add a constructor to copy the values from 
   //       an existing GamePadCapatilities instance
   public GamePadCapabilitiesEx(GamePadCapabilities copy) : this() {
      this.IsConnected = copy.IsConnected;
      this.HasAButton = copy.HasAButton;
      this.HasBackButton = copy.HasBackButton;
      this.HasBButton = copy.HasBButton;
      this.HasDPadDownButton = copy.HasDPadDownButton;
      this.HasDPadLeftButton = copy.HasDPadLeftButton;
      this.HasDPadRightButton = copy.HasDPadRightButton;
      this.HasDPadUpButton = copy.HasDPadUpButton;
      this.HasLeftShoulderButton = copy.HasLeftShoulderButton;
      this.HasLeftStickButton = copy.HasLeftStickButton;
      this.HasRightShoulderButton = copy.HasRightShoulderButton;
      this.HasRightStickButton = copy.HasRightStickButton;
      this.HasStartButton = copy.HasStartButton;
      this.HasXButton = copy.HasXButton;
      this.HasYButton = copy.HasYButton;
      this.HasBigButton = copy.HasBigButton;
      this.HasLeftXThumbStick = copy.HasLeftXThumbStick;
      this.HasLeftYThumbStick = copy.HasLeftYThumbStick;
      this.HasRightXThumbStick = copy.HasRightXThumbStick;
      this.HasRightYThumbStick = copy.HasRightYThumbStick;
      this.HasLeftTrigger = copy.HasLeftTrigger;
      this.HasRightTrigger = copy.HasRightTrigger;
      this.HasLeftVibrationMotor = copy.HasLeftVibrationMotor;
      this.HasRightVibrationMotor = copy.HasRightVibrationMotor;
      this.HasVoiceSupport = copy.HasVoiceSupport;
      this.GamePadType = copy.GamePadType;
   }

Note the second “TODO:” in the comments. The following code implements a constructor and member variable that does just that.

Also note that this constructor is marked as private. That means that we’ll be creating just one instance of the GamePadCapabilitiesEx class for the keyboard - KeyboardCapabilities. We’ll return it whenever the capabilities for the keyboard “controller” are requested.

   // TODO: add a constructor to populate the values for
   //       the keyboard; use it to create a static instance
   private static readonly GamePadCapabilitiesEx
      KeyboardCapabilities = new GamePadCapabilitiesEx(true);
   
   private GamePadCapabilitiesEx(bool isKeyboard) : this() {
      this.IsConnected = true;
      this.HasAButton = true;
      this.HasBackButton = true;
      this.HasBButton = true;
      this.HasDPadDownButton = true;
      this.HasDPadLeftButton = true;
      this.HasDPadRightButton = true;
      this.HasDPadUpButton = true;
      this.HasLeftShoulderButton = false;
      this.HasLeftStickButton = false;
      this.HasRightShoulderButton = false;
      this.HasRightStickButton = false;
      this.HasStartButton = true;
      this.HasXButton = true;
      this.HasYButton = true;
      this.HasBigButton = false;
      this.HasLeftXThumbStick = true;
      this.HasLeftYThumbStick = true;
      this.HasRightXThumbStick = true;
      this.HasRightYThumbStick = true;
      this.HasLeftTrigger = true;
      this.HasRightTrigger = true;
      this.HasLeftVibrationMotor = false;
      this.HasRightVibrationMotor = false;
      this.HasVoiceSupport = false;
      this.GamePadType = GamePadType.GamePad;
   }

We have this new class to represent a standard GamePadCapabilities instance, which happens to also be keyboard-aware. How do we use it?

We need to return the keyboard capabilities if the playerIndex matches the player index of the emulated controller, and return the specified controller’s capabilities otherwise. So, we need to tweak the GetCapabilities method of our GamePadEx class. It currently reads as follows.

   public static GamePadCapabilities GetCapabilities(PlayerIndex playerIndex)
   {
      return GamePad.GetCapabilities(playerIndex);
   }

It should now read as follows.

   public static GamePadCapabilitiesEx GetCapabilities(PlayerIndex playerIndex)
   {
      if(GamePadEx.IsKeyboardPlayerIndex(playerIndex))
      {
         return GamePadCapabilitiesEx.KeyboardCapabilities;
      } else {
         return
            new GamePadCapabilitiesEx(GamePad.GetCapabilities(playerIndex));
      }
   }

With that change in place, the GetCapabilities method is now keyboard-aware.

GamePadEx.GetState

This is where the real fun begins. We need to map keyboard keys to game pad buttons, sticks, and triggers.

NOTE: The original design for this component, in my 2007 XNA book, provided a way to configure which keys mapped to which buttons. This time around, though, I’m just going to map the keys via code.

If you’d like to see configurable key-to-button mappings, contact me. If there’s enough interest, I’ll post a version of the code that supports configurable button mappings.

Let’s start by updating the GetState methods to look like this, adding a new, private EmulateGamePadState method.

   public static GamePadState GetState(PlayerIndex playerIndex)
   {
      return GamePadEx.GetState(
            playerIndex, 
         GamePadDeadZone.IndependentAxes);
   }

   public static GamePadState GetState(
      PlayerIndex playerIndex, 
      GamePadDeadZone deadZoneMode)
   {
      if(GamePadEx.IsKeyboardPlayerIndex(playerIndex))
      {
         return GamePadEx.EmulateGamePadState();
      } else {
         return GamePad.GetState (playerIndex, deadZoneMode);
      }
   }

   // TODO: populate the GamePadState from KeyboardState data
   private static GamePadState EmulateGamePadState()
   {
      return GamePadState.Default;
   }

As written, our GamePadEx would pass through the controller data for connected controllers, but the keyboard controller will always behave as if no inputs are being touched. Let’s add the code to map keyboard keys to controller inputs.

   // TODO: populate the GamePadState from KeyboardState data
   private static GamePadState EmulateGamePadState()
   {
      var keyState = Keyboard.GetState ();

      var leftTrigger = keyState.IsKeyDown(Keys.LeftAlt) ?
         TRIGGER_MAX : TRIGGER_MIN;
      var rightTrigger = keyState.IsKeyDown(Keys.RightAlt) ?
         TRIGGER_MAX : TRIGGER_MIN;

      var dPadUp = keyState.IsKeyDown(Keys.W) ?
         ButtonState.Pressed : ButtonState.Released;
      var dPadDown = keyState.IsKeyDown(Keys.S) ?
         ButtonState.Pressed : ButtonState.Released;
      var dPadLeft = keyState.IsKeyDown(Keys.A) ?
         ButtonState.Pressed : ButtonState.Released;
      var dPadRight = keyState.IsKeyDown(Keys.D) ?
         ButtonState.Pressed : ButtonState.Released;

      // mimic DPad
      var leftThumbstick = Vector2.Zero;
      if (dPadUp == ButtonState.Pressed) {
         leftThumbstick.Y = THUMBSTICK_MAX;
         dPadDown = ButtonState.Released;
      } else if (dPadDown == ButtonState.Pressed) {
         leftThumbstick.Y = THUMBSTICK_MIN;
         dPadUp = ButtonState.Released;
      }
      if (dPadLeft == ButtonState.Pressed) {
         leftThumbstick.X = THUMBSTICK_MIN;
         dPadRight = ButtonState.Released;
      } else if (dPadRight == ButtonState.Pressed) {
         leftThumbstick.X = THUMBSTICK_MAX;
         dPadLeft = ButtonState.Released;
      }

      var rightThumbstick = Vector2.Zero;
      if (keyState.IsKeyDown(Keys.Down)) {
         rightThumbstick.Y = THUMBSTICK_MIN;
      } else if (keyState.IsKeyDown(Keys.Up)) {
         rightThumbstick.Y = THUMBSTICK_MAX;
      }
      if (keyState.IsKeyDown(Keys.Left)) {
         rightThumbstick.X = THUMBSTICK_MIN;
      } else if (keyState.IsKeyDown(Keys.Right)) {
         rightThumbstick.X = THUMBSTICK_MAX;
      }

      Buttons buttons = 0;
      if (keyState.IsKeyDown (Keys.Space)) 
         { buttons |= Buttons.A; }
      if (keyState.IsKeyDown (Keys.RightControl)) 
         { buttons |= Buttons.B; }
      if (keyState.IsKeyDown (Keys.PageDown)) 
         { buttons |= Buttons.X; }
      if (keyState.IsKeyDown (Keys.PageUp)) 
         { buttons |= Buttons.Y; }
      if (keyState.IsKeyDown (Keys.Escape)) 
         { buttons |= Buttons.Back; }
      if (keyState.IsKeyDown (Keys.Enter)) 
         { buttons |= Buttons.Start; }

      return new GamePadState(
         new GamePadThumbSticks(leftThumbstick, rightThumbstick), 
         new GamePadTriggers(leftTrigger, rightTrigger), 
         new GamePadButtons(buttons),
         new GamePadDPad(dPadUp, dPadDown, dPadLeft, dPadRight));
   }

The selection for mapping keyboard keys to controller buttons was arbitrary. I wanted easy access for using both thumbsticks, pressing A, or pressing B. The escape key felt like a natural fit for Back, and the enter key felt like a natural fit for Select.

There’s nothing preventing you from mapping several keyboard keys to the same controller button. For example, if your game uses the left thumbstick and ALL four of the A, B, X, Y buttons but makes little use of the right thumbstick, it might make more sense to map the I, J, K, and L keys to the colored buttons.

GamePadEx.SetVibration

While I said earlier that we don’t need to tweak the SetVibration method since keyboards don’t have rumble motors, it’s odd that we’d pass that request on to a (most likely) disconnected controller.

In fact, the framework documentation says that querying the state of a disconnected controller is invalid for all but the IsConnected member. So, we’ll check to see if the specified playerIndex is the one associated with the keyboard, and do nothing in that case.

“When a controller is disconnected, values for its state will not be valid. Also, the controller will not receive any new vibration settings.”

Just replace the existing SetVibration method in our GamePadEx class with the following code to make it keyboard-aware.

      public static bool SetVibration(
         PlayerIndex playerIndex, 
         float leftMotor, 
         float rightMotor)
      {
         if(GamePadEx.IsKeyboardPlayerIndex(playerIndex)) {
            return false;
         } else {
            return GamePad.SetVibration (
               playerIndex, 
               leftMotor, 
               rightMotor);
         }
      }

Summary

That’s it. We’re done. Our helper class is ready to drop into any game that would like to allow the keyboard to act as a controller.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 15: Odds and Ends, TouchPanelEx

Overview

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sit amet fringilla augue. Integer justo lectus, fringilla sed tempus quis, accumsan ut mi. Duis ipsum quam, sodales ac fringilla at, gravida finibus ante. Fusce facilisis tellus et ultricies volutpat. Mauris eget tincidunt nulla. Vestibulum sodales nibh ipsum, nec euismod erat maximus id. Praesent posuere ultrices ultricies. Fusce bibendum vulputate mauris eu ultricies. Donec id laoreet ante, vel imperdiet dolor. Morbi suscipit lectus sit amet euismod imperdiet.

Nullam vulputate ipsum id maximus vulputate. Nullam tempor accumsan odio, ac accumsan tellus ultricies at. Nunc ex justo, egestas nec condimentum id, lobortis condimentum urna. Suspendisse potenti. Donec scelerisque leo quis felis facilisis bibendum. Etiam augue quam, varius nec enim dictum, imperdiet semper ex. Donec feugiat consectetur nulla, quis eleifend mauris vehicula ac. Duis pretium ac lacus vel gravida. Donec facilisis vestibulum venenatis. Donec odio arcu, rhoncus at semper vel, iaculis eu sapien.

Summary

Blah. Blah. Blah. Blah. Blah.

Review Questions

Blah. Blah. Blah. Blah. Blah.

Exercises

Blah. Blah. Blah. Blah. Blah.


Chapter 16: Odds and Ends, Collision Detection

Overview

Nothing irritates players more than thinking that they hit an opponent and the hit doesn’t register, or thinking that they dodged a bullet only to find that they’ve lost a life. For most game programming tasks, ‘‘close enough’’ is perfectly fine. Collision detection isn’t one of those tasks, though.

In this chapter, we will develop a reusable class to help us manage pixel-perfect 2D collision detection.

In this chapter, you will learn how to:

  • Extract pixel data from a texture
  • Quickly determine whether two on-screen sprites are touching

Opacity Data

Sprites are based on textures. Those textures are made up of pixels. To determine if two sprites are touching, you need to see if any common, opaque (non-transparent) pixels occupy the same on-screen pixel. To do that, you’ll need to access the pixel data for the texture(s) of the two sprites. Luckily there’s a method in the Texture2D class that does just that.

To access the pixels for a texture, we’ll use code similar to the following:

   // an array to hold the pixel data from the texture
   Color[] pixels = new Color[texture.Width * texture.Height];
   // fill our array with the texture's pixel data 
   texture.GetData<Color>(pixels);

Now we can access any pixel in the single-dimensional array using code similar to the following:

   Color pixel = pixels[x + (y * texture.Width)];

Remembering Opacity

The GetData method of the Texture2D class is fairly expensive in terms of performance and memory usage (and garbage collection churn). We’ll want to get the data once, and then store it somewhere so that we can refer to that in-memory copy of the data rather than pulling it from the texture every time we need to inspect a sprite’s pixels.

It’s not important what color each pixel in our sprite is. We only need to know if the pixel is opaque or transparent. Rather than store the colors of each pixel, we’ll store an array of bool values that tell us whether a given pixel is opaque.

Alpha Threshold

There may be some pixels that aren’t fully opaque or fully transparent. For example, your sprite may have a drop shadow. In that case, you probably don’t want a collision to be triggered when the missile hits the ship’s shadow. To make our code configurable, we’ll add a threshold value for the opacity. If the alpha is greater than or equal to this threshold, we’ll consider that pixel to be opaque.

A Simple Collision Detection Optimization

Even though we saved some processing effort by storing our pixel data in an array of booleans rather than repeatedly accessing the texture’s pixel data directly, it’s still rather CPU-intensive to scan an opacity data array for every pixel of every sprite that’s on the screen with every call to our game’s Update method.

It’s a complete waste of time and resources to check for collisions, pixel by pixel, when the sprite textures don’t overlap at all. To save ourselves some effort (and some valuable CPU cycles), we need to make sure that there’s at least a chance for a collision, by checking to see if our sprite textures overlap.

The PixelPerfectHelper Class

The PixelPerfectHelper class contains a collection of static methods to help us detect 2D collisions.

   using System;
   using Microsoft.Xna.Framework;
   using Microsoft.Xna.Framework.Graphics;
   
   namespace MoreOnCode.Graphics
   {
      public class PixelPerfectHelper
      {
         // TODO: Implement GetOpaqueData
         public static bool[,] GetOpaqueData(
            Texture2D texture, Rectangle rect, byte threshold)
         {
            return null;
         }
   
         // TODO: Implement DetectCollision
         public static bool DetectCollision(
            Rectangle rect1, Vector2 loc1, bool[,] data1,
            Rectangle rect2, Vector2 loc2, bool[,] data2)
         {
            return false;
         }
   
      }
   }

GetOpaqueData

The first task in collision detection is to generate our opacity data array. Given a Texure2D object, the texture rectangle for the sprite, and an opacity threshold, the GetOpaqueData generates and returns an array of Boolean values that represent the opacity of each pixel of the sprite.

         // REPLACE PLACEHOLDER CODE WITH THE FOLLOWING
         // TODO: Implement GetOpaqueData
         // REPLACE PLACEHOLDER CODE WITH THE FOLLOWING

         // overload for GetOpaqueData(Texture2D, Rectangle, byte)
         public static bool[,] GetOpaqueData(IPixelPerfectSprite sprite)
         {
            return GetOpaqueData(sprite.TextureData, sprite.TextureRect, 255);
         }

         // overload for GetOpaqueData(Texture2D, Rectangle, byte)
         public static bool[,] GetOpaqueData(
            IPixelPerfectSprite sprite, byte threshold)
         {
            return
               GetOpaqueData(sprite.TextureData, sprite.TextureRect, threshold);
         }

         // overload for GetOpaqueData(Texture2D, Rectangle, byte)
         public static bool[,] GetOpaqueData(Texture2D texture, Rectangle rect)
         {
            return GetOpaqueData(texture, rect, 255);
         }

         // extract pixel data from the texture
         public static bool[,] GetOpaqueData(
            Texture2D texture, Rectangle rect, byte threshold)
         {
            // temp variables to save some typing
            int width = rect.Width;
            int height = rect.Height;

            // an array of booleans, one for each pixel
            // true = opaque (considered), false = transparent (ignored)
            bool[,] data = new bool[width, height];

            // an array to hold the pixel data from the texture
            Color[] pixels = new Color[texture.Width * texture.Height];

            // I'd rather have used the overload for Texture2D.GetData
            // that specifies the texture rect, but that function didn't
            // work on the Xbox 360. This version pulls pixel data from 
            // the entire texture, but it should be OK since we're only 
            // using it briefly, and only on init of our game sprites.
            texture.GetData<Color>(pixels);

            // for each row of pixel data
            for (int y = 0; y < height; y++)
            {
               // for each column of pixel data
               for (int x = 0; x < width; x++)
               {
                  // if the pixel's alpha exceeds our threshold,
                  // note it in our boolean array
                  if (pixels[
                     rect.Left + x +
                     (rect.Top + y) *
                     texture.Width].A >= threshold)
                  {
                     data[x, y] = true;
                  }
               }
            }

            // return our findings to the caller
            return data;
         }

DetectCollision

Once we have our opacity data, we can start checking for sprite collisions. The DetectCollision method encapsulates the two checks that need to be performed - do the sprite textures overlap, and, if so, do any of the overlapping, opaque pixels touch? These two checks are handled by the BoundsOverlap and PixelsTouch methods, respectively.

         // REPLACE PLACEHOLDER CODE WITH THE FOLLOWING
         // TODO: Implement DetectCollision
         // REPLACE PLACEHOLDER CODE WITH THE FOLLOWING
   
         // overload for DetectCollision(Rect, Vec2, bool[], Rect, Vec2, bool[,])
         public static bool DetectCollision(
            IPixelPerfectSprite one, IPixelPerfectSprite two)
         {
            return DetectCollision(
               one.TextureRect, one.Location, one.OpaqueData,
               two.TextureRect, two.Location, two.OpaqueData);
         }

         // determine whether the bounding rectangles of the sprites overlap
         // if they do, compare pixel-by-pixel within the intersection
         public static bool DetectCollision(
            Rectangle rect1, Vector2 loc1, bool[,] data1,
            Rectangle rect2, Vector2 loc2, bool[,] data2)
         {
            return
               BoundsOverlap(rect1, loc1, rect2, loc2) &&
               PixelsTouch(rect1, loc1, data1, rect2, loc2, data2);
         }

         // TODO: Implement BoundsOverlap
         protected static bool BoundsOverlap(
            Rectangle rect1, Vector2 loc1,
            Rectangle rect2, Vector2 loc2)
         {
            return false;
         }

         // TODO: Implement PixelsTouch
         protected static bool PixelsTouch(
            Rectangle rect1, Vector2 loc1, bool[,] data1,
            Rectangle rect2, Vector2 loc2, bool[,] data2)
         {
            return false;
         }

Note the two helper methods - BoundsOverlap and PixelsTouch. They’re used internally by CheckForCollisions. The first check is quick. We just want to know if the two specified sprites overlap. If not, we don’t have to check any further.

The three steps of collision detection.

If the sprites do overlap, we’ll need to check the subset of opaque pixels that overlap. If any of those are touching, we have a collision.

BoundsOverlap

The BoundsOverlap method returns a boolean value. If any part of the bounding rectangles of the two sprites overlap, this method will return true.

If the first sprite is fully to the left, fully to the right, fully above, or fully below the second sprite, there is no overlap. Otherwise, the bounding rectangles of the two sprites do overlap, and we need to perform a pixel-by-pixel comparison.

         // REPLACE PLACEHOLDER CODE WITH THE FOLLOWING
         // TODO: Implement BoundsOverlap
         // REPLACE PLACEHOLDER CODE WITH THE FOLLOWING

         // see if the texture rectangles overlap, if they don't, there's
         // no need to do a pixel-by-pixel comparison
         protected static bool BoundsOverlap(
            Rectangle rect1, Vector2 loc1,
            Rectangle rect2, Vector2 loc2)
         {
            // determine the top, left, bottom, right for rect1
            int top1 = (int)loc1.Y;
            int left1 = (int)loc1.X;
            int bottom1 = top1 + rect1.Height;
            int right1 = left1 + rect1.Width;

            // determine the top, left, bottom, right for rect2
            int top2 = (int)loc2.Y;
            int left2 = (int)loc2.X;
            int bottom2 = top2 + rect2.Height;
            int right2 = left2 + rect2.Width;

            return !(
               // rect1 fully to the right of rect2?
               left1 > right2 ||
               // rect1 fully to the left of rect2?
               right1 < left2 ||
               // rect1 fully below rect2?
               top1 > bottom2 ||
               // rect1 fully above rect2?
               bottom1 < top2
            );
         }

PixelsTouch

This is the routine where pixel-by-pixel comparisons are performed. First, we calculate the bounds of the smallest rectangle that contains all of the overlapping pixels of both sprites. Then, we focus our search for a collision to that subset of the opaque data. If both sprites have an opaque pixel at the same location, a collision has occurred.

         // REPLACE PLACEHOLDER CODE WITH THE FOLLOWING
         // TODO: Implement PixelsTouch
         // REPLACE PLACEHOLDER CODE WITH THE FOLLOWING

         // perform a pixel-by-pixel comparison
         protected static bool PixelsTouch(
            Rectangle rect1, Vector2 loc1, bool[,] data1,
            Rectangle rect2, Vector2 loc2, bool[,] data2)
         {
            // update rects with locations of sprites
            rect1.X = (int)Math.Round(loc1.X);
            rect1.Y = (int)Math.Round(loc1.Y);
            rect2.X = (int)Math.Round(loc2.X);
            rect2.Y = (int)Math.Round(loc2.Y);

            // determine the intersection of the two rects
            Rectangle intersect = Rectangle.Empty;
            intersect.Y = Math.Max(rect1.Top, rect2.Top);
            intersect.X = Math.Max(rect1.Left, rect2.Left);
            int bottom = Math.Min(rect1.Bottom, rect2.Bottom);
            int right = Math.Min(rect1.Right, rect2.Right);
            intersect.Height = bottom - intersect.Y;
            intersect.Width = right - intersect.X;

            // scan the intersected rectangle, pixel-by-pixel
            int x1 = intersect.X - rect1.X;
            int x2 = intersect.X - rect2.X;
            int y1 = intersect.Y - rect1.Y;
            int y2 = intersect.Y - rect2.Y;
            for (int y = 0; y < intersect.Height; y++)
            {
               for (int x = 0; x < intersect.Width; x++)
               {
                  // are both pixels opaque?
                  if (data1[x1 + x, y1 + y] &&
                     data2[x2 + x, y2 + y])
                  {
                     return true;
                  }
               }
            }
            return false;
         }

PixelPerfectHelper in Action

To keep our parameter lists small, we’ll make sure that the game’s custom sprite class implements the IPixelPerfectSprite interface.

   using System;
   using Microsoft.Xna.Framework;
   using Microsoft.Xna.Framework.Graphics;

   namespace MoreOnCode.Graphics
   {
      // a handy interface to allow you to pass your game sprite 
      // into these helper methods, saving some typing in your 
      // parameter lists
      public interface IPixelPerfectSprite
      {
         Texture2D TextureData { get; set; }
         Rectangle TextureRect { get; set; }
         Vector2 Location { get; set; }
         bool[,] OpaqueData { get; set; }
      }
   }

That interface exposes all of the sprite properties that we’ll need to perform collision detection. The following is an example class that implements the interface.

   using System;
   using Microsoft.Xna.Framework;
   using Microsoft.Xna.Framework.Graphics;

   namespace MoreOnCode.Graphics
   {
      // a handy class to allow you to refer to your sprite
      // and its associated data in one instance
      public class GameSprite : IPixelPerfectSprite 
      {
         public Texture2D TextureData { get; set; }
         public Rectangle TextureRect { get; set; }
         public Vector2 Location { get; set; }
         public bool[,] OpaqueData { get; set; }

         // draw this sprite, using current settings, and specified tint
         public void Draw(SpriteBatch batch, Color color)
         {
            batch.Draw(TextureData, Location, TextureRect, color);
         }
      }
   }

Our Game

Since this set of classes is used in several of the example games, I’m not going to write a new example just to showcase collision detection. If you’d like to see collisions in action check out one of the following chapters.

  • Chapter 4: Spit Polish
  • Chapter 5: Side Scroller
  • Chapter X: Blah. Blah. Blah.

A contrived example follows.

   var foo = new bar();

In this example, blah. Blah. Blah. Blah.

Summary

In this chapter, you learned how to inspect pixel data from a texture and use that data to perform pixel-perfect collision detection between 2D objects. You learned about some of the performance concerns with this method, and you picked up a couple of optimization tips for offsetting those penalties.

Review Questions

Think about what you’ve read in this chapter (and the included source code) to answer the following questions.

  1. What are the two basic checks that are performed when detecting collisions using the methods described in this chapter?
  2. Why are two checks performed?
  3. Why is opacity data collected once, when the texture is first loaded?
  4. How does this method of collision detection avoid false positives, for example when one sprite touches another sprite’s shadow?

Exercises

EXERCISE 1. Create a game, based on the code in this chapter, where any balls that the player touches become stuck to the player. Move the attached balls the same distance and in the same direction as the player as his location is updated.

EXERCISE 2. Similar to the first exercise, create a game, based on the code in this chapter, where any balls that the player touches begin to follow the player. Track the last NUM_OBSTACLES location of the player, and render each captured obstacle in one of those locations to achieve a growing snake effect.

EXERCISE 3. Create a game, based on the code and images in this chapter, that uses more than one obstacle image. Circles are a good test shape since they have transparent data on all sides, but it’s a little boring. Add some stars, crescent moons, gears, or any other irregular shape that you like. To keep things simple, you can still use a single source texture, but you’ll need to have distinct texture rectangles for each obstacle object.


Chapter 17: Odds and Ends, Particles

Overview

Individual particles are usually rather insignificant. But collectively, particles can be used to great effect, with minimal resource consumption.

Particles are created and managed by an object known as an emitter. The emitter spawns new particles from its current location, configuring each with a location, velocity, lifetime, and other properties. Once they leave the emitter, particles are pretty much independent objects. Global forces like gravity and wind may affect particles, and they may vary their color or opacity over time (for example a burning ember may fade to nothing).

Particle systems are used in a wide variety of game genres for a wide variety of in-game effects.

  • When your racecar scrapes against a guardrail, the sparks are particles.
  • When you’re snowboarding down a mountain, the snow wash from your board is made up of particles.
  • When you fire a missile from your fighter jet, the vapor trail is made up of particles.
  • When your 12th-level mage summons enough mana to cast a healing spell, the aura that surrounds her contains particles.
  • When you clear a row in your favorite puzzle game and the blocks explode, the falling pieces are particles.
  • When you shoot out a window in a first-person shooter, the shards of glass that fall to the ground are particles.
  • When a comet flies by your starship, its tail contains particles.
  • When you throw a smoke grenade onto the battlefield, the resulting smokescreen is made up of particles.
  • When you walk past a fountain in your favorite MMORPG, the water jets are made up of particles.

Getting Started

In this chapter, we will create a simple 2D particle system. The example code that we will develop is by no means a complete implementation, but it should provide a good base for you to build on, and it will effectively demonstrate the basic features of a 2D particle system. Many of the concepts that you learn here will apply to 3D particle systems as well.

Some particle systems account for collisions between particles and other game objects but rarely include checks for collisions between particles and other particles. In the interest of simplicity, the code that we develop in this chapter doesn’t include any non-particle game objects, so we won’t add collision checking to our system.

In this chapter, you will learn how to:

  • Manage thousands of simple game objects simultaneously
  • Limit the resources that these objects consume
  • Add simple effects to your game to make it more immersive

The Architecture

The particle effect is made up of a few, specialized classes. These classes work together to manage the state of individual particles, and then render the results to the screen. This example is designed around the MonoGame Framework’s 2D graphics APIs, but most of the principles that we’ll discuss in this chapter are also applicable in a 3D particle system.

The Particle

The particle is the basic building block of any particle system. Particles appear on the screen as a single point or 2D graphic. Minimally, particles have a location and velocity. Our particles will also include properties for color, age, lifetime, rotation, opacity, scale, and depth. The Particle class has only two methods: Update and Draw.

The following list describes each of the parameters and methods of this class.

  • Age: The number of (cumulative) seconds that this particle has been active.
  • Color: The tint with which to draw this sprite.
  • Depth: The Z-Order of this sprite, expressed as a float between 0.0f and 1.0f.
  • IsActive: The current state of this particle. Particles are created once, and placed in a pool. When a particle is marked as inactive, it’s available to be spawned as a new on-screen particle.
  • Lifetime: The maximum number of (cumulative) seconds that this particle may remain active.
  • Velocity: The distance that this particle will travel in a single second, assuming no outside force (like gravity or wind) is affecting it.
  • Opacity: The current transparency of this particle.
  • Location: The current location (screen coordinates) of this particle.
  • Rotation: The current rotation of this particle, expressed in radians.
  • Scale: The scale of this particle, where 1.0f is the actual size of the source texture.
  • Draw(): Draw this particle using its current properties.
  • Update(): Move the sprite, and update its age.

The Particle class is basically just a warehouse for the properties that the Emitter class uses to manage each particle.

   using System;
   using Microsoft.Xna.Framework;
   using Microsoft.Xna.Framework.Graphics;

   namespace MoreOnCode.Graphics.ParticleSystem
   {
      public struct Particle
      {
         public bool IsActive;
         public double Age;
         public double LifeTime;
         public Vector2 Position;
         public Vector2 Velocity;
         public Vector4 Color;
         public float Rotation;
         public float Opacity;
         public float Scale;
         public float Depth;

         // update position (based on m_Movement) and age
         public void Update(float elapsed)
         {
            // only update active particles
            if (IsActive)
            {
               // move the particle
               Position += Velocity * elapsed;

               // check for expired particles
               if (LifeTime != 0.0f) // 0.0f == never dies
               {
                  Age += elapsed;
                  if (Age > LifeTime)
                  {
                     IsActive = false;
                  }
               }
            }
         }

         // render the particle
         public void Draw(
            SpriteBatch batch,
            Texture2D texture,
            Rectangle clipRect)
         {
            // only draw active particles
            if (IsActive)
            {
               batch.Draw(
                  texture,
                  Position,
                  clipRect,
                  new Color(Color),
                  Rotation,
                  Vector2.Zero,
                  Scale,
                  SpriteEffects.None,
                  Depth);
            }
         }
      }
   }

As you can see from the preceding listing, the particle implementation is (intentionally) quite simple. Particle systems are meant to be lightweight, requiring very little CPU time and memory for each particle.

The Emitter

The emitter is responsible for managing individual particles, spawning new particles and reclaiming expired particles.

The emitter is initialized with a maximum number of particles to manage. Particles are created once, and placed in a pool of inactive particles, ready to be spawned. Whenever a new particle is needed, it’s moved from the inactive pool, initialized with new property values, and placed in a pool of active particles. With each call to the emitter’s Update method, the particle’s Update method is called for each particle object in the active pool.

NOTE: There are a couple of reasons why particles are implemented as a pooled resource, rather than creating them as they’re needed.

The first reason is to reduce the overhead of creating and destroying the objects that represent each particle. There is a performance penalty for allocating, initializing, and releasing thousands or millions of in-memory objects. By creating the objects once, and then placing them in a pool, we eliminate two of those three tasks.

The second reason that particles are implemented as a pooled resource is that they’re basically just eye candy. They’re not essential to the game play. By limiting our particles to a fixed number, we can be sure that we won’t create so many particles that their processing and memory usage affects more critical areas of the game logic.

The emitter also contains the ranges of values that each of the particle’s properties should be initialized to. By initializing properties from a range of values (rather than simply assigning a single, static value to each new particle) particles seem to act more independently.

To help us track these ranges, I’ve created a simple, templated class that will contain the minimum and maximum values for a given property, and generate a random value for us that lies within that range. This class is called RangedValue, and we will discuss it in more detail later in this chapter.

The emitter also manages a list of global particle forces, like gravity and wind. These global forces are derived from a common base class called a Modifier, which we will also discuss later in this chapter.

As with the Particle class, the Emitter class has many configurable properties. The following list describes each of the parameters and methods of the Emitter class.

  • Active: When false, active particles will continue to be updated and drawn, but new particles will not be spawned.
  • Enabled: When false, all processing is paused. Active particles will not be updated, and nothing will be drawn.
  • EmitterRect: Emitters have a width and height so that particles can be spawned from within a rectangle, rather than from a single point.
  • EmitterBoundsRect: In addition to a particle’s Lifetime property, we can reclaim particles when they leave the screen (or when they leave the EmitterBoundsRect).
  • Position: It’s a pain to update a rectangle when all you wanted to do was move the emitter to a new location, so this helper allows you to just specify a new X and Y to change the EmitterRect.
  • ParticlesPerUpdate: This is the number of new particles to emit with each call to Update. If there aren’t enough particles in the inactive pool to satisfy this request, the number of particles actually spawned will be less than this value.
  • MaxParticles: This is the maximum number of particles that the emitter will ever actively manage. By placing an upper limit, we can make sure that our emitter isn’t stealing resources that could be better used for other parts of our game.
  • ParticleLifetime: The number of seconds that a single particle may be active before being reclaimed.
  • RangeColor: The range of colors from which a new particle will have its Color property initialized.
  • RangeVelocity: The range of velocities from which a new particle will have its Velocity property initialized.
  • Texture: The texture of the sprite that represents a particle.
  • TextureRect: The source rectangle, within the Texture, for all particles.
  • AddModifier(): Add a modifier (like gravity) to this emitter.
  • ClearModifiers(): Clear the list of modifiers for this emitter.
  • RemoveModifier(): Remove a specific modifier from this emitter.
  • Draw(): Draw all active particles.
  • Update(): Spawn new particles, update all active particles, apply any global modifiers (like gravity) to all active particles, and reclaim any inactive particles for later use.
   using System;
   using System.Collections.Generic;
   using Microsoft.Xna.Framework;
   using Microsoft.Xna.Framework.Graphics;

   namespace MoreOnCode.Graphics.ParticleSystem
   {
      public class Emitter
      {
         // default constructor, 1000 particles
         public Emitter() : this(1000) { }

         // init emitter with max particles
         public Emitter(long maxParticles) : base()
         { 
            this.MaxParticles = maxParticles;
            this.ParticlesPerUpdate = 1;
            this.ParticleLifetime = 10.0f;
            this.EmitterRV2 = new RangedVector2();
         }


         // helper to init particle locations within emitter bounds
         protected RangedVector2 EmitterRV2 { get; set; }

         // location and size of the emitter
         protected Rectangle m_EmitterRect;
         public Rectangle EmitterRect
         {
            get { return m_EmitterRect; }
            set
            {
               m_EmitterRect = value;
               EmitterRV2 = RangedVector2.FromRectangle(m_EmitterRect);
            }
         }

         // helper to update the location of the emitter
         public Vector2 Position
         {
            get { return new Vector2(m_EmitterRect.Left, m_EmitterRect.Top); }
            set
            {
               EmitterRect = new Rectangle(
                  (int)Math.Round(value.X),
                  (int)Math.Round(value.Y),
                  m_EmitterRect.Width,
                  m_EmitterRect.Height);
            }
         }

         public Rectangle EmitterBoundsRect { get; set; }
         public RangedVector2 RangeVelocity { get; set; }
         public RangedVector4 RangeColor { get; set; }

         public Rectangle TextureRect { get; set; }

         protected Texture2D m_Texture;
         public Texture2D Texture
         {
            get { return m_Texture; }
            set
            {
               m_Texture = value;
               TextureRect = m_Texture.Bounds;
            }
         }

         public bool Enabled { get; set; } // false? don't draw, don't update
         public bool Active { get; set; } // false? draw and update, no new
         public long ParticlesPerUpdate { get; set; } // particles per frame

         // max number of particles that this emitter can track
         protected long m_MaxParticles = 1000;
         public long MaxParticles
         {
            get { return m_MaxParticles; }
            set
            {
               m_MaxParticles = Math.Max(value, 1L);
               m_ActiveParticles.Clear();
               m_InactiveParticles.Clear();
               for (long i = 0; i < m_MaxParticles; i++)
               {
                  m_InactiveParticles.Add(new Particle());
               }
            }
         }

         // lifespan of particle, expressed in seconds
         public float ParticleLifetime { get; set; }

         // keep track of active and inactive particles
         protected List<Particle> m_ActiveParticles = new List<Particle>();
         protected List<Particle> m_InactiveParticles = new List<Particle>();

         // keep track of attached modifiers
         public List<Modifier> Modifiers = new List<Modifier>();

The Update method manages the active particles that it owns, reclaiming spent particles and spawning new particles as needed.

         // manage active particles, spawn new particles if it's time to do so
         public virtual void Update(float elapsed)
         {
            // only update if enabled
            if (Enabled)
            {
               // temp variables to save typing
               bool outOfBounds;
               int parX, parY;
               for (int i = 0; i < m_ActiveParticles.Count; i++)
               {
                  var particle = m_ActiveParticles[i];

When a particle leaves the area of the screen that’s defined by the EmitterBoundsRect property, it becomes inactive.

                  // when particle leaves emitter bounds, mark inactive
                  parX = (int)Math.Round(particle.Position.X);
                  parY = (int)Math.Round(particle.Position.Y);
                  outOfBounds = 
                     parX < EmitterBoundsRect.Right &&
                     parX + TextureRect.Width > EmitterBoundsRect.Left &&
                     parY < EmitterBoundsRect.Bottom &&
                     parY + TextureRect.Height > EmitterBoundsRect.Top;
                  if (outOfBounds) particle.IsActive = false;

If the current particle is (still) active, any attached modifiers will be allowed to process it before it is asked to update itself.

                  // process active particles, cleanup inactive particles
                  if (particle.IsActive)
                  {
                     // allow active modifiers to update particle
                     foreach (var modifier in Modifiers)
                     {
                        if (modifier.Enabled)
                        {
                           // tell the modifier to update this particle
                           modifier.Update(particle, elapsed);
                        }
                     }
                     // tell particle to update itself
                     particle.Update(elapsed);
                  }
                  else
                  {
                     // move particle to inactive list for later reuse
                     m_InactiveParticles.Add(particle);
                     m_ActiveParticles.RemoveAt(i--);
                  }
               }

Now that all of the active particles have been updated, and newly inactive particles have been reclaimed, it’s time to spawn new particles.

               // try to generate ParticlesPerUpdate new particles
               for (long i = 0; Active && i < ParticlesPerUpdate; i++)
               {
                  if (m_InactiveParticles.Count > 0)
                  {
                     // reset particle and add it to our pool of active particles
                     var particle = m_InactiveParticles[0];
                     particle.Position = EmitterRV2.RandomValue();
                     particle.Velocity = RangeVelocity.RandomValue();
                     particle.Color = RangeColor.RandomValue();
                     particle.IsActive = true;
                     particle.LifeTime = ParticleLifetime;
                     m_InactiveParticles.RemoveAt(0);
                     m_ActiveParticles.Add(particle);
                  }

If we’ve run out of particles in our inactive pool, there’s no need to keep trying to spawn new particles. We’ll just exit the loop. Maybe there will be some more particles to play with during the next frame.

                  else
                  {
                     // no more particles in our inactive pool
                     break;
                  }
               }
            }
         }

The Draw method of the Emitter class simply iterates through the list of active particles, asking each to draw itself.

         // render the active particles
         public virtual void Draw(SpriteBatch batch)
         {
            // only draw particles when emitter is enabled
            if (Enabled)
            {
               foreach (var particle in m_ActiveParticles)
               {
                  // ask the particle to draw itself
                  particle.Draw(batch, Texture, TextureRect);
               }
            }
         }

      }
   }

Modifiers

Left to their own devices, particles will move at a constant rate, in a fixed direction. Particles maintain their own position data (the Position property) and velocity data (the Velocity property). Whenever the Update method is called on a particle, it modifies its own position using the simple formula, ‘‘Position = Position + Velocity.’’ That’s fine if you’re simulating a frictionless, gravity-free environment. In most scenarios, that’s not the case.

It doesn’t make much sense to implement global changes like gravity and wind at the particle level. Gravity affects every particle. So, the emitter manages a list of helper objects that can make global changes to particles. These helper objects are instances of the Modifier structure.

   using System;
   using Microsoft.Xna.Framework;

   namespace MoreOnCode.Graphics.ParticleSystem
   {
      // update a particle based on custom code, used by emitter
      public struct Modifier
      {
         // only update active modifiers
         public bool Enabled;
         public Vector2 PositionDelta;
         public Vector2 VelocityDelta;
         public float RotationDelta;
         public float ScaleDelta;
         public float DepthDelta;

         // called for each particle, every frame, by emitter, if enabled
         public void Update(Particle particle, float elapsed)
         {
            if (PositionDelta != Vector2.Zero) 
               { particle.Position += PositionDelta * elapsed; }
            if (VelocityDelta != Vector2.Zero) 
               { particle.Velocity += VelocityDelta * elapsed; }
            if (RotationDelta != 0.0f) 
               { particle.Rotation += RotationDelta * elapsed; }
            if (ScaleDelta != 0.0f) 
               { particle.Scale += ScaleDelta * elapsed; }
            if (DepthDelta != 0.0f) 
               { particle.Depth += DepthDelta * elapsed; }

            // allow for custom modifier logic
            if (OnUpdate != null) {
               OnUpdate (particle, elapsed);
            }
         }

         public delegate void OnUpdateDelegate(
            Particle particle, 
            float elapsed);
         public OnUpdateDelegate OnUpdate;

      }
   }

You can think of modifiers as a kind of plug-in. A simple gravity modifier would update particles using a formula similar to “particle.Velocity.Y = particle.Velocity.Y + this.VelocityDelta.Y.” A simple wind modifier would update particles using a formula similar to “particle.Velocity.X = particle.Velocity.X + this.VelocityDelta.X.” Modifiers are typically very simple, but they can be combined with other simple modifiers to achieve great composite effects.

   var modifierGravity = new Modifier();
   modifierGravity.VelocityDelta = new Vector2(0.0f, 200.0f);
   
   var modifierWind = new Modifier();
   modifierWind.VelocityDelta = new Vector2(200.0f, 0.0f);
   
   emitter.Modifiers.Add(modifierGravity);
   emitter.Modifiers.Add(modifierWind);

Of course, the above example could be combined to create a single Modifier for both effects.

   var modifierGravityAndWind = new Modifier();
   modifierGravityAndWind.VelocityDelta = 
      new Vector2(200.0f, 200.0f);
   
   emitter.Modifiers.Add(modifierGravityAndWind);

Modfiers don’t have to limit themselves to the exposed particle “Delta” properties. You can also add a custom OnUpdate delegate to perform more complex calculations.

   var modifier = new Modifier ();
   modifier.OnUpdate = 
      new Modifier.OnUpdateDelegate (MyUpdateFunction);
   emitter.Modifiers.Add(modifier);

Using your own logic, you might change the particles’ colors to create a pulsing or fading effect. Or you might change the particles’ size or rotation to create interesting falling leaves or snow. Or you might create a single-point gravity effect so that particles are pulled into a black hole or whirlpool.

NOTE: We could just as easily have implemented these effects in the Emitter class, but using modifiers allows us to add new effects without changing the core emitter class every time. Coding and maintenance are easier since the effect classes are self-contained, and debugging is easier since the emitter implementation isn’t constantly changing.

Of course, there may be a performance penalty for calling the modifier’s Update method once for every particle. If we find that to be the case, we could consider breaking the modifier updates into a separate pass, processing particles before or after the emitter is done with its update pass.

In that scenario, modifiers no longer work on a single particle at a time—they’re called once per update, and they process all the active particles in a loop (saving thousands of calls to the modifier’s Update method). This method might introduce other performance issues, though (like cache misses). So, you’ll want to profile your code before and after to see if your ‘‘optimizations’’ are doing what you think they should.

Ranged Values

The RangedValue class contains two properties (Min and Max) that store the minimum and maximum values for this range, and a method (RandomValue) to generate a value within this range. The class also contains another property (Value) that returns the result of the last call to the RandomValue method.

This is the first time that we’ll be using a feature of the C# programming language known as generics. Generics allow you to define a single class that performs a common set of tasks, then change the type of data that the class uses.

For example, we can define a simplified RangedValue class that just holds our Min and Max values using the following code:

   public class RangedValue<T>
   {
      // the min value
      public T Min { get; set; }
      public T Max { get; set; }
   }

To use this class for a ranged integer, a ranged string, and a ranged Color, we could then add code similar to the following to our game:

   RangedValue<int> IntRange;
   RangedValue<string> StringRange;
   RangedValue<Color> ColorRange;

Before generics, we had two basic options. The first option was to implement each of these variations as a separate class, possibly implementing a common interface in each specialized class (or deriving each from a common base class) so that we could pass the object among methods generically. The second option was to implement the RangedValue class so that the Min and Max properties used System.Object as their data type, but that would require runtime casting (boxing and unboxing) and performance would suffer if we used the class extensively.

While the first option is better in terms of performance, maintaining multiple classes is a pain. If you make a change to one of the classes, you need to remember to make the same change to the other classes.

Under the covers, the compiler is basically doing the work of the first option for us when we use generics by creating separate, specialized classes, each based on our template. This gives us the performance benefits of using the data types that we’re actually interested in using, while limiting the amount of code that’s involved (versus writing everything by hand). Of course, generics have some restrictions, and that’s why the preceding example is simplified.

Storing type-specific data is the easy part. Converting random values (which are stored as integers or floating-point values) to types that cannot be known at compile time is harder. For that reason, we do have to implement type-specific classes, but generics still save us from duplicating more code than we have to.

The actual RangedValue class source code listing follows.

   using System;
   using Microsoft.Xna.Framework;

   namespace MoreOnCode.Graphics.ParticleSystem
   {
      // simple class to hold min / max values and generate random values 
      // within those bounds. b ase class uses generics (templates)
      public abstract class RangedValue<T>
      {
         public RangedValue() : this(default(T), default(T)) {}

         public RangedValue(T min, T max) : base()
         {
            this.Min = min;
            this.Max = max;
         }

         public T Min { get; set; }
         public T Max { get; set; }
         public T Value { get; set; }

         // random number generator
         protected Random m_rand = new Random();

         // generate a random value between min and max, inclusive
         public abstract T RandomValue();
      }

      public class RangedByte : RangedValue<byte>
      {
         public RangedByte() : base() { }
         public RangedByte(byte min, byte max) : base(min, max) { }

         // generate a random value between min and max, inclusive
         public override byte RandomValue()
         {
            Value = (byte)Math.Round(
               MathHelper.Lerp(
                  (float)Min,
                  (float)Max,
                  (float)m_rand.NextDouble()));
            return Value;

         }
      }

      // type-specific subclass
      public class RangedInt : RangedValue<int>
      {
         public RangedInt() : base() { }
         public RangedInt(int min, int max) : base(min, max) { }

         // generate a random value between min and max, inclusive
         public override int RandomValue()
         {
            Value = (int)Math.Round(
               MathHelper.Lerp(
                  (float)Min,
                  (float)Max,
                  (float)m_rand.NextDouble()));
            return Value;

         }
      }

      // type-specific subclass
      public class RangedLong : RangedValue<long>
      {
         public RangedLong() : base() { }
         public RangedLong(long min, long max) : base(min, max) { }

         // generate a random value between min and max, inclusive
         public override long RandomValue()
         {
            Value = (long)Math.Round(
               MathHelper.Lerp(
                  (float)Min,
                  (float)Max,
                  (float)m_rand.NextDouble()));
            return Value;

         }
      }

      // type-specific subclass
      public class RangedFloat : RangedValue<float>
      {
         public RangedFloat() : base() { }
         public RangedFloat(float min, float max) : base(min, max) { }

         // generate a random value between min and max, inclusive
         public override float RandomValue()
         {
            // linear interpolation between min and max based on random number
            Value = (float)MathHelper.Lerp(
               (float)Min,
               (float)Max,
               (float)m_rand.NextDouble());
            return Value;

         }
      }

      // type-specific subclass
      public class RangedDouble : RangedValue<double>
      {
         public RangedDouble() : base() { }
         public RangedDouble(double min, double max) : base(min, max) { }

         // generate a random value between min and max, inclusive
         public override double RandomValue()
         {
            // linear interpolation between min and max based on random number
            Value = (double)MathHelper.Lerp(
               (float)Min,
               (float)Max,
               (float)m_rand.NextDouble());
            return Value;

         }
      }

      // type-specific subclass
      public class RangedVector2 : RangedValue<Vector2>
      {
         public RangedVector2() : base() { }
         public RangedVector2(Vector2 min, Vector2 max) : base(min, max) { }

         // generate a random value between min and max, inclusive
         public override Vector2 RandomValue()
         {
            // linear interpolation between min and max based on random number
            var value = Vector2.Zero;
            value.X = (float)MathHelper.Lerp(
               (float)Min.X,
               (float)Max.X,
               (float)m_rand.NextDouble());
            value.Y = (float)MathHelper.Lerp(
               (float)Min.Y,
               (float)Max.Y,
               (float)m_rand.NextDouble());
            this.Value = value;
            return Value;

         }

         // determine min and max values from a Rectangle
         public static RangedVector2 FromRectangle(Rectangle rect)
         {
            Vector2 v2Min = Vector2.Zero;
            v2Min.X = rect.Left;
            v2Min.Y = rect.Top;

            Vector2 v2Max = Vector2.Zero;
            v2Max.X = rect.Left + rect.Width;
            v2Max.Y = rect.Top + rect.Height;

            RangedVector2 rv2 = new RangedVector2();
            rv2.Min = v2Min;
            rv2.Max = v2Max;

            return rv2;
         }
      }

      // type-specific subclass
      public class RangedVector3 : RangedValue<Vector3>
      {
         public RangedVector3() : base() { }
         public RangedVector3(Vector3 min, Vector3 max) : base(min, max) { }

         // generate a random value between min and max, inclusive
         public override Vector3 RandomValue()
         {
            // linear interpolation between min and max based on random number
            var value = Vector3.Zero;
            value.X = (float)MathHelper.Lerp(
               (float)Min.X,
               (float)Max.X,
               (float)m_rand.NextDouble());
            value.Y = (float)MathHelper.Lerp(
               (float)Min.Y,
               (float)Max.Y,
               (float)m_rand.NextDouble());
            value.Z = (float)MathHelper.Lerp(
               (float)Min.Z,
               (float)Max.Z,
               (float)m_rand.NextDouble());
            this.Value = value;
            return Value;

         }
      }

      // type-specific subclass
      public class RangedVector4 : RangedValue<Vector4>
      {
         public RangedVector4() : base() { }
         public RangedVector4(Vector4 min, Vector4 max) : base(min, max) { }

         // generate a random value between min and max, inclusive
         public override Vector4 RandomValue()
         {
            // linear interpolation between min and max based on random number
            var value = Vector4.One;
            value.X = (float)MathHelper.Lerp(
               (float)Min.X,
               (float)Max.X,
               (float)m_rand.NextDouble());
            value.Y = (float)MathHelper.Lerp(
               (float)Min.Y,
               (float)Max.Y,
               (float)m_rand.NextDouble());
            value.Z = (float)MathHelper.Lerp(
               (float)Min.Z,
               (float)Max.Z,
               (float)m_rand.NextDouble());
            value.W = (float)MathHelper.Lerp(
               (float)Min.W,
               (float)Max.W,
               (float)m_rand.NextDouble());
            Value = value;
            return Value;
         }

         // determine min and max values from colors
         public static RangedVector4 FromColors(Color min, Color max)
         {
            Vector4 v4Min = Vector4.Zero;
            v4Min.X = (float)min.R / (float)byte.MaxValue;
            v4Min.Y = (float)min.G / (float)byte.MaxValue;
            v4Min.Z = (float)min.B / (float)byte.MaxValue;
            v4Min.W = (float)min.A / (float)byte.MaxValue;

            Vector4 v4Max = Vector4.Zero;
            v4Max.X = (float)max.R / (float)byte.MaxValue;
            v4Max.Y = (float)max.G / (float)byte.MaxValue;
            v4Max.Z = (float)max.B / (float)byte.MaxValue;
            v4Max.W = (float)max.A / (float)byte.MaxValue;

            RangedVector4 rv4 = new RangedVector4();
            rv4.Min = v4Min;
            rv4.Max = v4Max;

            return rv4;
         }
      }
   }

Our Game

Since this set of classes is used in several of the example games, I’m not going to write a new example just to showcase the particle effects. If you’d like to see the particles in action check out one of the following chapters.

  • Chapter 4: Spit Polish
  • Chapter 5: Side Scroller
  • Chapter X: Blah. Blah. Blah.

A contrived example follows.

   var emitter = new Emitter();
   emitter.ParticlesPerUpdate = 20;
   emitter.MaxParticles = 15000;
   emitter.EmitterRect = new Rectangle(200, 200, 0, 0);
   emitter.RangeColor = 
      RangedVector4.FromColors(Color.Orange, Color.Yellow);
   
   // add a modifier to the emitter
   var modifier = new Modifier();
   modifier.VelocityDelta = new Vector2(200.0f, 200.0f);
   emitter.Modifiers.Add (modifier);
   modifier.Enabled = false; // disable the modifier for now

In this example, the emitter will spawn no more than 20 new particles per frame, and no more than 15,000 particles will be active at any one time. Particles will be spawned from a single point on the screen (rather than a rectangular area since the Width and Height of the rectangle are both zero). New particles will be tinted yellow, orange, or some shade between those two extremes.

Summary

In this chapter you learned how to manage tens of thousands of simple game objects at the same time, with minimal resource usage. You also learned how particles are used in a wide variety of games as a simple way to make the environment more immersive.

Review Questions

Think about what you’ve read in this chapter (and the included source code) to answer the following questions.

  1. How do the particles seem to move independently of each other even though there’s only one game loop, one Particle2D.Update method, and one Particle.Draw method?
  2. What mechanism did we implement to make global changes across all particles?
  3. What is the RangedValue class? How is it useful for this chapter’s example code?
  4. Using everything you’ve read about this chapter’s particle system implementation, how might you go about simulating a fire using particles?
  5. List some examples of particles (or effects that you think may have been created using particles) in games that you have actually played. If those effects were omitted, would the game play suffer? Would the game be less immersive?

Exercises

EXERCISE 1. Create a new particle image to fall from the sky like rain. Be creative. Find or create a leaf, a snowflake, a smiley face, or any image of your choosing. Instantiate an Emitter for these particles that is located at the top-left of the screen with a width equal to the screen’s width and a height of zero. Add a Modifier to the emitter to simulate gravity. Set the RangeVelocity property of the emitter to new RangedVector2(Vector2.Zero, Vector2.Zero) so that the particles enter the simulation at rest, then fall as gravity takes hold of them.

EXERCISE 2. Modify Exercise 1 so that the emitter supports more than one particle image and randomly selects one image from the available images when spawning a new image. Rework the code you modified in the first exercise so that you can see a snowfall or autumn day with more variety.

EXERCISE 3. Create a new Modifier that attracts particles toward a single point on the screen (you’ll have to use the OnUpdate delegate for this one). Instantiate an Emitter with an EmitterRect that encompasses the entire screen so that particles can appear anywhere on the screen, then move toward this point.

EXERCISE 4. Create a simple fireworks game that fires exploding rockets into the sky. As the rocket travels up, leave a thin trail of small, orange particles. When the rocket reaches a certain altitude, change the behavior of the emitter to release several hundred brightly colored particles in a single burst. Make sure that all of these particles are affected by gravity.


Thanks for Reading!

Gushing love to the reader goes here


THE END