Sinister Soups Serving Musings On Game Development and Play

25May/101

Objects, Components, and Entities, Oh My!

A new post at last, and it’s that rarest of rare beasts, a programming post!

I’ve been reading and thinking about game system architecture lately. What I mean, specifically, is how objects and actors that take part in a game are represented in code, and what the relationships (in code) between them are like.

The traditional approach follows the Object Oriented programming model of a class hierarchy, where everything is represented by an object containing both data and functions, so that an Orc has both a Size value and an EatPeasant() function bundled up inside it. Furthermore, rather than writing each object from scratch, inheritance is used so that a tree of objects emerges, where specific actors like Orcs inherit much of their data and functionality from object higher up in the tree.

For example, an Orc may inherit its Size from a Monster class, as well as Position, which Monster in turn inherits from MovableObject, which inherits it from GameObject.

This is the naïve OOP approach to managing the actors in a game, and it is almost certainly the wrong approach, at least for a game of any appreciable size or complexity. Don’t get me wrong, it’s an intuitive way to set things up, especially for programmers with experience in other fields, and it can work very well for a small game where the hierarchy can be kept under control and doesn’t grow to massive, unmanageable proportions.

But there are better ways to do things, ways that are much cleaner once you have hundreds of different types of objects in your game, ways that are ultimately just as intuitive once you get used to them.

This is what I’ve been reading about, and pondering, in recent days: component-based architectures and entity systems for representing and managing the actors in your game. While I explain the concepts involved below, if you're really interested in the subject I recommend Mick West's article on the subject, which is very well written and goes into considerable detail.

At its most basic, a component-based architecture eschews a complex object hierarchy in favor of every actor in the game being a collection of components that define what that actor is, and what that actor does. Each actor then, apart from perhaps having some extremely common data such as an identifier, holds a list of components like PhysicsComponent, InputControllable, IsMonster, or whatever else is necessary to define all the operations that the actor can undergo.

These components then hold the relevant data and functions that define the actor, while centralized game systems either iterate over the actors, or even hold their own references to the individual actors’ components, and are able to do whatever updating or rendering the component requires every frame.

The benefits to this kind of setup are many. For one thing, instead of having perhaps hundreds of separate inherited objects, each necessitating its own class with all the upkeep that this entails, actors are simply the sum of their components, and any time a new component is written by a programmer, it can not only very easily be used to create new actors, but can also be trivially added to actors that already exist, giving them new functionality.

This means that with the proper tools, designers can easily redefine behavior on any actor simply by changing what components make up that actor, or tweaking the data that component manages; the only limitation is what components are available. Writing an individual component is also simpler and easier to test than modifying a fully realized, complex, working object that is being passed around throughout the game.

As an example, our Orc from before would be defined by the components that give it a size, and that allow it to eat peasants. If we then decide that Orcs should fly, we can give it a flying component, one which we might already be using for birds, or that we can subsequently use for whatever other actors we think should fly.

It also becomes trivially easy to make other Orc-like monsters, by simply swapping out a couple of components, or simply initializing the new monsters components with different data. For instance, a Goblin monster may be functionally identical to the Orc, but its SpriteComponent loads Goblin.jpg instead of Orc.jpg.

A component system within the confines of an object-oriented language like C++ or C# is all well and good, but what I found particularly interesting while reading on this subject was a method used by Adam Martin, to do away with the pesky and ill-fitting OOP paradigm entirely while designing this sort of component-based architecture.

Essentially, Adam proposes that the actors in a game (which he call entities, a common term that I have not used up until now specifically because he calls his method an Entity System) and their components should be approached using a database model.

Instead of even having an actor class which holds a list of component objects, he advocates divorcing the data and functionality of entities entirely from the traditional OOP model. An entity then becomes nothing more than a unique identifier, a number or a string, and components become packets of data needed by that entity.

Separate systems operate on the data in a component, for instance, a PhysicsSystem might take the data in a PhysicsComponent and use it modify the data in the entity’s PositionComponent, but components themselves merely hold data, not functionality.

The cool thing about this, though it took me a while to make sense of it, is that instead of passing around complex class-based objects in your code, you can simply hold onto an ID for the entity you want, and then essentially perform database-style queries to obtain any data you currently need from the components bound to that ID.

Not only do you get all the benefits of the popular and powerful component architecture, but you also keep your data separate from functionality which comes with a number of benefits; for example, it allows you to perform parallel operations easily on different entities (which are just sets of data) without breaking anything.

I feel like my thoughts about this database-like view of a component system are not yet fully formed, but I definitely feel like there is a powerful elegance to doing things this way. I will need to let the thoughts simmer some more before I have more to say about it, I think.

I recommend checking out Adam’s series of articles on the subject, linked above. It really is quite eye-opening.

18Mar/102

Source Control For The Hobbyist Developer

I've been working on an XNA game project with some friends in my free time, and as any professional developer knows, it's much more difficult to coordinate changes to a programming project without some sort of source control solution. While we did without in the beginning, it came to be too much of a hassle, and last night I finally set up source control repository for us. I was thinking that it might be helpful to others, and to myself for future reference, to outline the solution I ended up using, and how I set it up.

Firstly, what is source control? Source control is a way to let multiple people edit the same resources, whether that's documents or source code, without their edits stomping on each other. While there are different ways to accomplish this, the method my friends and I are used to involves checking out files from a central repository, editing them independently, and then checking them back into the repository. If multiple people check out the same file, then the first to check changes in can do so freely, while everyone who checks in after that needs to first correct any conflicts their checkins might have with that first person's changes.

Ultimately, for our home work, we wanted a system with a decent GUI, that was simple to use, and worked more or less how we were used to. Since there are a lot of sites out there that will host repositories using the Subversion (or SVN) source control system, and there is a popular shell integration application called TortoiseSVN which allows you to work with SVN without using the command line, this was the system we ended up going with.

The first thing you need to decide if you want to use TortoiseSVN is whether you want to have a local repository on your computer, which you can use to track your own changes to a project you are working on, but which you can't easily give other people access to, or if you want to have the repository stored on a server so that team members on multiple computers can all access and edit it easily.

In our case, the latter was the only logical choice, a local repository only makes sense if you are the only one working on a project, so we looked for a service site that would let us host a repository easily. We ended up going with XP-Dev, a service we chose because it allows free hosting of up to two SVN repositories with 200 MBs of space available, and also gives you a lot of rather nice tools as part of your account to make project management easier, tools like forums, a wiki, a blog, and bug and task tracking.

There are very many different hosting sites like this, however, so you may be able to find one that gives you even more space for free, if you need it, and they all offer subscription options as well that give you more space and unlock more powerful features.

Once you have an account set up, you will be able to create a repository for your project, and you should get a URL that you can use to access your repository. On XP-Dev, the repository URL looks something like this:
http://svn2.xp-dev.com/svn/some_project_name/

At this point, you are ready to install TortoiseSVN; you can get the installer at their download page. While it is installing, consider where you want your project to reside on your computer, you will need a directory that you designate as the root of your repository, so that Tortoise can download a copy of the repository there for you to edit and then check back into the repository on the server. In my case, I wanted to make sure the repository was obvious and easy to find, so I created a directory called D:\SVN\Projectname.

Once you have your directory ready, and Tortoise successfully installed (you will need to restart Windows for the shell integration to work correctly), you can then start setting up your repository. Assuming your repository on the server is empty at this point, move whatever folders you are going to be managing to your SVN\Projectname folder, right-click on the SVN\Projectname folder and select the TortoiseSVN --> Import option.

Import option, with equally relevant SVN Checkout option above it...

You will be prompted for the URL of the repository, which you should have gotten from your hosting service, and when you click OK, for your credentials to access that repository. Assuming there are no hiccups with your credentials, it should then upload the contents of your SVN\Projectname folder to the repository on the server, and the first revision of your project will be up and running!

While this put the files you want into your repository, it doesn't actually register that this directory is a local copy of the repository, and so you won't be able to use Tortoise to check in file and folder changes yet. To do this, you must now right-click on the SVN\Projectname folder, and select the SVN Checkout option, which will download the files back from the repository, and mark them as local copies that you can edit, and later commit to merge them back into the repository.

Once you have done this, you should see the folders in the SVN\Projectname folder with little green check-mark icons on top of them, indicating that they are fully up to date. If you edit any of these files or folders, the icon will change to a red stop sign, and when clicking on any file or folder in the repository directory structure, you will be able to use the SVN Update command to sync up to the newest version of the repository, and the SVN Commit command to check in any changes you have made.

SVN Update and SVN Commit commands available once you have checked out the repository.

A few other useful tips for working with Tortoise and SVN in general:

  • Since Tortoise is a shell extension, all of its functionality can be accessed through the right-click menu in Explorer. There are many nice options here to help you manage your files and your repository.
  • When you go to commit your changes, you will be given a list of files that will be added with your check in, as well as any modified files. You can double-click on any of the files in this list to see the difference between them and make any changes.
  • If the list of files that will be added on a commit includes files built as part of the project, binaries or obj files you don't actually want cluttering up your repository, you can simply right-click these files in the list and choose to ignore entire directories or specific file extensions. Those files and folders will not be uploaded to the repository, and will not show up in subsequent commits.
  • TortoiseSVN has a very nice manual available in the docs section of their website. The manual not only covers Tortoise itself, but also has some good info about SVN and best practices for setting up your repositories and how to use it on a daily basis.

Hopefully, this has been helpful to anyone out there looking for a quick and easy explanation of how to set up source control for a personal project. It seems to be working out pretty nicely for our team, and I wish you good luck in your own endeavors!

13Jan/100

You’re Thinking It Wrong

Well, maybe not wrong, but too much. That was my problem, overthinking. I'm sure it's not a novel lesson to be learned, but it's worth repeating that sometimes, keeping things simple is the only way to go, and trying to make things more complex than they need to be is not only a waste of time, but ultimately doesn't give you the result you want.

Unfortunately, programmers tend to be wired to overthink things, or at least to try to model reality where reality has no business.

I'm working on a game in my spare time, and it's a game that involves physics. Or rather, it involves the perception of physics-like interactions. We're talking bouncing, and more specifically: levers. When one object lands on one end of a first-class lever (aka. a see-saw), the object on the other end should experience forces proportional to the normal component of the force of the landing object, and the distance of both objects from the fulcrum of the lever.

In other words, if an object lands near the end of the lever, it should launch the object on the other end of the lever further than if it landed near the fulcrum.

So I got it into my head that I would be calculating the torque of the landing object, or maybe taking the forces on one side and the other, but force (and therefore, acceleration) is useless unless you know how long it acted for (acceleration is change in velocity over time, after all) so how long should I apply the force to the object I'm launching? And what about angular momentum, linear momentum's bastard cousin? Shouldn't momentum be conserved... or something? So does that mean that I need to apply not only an acceleration but also a starting launch velocity based on the angular momentum applied to the lever?

As you might be able to tell, it's been years since I took a physics class, and my understanding of this particular aspect was fuzzy at best even then.

My friend, who is also working on this game, pointed out that all of this was a waste of time, because it likely wouldn't be fun anyway, and what we really needed was a set of rules that was fun to play, not necessarily "physically accurate." I knew he was right, of course, but I wanted to do both, I wanted the simple tweakable system, and the realistic physical simulation, the latter probably more as a challenge to try to figure this stuff out again.

Ultimately, I realized that even if I did get a realistic physics simulation working, both of my objects would have about the same mass, and therefore, either one landing on the lever wouldn't do much at all to the other. It certainly wouldn't result in the kind of wacky catapultation that we were aiming for.

So instead of mucking with the math any longer, I sat down and wrote a reasonable approximation of what I wanted to happen, not what would happen in real life. I simply launched the object on the end of the lever at a constant velocity scaled by each object's distance from the fulcrum. Not only did this give a pretty satisfying feeling to the way objects are launched, but it also immediately exposed a bunch of fun values to tweak. Now we could tweak the constant launch velocity, what weight either object's distance played in the final velocity, as well as the simple fact that there was now a working function where any sort of formula could be devised if we found that this one didn't work for us.

In other words, when I stopped overthinking it, I was able to quickly and easily cook up a system that was a lot more customizable than boring old reality, and allowed us to focus on fun gameplay, rather than my pedantic obsession with simulating reality.

A simple but valuable lesson then: don't spend even a minute worrying about how to implement a gameplay system if that system's goal is not fun gameplay. If you're thinking about how to implement a gameplay system, think about how to implement it so that it feels fun, and is easy to tweak for yourself and other designers.