Open Source Game Engine LÖVE needs a Mac port

LÖVE is an open-source 2D game engine which uses the versatile Lua scripting language to create dynamic gaming experiences. It relies on OpenGL graphics and the SDL interface library to allow for cross-platform implementation and is an all-encompassing gaming environment for the development and enjoyment of 2D games.
Read the rest of this entry »

Nanocrisis

Game Design: Scale down!

My first step in creating the game was to figure out exactly how it would play. I decided on making a 3D-platform game because I had not previously tried making a game of this genre. My intention was to make a game that would at least be fun for me to play, so I added a lot of RPG features, such as the ability to upgrade your character as you moved through the game. The original design was more similar to Secret of Mana, and two-player support was planned. This turned out to be much too lofty of a goal, so the game was ultimately single-player, and not anywhere near as long as originally planned. Thus, the same lesson you hear a lot in the Indie game world persists here—scale down your plan! There’s no way to make a 3D game like the newer Zelda series or Mario64 within this short of a time period, and those are even single-player. Design a story with characters that stand out.

I wrote up an initial design document, and a friend filled in the story. The story was also scaled down a great deal, and what remains in the game are only some elements of the story that caught my eye. I don’t have a whole lot to say about the story, but I feel that making memorable characters in the game was very worthwhile—of course, you always have a main character or several who are memorable, but including a standout villain or a character who shows up frequently adds a lot more fun to a game. To appeal to casual players, keep it simple.

I am not really sure how successful the actual in-game design was, because a lot of people got stuck at the title screen (see uDevGames section below) and there really were not all that many comments about it. I think a lot of people were confused about this style of game, because the game didn’t really tell you what to do, you had to explore and try to find money and items to get further along. Those who got far into the game tended to like it, so there seems to be a certain hump to overcome, at which point you understand what the game is about and how it is to be played. Presumably a lot of people didn’t have time to try and mess around to get over this hump.

Game Engine: Never start from scratch!

Rule number one for actually making this sort of game is that you should never start from scratch, unless you have years to work on it, and an interest in how the guts of game engines work. With this in mind, I next picked out some libraries to start with, in particular the code of Devlib, which is an open-source, minimalist game engine. This was a great idea, as it gave me a notion of how to glue these separate open-source libraries together. Devlib by itself was not sufficient to do what I wanted, so I had to hack it like crazy—I would not recommend using it without modification. For making a 3D-platform game, I would actually recommend you start with a more high-level engine if possible, such as Torque. If you are very serious about making a 3D game, there are of course a lot of other great commercial engines as well, and again I would advise against starting from scratch unless you have lots of time and interest in low-level details.

Devlib incorporates SDL for setting up a drawing context. This is a great choice for the Mac OS X platform, and is becoming a lot more popular and stable. I would recommend it to anyone.

Drawing: DirectX and OpenGL

I chose OpenGL since I wanted to work well with the Mac OS X platform. Any cross-platform developer would want to do the same.

Image Loading: DevIL

The cross-platform image library DevIL worked great for what I wanted, and I recommend it. (Relevant to me was the JPG, PNG, and TGA support.) QuickTime is also popular for loading images, but I was interested in making the game as cross-platform as possible.

Font Drawing: FreeType for TrueType

This library is also fine, and by the way, there are plenty of free TrueType fonts you can find on the web, such at those at Tom7. I would not recommend using Devlib’s built-in font drawing support, which is quite inefficient and has a lot of overhead. Instead, OpenGL FreeType is a much better choice, tailored towards OpenGL rendering.

Physics: ODE

All in all, this library was acceptable for what I wanted to do, but it is somewhat quirky and difficult to get to work exactly the way you want it to. A game-specific physics library might be a better choice, but I haven’t played around too much with it. ODE definitely will get the job done, though, but it may cost you some time.

Scripting Language: Lua

This was the first time I wrote a game with scripting, and I was amazed by how much this helped to speed up game creation. Lua is one of the best choices you can use for a game scripting engine—so much that I have dedicated a section to it below.

Sound: SDL_mixer

FMOD is what Devlib used for sound, but I ended up using SDL_mixer, because I was trying to avoid the cost of licensing FMOD. FMOD itself is supposed to be fairly good if you actually do use it. However, using SDL_mixer turned out to be a poor choice. SDL_mixer is not as good about using audio hardware acceleration, and can sometimes introduce clicks and pops; also, it has limited features. I recommend using OpenAL instead.

Devlib also has several other components that I did not use, such as its mesh loading support, resource loading support, and font support. Devlib’s mesh support is not very flexible, so I wrote my own mesh/geometry code. This is a fairly simple linear-interpolation system; each mesh file is a group of keyframes, and each keyframe has all the vertex positions for a given pose of the model. Then, in animation files, keyframe weights are listed with time deltas. You can see this in the ‘ani’ files of the data folder. I created these models and animation files with my own modeler, OpenTeddy, which I describe a little further in the work flow section.

Resource Management: Caching is a powerful method for resources

Though I used Devlib’s resource support, I wrote my own resource management system. The system is simply a cache. Instead of having separate variables for each data pointer I want to store, I have a table for each type of data (e.g. sounds, images, keyframe data) and ask the system to give me a resource with a given name. The resource is loaded if it is not already in memory, and if not, it is loaded, but if it already is, a pointer to it is returned. To use this effectively, you need to pre-load a certain amount of resources to avoid delays when something new appears. For example, there is a noise for when the player swings a weapon; this sound is loaded when the game starts by requesting it instead of the first time the player actually swings, so there is no delay in case it takes a while to load the file.

Another consideration you might be worried about is taking up too much memory from loading all these data. Not to worry! In modern operating systems (Mac OS X, Windows NT or higher) when your program takes up too much memory, the operating system starts using the disk to store your excess memory that hasn’t been used in a while (this is called ‘virtual memory’) and it brings the memory back into your program when it is accessed. This is all done transparently, behind your back. So, you can load all you want, and if you load too much you should be fine, as long as you don’t work with a really big set of resources in a small time window. For those that use C++, here is a snippet of code from the system. PRall_lookup is a templated hash table, where you choose the type of the pointer to return. It also has a method find_or_load(), which returns a pointer to the loaded version of a data file you request. When g_all_music below is destroyed, its destructor from PRall_lookup will free all the loaded music files.

struct PRmusic : public PRcopystr {
public:
Mix_Music *music;
PRmusic(const char* i_filename) : PRcopystr(i_filename){
g_soundLoad();
music = Mix_LoadMUS(i_filename);
}
~PRmusic(){
Mix_FreeMusic(music);
}
};
PRall_lookup&ltPRmusic> g_all_music;
PRmusic* p = g_all_music.find_or_load("title.ogg");
PlayMusic(p);

Programming with Lua: Scripting helps speed up your development.

I should note that half of my code is Lua (in the data folder,

game.lua

,

title.lua

) and the other half is C++. Because I added scripting, I was able to add a lot of new behavior and features very quickly. By the way, make sure you are getting full output from your scripting interface. You need to know from which line and which file you are having a problem, and a full stack trace if possible.

Function Interface

What I found to be the easiest (though possibly not the most efficient) way to do the interface is have my Lua procedures each take in one argument, which is a table. This way I can quickly change my interface and allow default values. For example, I might have:

render_billboard( [x=50, y=20, texture="mytex.png"] )

Then if I decide to allow a color, I can make the default color white if it is unspecified and the user could also specify it:

render_billboard( [x=50, y=20, texture="mytex.png", color=[1.0,0.0,0.0] )

There is still some annoying manual labor you have to do to implement this. For each argument you obviously have to try to look up the string in the table, and if it’s there, use it instead of the default argument.

I would not use Luabind makes your compilation time incredibly slow, and if you start increasing the maximum number of arguments in your interface, it starts running into too-deep template errors. I tried it out and wasted a lot of time on it.

Vectors

I found it useful (though it’s somewhat slow) to represent vectors with tables. You can see in my previous code example how this works. The way to do this easily in Lua is to push a table, then push the number 1, push the first value, push the number 2, push the second value, then the third value. I use vectors of size 2 through 4. All my vector math is implemented in Lua. If this is too slow you can of course push it up into the engine layer, but again you still have this sort of overhead by converting to a table. However, I found it incredibly easy and flexible to do it in this way.

Handles

The way my system works is that when you ask for a new object, you get an integer handle to the object. You can then refer to it by the handle:

local ob = create_object( [model="test.model", loc=[0,1,0]) … set_object( [index=ob, loc = [1,1,1] )

In my system, objects are the only things with handles. You could do a lower-level version of things where textures have handles, models have handles, etc. I find, though, that you may just want to specify what you want each time and simply use a cache. So for example instead of passing a texture to a handle, then using that handle, you just mention the name of the texture every time, and the system is smart enough to internally cache that texture so that it doesn’t have to load it each time the draw texture is called. This is described in the above resource management section.

There are of course a lot of programs that use Lua, and I have actually not looked at any other ones (which is probably to my disadvantage, but my engine is working fine so far, except being somewhat slow on older systems.) I am aware of one recent game, Gia (from rpgdx.net) that uses Lua. I haven’t looked at how he does things, though.

Workflow: Start simple as possible, and slowly grow a full game

The first thing I did was try to make a simple program using Devlib. Once I got that to work, I made more and more complicated programs, that first loaded my meshes, animated them, added physics support, and then scripted them. This sort of continual evolution is a very good way to develop a program, because you know that what you currently have is working fine, so when you add something new, you know that’s probably the culprit. I used a memory checking system (called MMGR.h) and turned out checking all the time, so whenever a memory bug came up, I could fix it right away. Once I got scripting working, I made a simple demo where the character could walk around on another mesh. From here I tried to make sure I had all the features I wanted, by adding more and more interactions with other objects. At this point I started making the actual game levels. Use a professional tool chain.

Making character and monster models was done in OpenTeddy, which I developed myself earlier in the year. The reason was surprisingly not that I wanted more power from a modeler, but that I actually, despite being a computer graphics student, do not know how to use professional modeling packages, such as Maya, as I never learned them. I would recommend against making your own modeler. I had tons of trouble with my modeler, and it was really insufficient for making level (room) models. Instead, you should learn how to use Maya, for example, and you could write some plug-ins for it in order to do things specific to your game. This is certainly the best approach, but rather difficult if you don’t know too much about it. So start learning how to use a professional 3D package as early as possible.

A lot of the level data is in my scripts, which is also a fairly bad idea—it meant that I had to type in the location of exits and entrances, which was a huge nuisance. It would have made a lot more sense to store this data inside the level meshes, or make a special level format just for rooms.

I had a lot of fun making characters and monsters, however, which is a big part of what motivated me to keep going. This was the only advantage of my own tool, because OpenTeddy is specialized in making organic shapes. As an aside, OpenTeddy is based on the work of Takeo Igarashi. His team created an easy-to-use 3D modeling tool based on creating mesh blobs with 2D strokes. I extended the concept to include boolean operations, which made it a lot more usable, and allowed me to make (debatably) much more professional-looking models. I hear there is a Teddy plug-in in several professional 3D packages, and I would recommend using such a tool to save you time.

Music for the game was created with FruityLoops. I had a lot of fun with this, and would recommend it to anyone. It is, however, PC-only. I felt that the music added a lot of mood to the game, but from the uDevGames results, people either didn’t like the music that much, or didn’t like the sounds that much. It’s difficult to tell, because I didn’t receive many comments about it.

Audio was created by finding free sounds, and then modifying them with Audacity. This is fairly straightforward, so I won’t say much about it, but you should remember that OGG is a good sound format to use, though you will need to get the correct libraries for this.

uDevGames: Make sure your opening interface is simple and comprehensive

When I received my scores for uDevGames, I was disappointed, because I expected to do somewhat better. However, I did something really stupid. At the title screen, I opted for somewhat of a consistent keyboard interface, but this was a very bad idea, because people didn’t know to press a key since in most computer games you would click the mouse instead. I did not implement mouse support, and I really didn’t want to. I should have though, because it would probably have given me a good deal more votes. So the tip here is you should definitely make your out-of-game interface both mouse and keyboard—a standard interface is best. Instructions all along the way (even CLICK THE MOUSE TO CONTINUE at the beginning might help) are probably a great idea; in-game instructions are the best, and I think it was helpful for me to include them. If you’ve played the fairly recent “Prince of Persia: Sands of Time” game, it has fairly sufficient in-game instructions, which gives you an idea about that. Simpler games appeal to the public.

About gameplay, again I received very few comments, and what comments I did receive I fixed gameplay for, so it’s very difficult for me to gauge what people actually thought about it. My personal opinion is that I received a mediocre score because the game was too complicated—remember that for uDevGames you are being judged by the public, and a game that will be most successful with the most number of people is one with a simple interface, so nobody has trouble playing it. I should also note that historically, RPGs have not placed all that highly in uDevGames for what I feel is this same reason of complexity. I also encountered some game crashes despite testing with a reasonable number of people. Because again my game was somewhat complicated, it was almost impossible to anticipate these bugs coming up.

Try your sound on headphones, and on different systems

For audio, one comment I heard is to make sure things aren’t too loud or too soft—there should be an audio adjustment menu and you should test the game with headphones. I did neither of these things. Another problem I came across is that a few people felt the music was somewhat monotonous. However, I was only allotted 10MB of space for the whole game, so each song was only a minute and a half to two and a half minutes. It would have been a better idea to just make one or two pieces of longer music, and leave the other music out to decrease download size. Small downloads can lead to more votes, because non-broadband users probably will download smaller games first in the interest of time. The best-rated graphics are clean and consistent.

Finally, about graphics, I think I was judged somewhat harshly because I had a lot of repeating textures—since I didn’t have the time to make really detailed levels, I went for levels that were just comprehensible but not really detailed. This was probably not such a good idea, because I think it introduced the perception that I was just being sloppy. The fact that I had animated models did not seem to help me all that much, and you can probably get a lot of mileage out of 2D graphics that look good.

* Genre:
* Developer:
* Url:
* Team size: 1
* Released date:
* Project length:
* Development hardware:
* Critical applications:

SDL,OpenGL,DevIL,ODE,Lua

Adventures on Pirate Isle

Another interesting thing to note is that my target audience for Pirate Isle was much younger than those I normally develop for. One goal for Pirate Isle was that it would be fun and appropriate for gamers of all ages, and this resulted in a number of technical and game design considerations. I tried to keep the number of individual controls down to a minimum (the gamer only has four buttons to control Slash fully: left, right, jump, action) and the default configuration is set up so that two children can control Slash at once.

Not only did I choose a different target audience and genre of game to make, I also decided to explore different technologies with which to make the game. The entirety of Adventures on Pirate Isle is defined in a number of XML files which are then interpreted by the executable to display the game, much like how your web browser interpreted the HTML of this document in order to render this web page. The engine I created for Pirate Isle utilizes XML to provide structure and easy parsing of the game objects, but without some kind of scripting language it is nothing more than a file format to store definitions. For the brains behind the brawn, Pirate Isle uses Lua.

Yo ho ho, and a bottle of rum!

pirate_isle_2.jpg

Slash against the octopus

I found Lua to be simple to incorporate, easy to learn, and quite powerful in its own right. I had no experience with scripting languages before writing Pirate Isle, so the first thing I did was research the various languages. As normally happens, this particular topic of discussion had already been flushed out on the iDevGames forum. What excited me about Lua as opposed to the other scripting languages is its small footprint. Incorporating Lua into my project was a snap, and it handled running on Mac OS 9, Mac OS X, and Windows beautifully. Lua is also a simple, easy to read language, perfect for allowing interested parties to modify the game to their liking.

Even though Lua is as cool as it is, it is still an interpreted language. This means it lacks what games need most often, performance. My initial tests with Lua showed that it was too slow and cumbersome to have it handle every aspect of the game (such as storing and rendering the sprites). After some more tweaking and brainstorming, I ended up with what is best compared to a car and its driver. The car in this case is an OpenGL engine written in C—clean, fast, quick to respond and handles all the brunt work of going from here to there. Lua then fulfilled the role of the driver. Lua tells the car where and when to go, but leaves the specifics of how the car travels along the road and bounces against the rocks to the car. This approach improved performance dramatically.

That’s great, but now that Lua has been “demoted” to just being the driver I ran into another problem. How should all these scripts be structured, and what API needed to be developed in order to place the least amount of burden on the scripting language?

Hello XML

Using XML allowed me to define separate sprite objects, each with its own initialization, update, and event Lua scripts for unlimited customization. Once this was in place, I had a quick and easy framework for adding new, unique sprites to the game. This was also extremely useful for quick prototyping of new sprite animations, as well as doing quick fixes since modifications to the script did not require a recompile, and in many instances didn’t even require the game to be reloaded!

Avast ye ZBrushers!

pirate_isle_zbrush.jpg

ZBrush in action

I found out quite quickly that making a platformer is hard. I enjoy switching between genres when choosing games to make, and I must admit that the amount of work it takes to make a decent platformer is far beyond what I originally anticipated. If the sheer number of assets were not daunting enough, the intricacies of level design and the pressure to balance it just right are enormous. When I first developed the idea for Pirate Isle, my thoughts were to use pixel art in order to recapture some of the “retro” gaming experience. An example of this can be seen in the first color version of Slash in the image at the top of this postmortem. However, after about two weeks of some serious sprite creation and animation framing, I realized that at my current rate of graphic creation I would never make the deadline in time. Also, my pixel renditions of Slash didn’t have the “cute and cuddly” feeling that I was going for (as my lovely wife so pragmatically put it the pixel version looks like a “drowned rat”).

It was too late in the contest by this time to redo many of the hand-crafted game items I had already made, and Steve was already working on some hand-drawn enemy sprites, so I was forced to make some tough decisions. I settled on using the hand drawn objects I had already created (for instance, the fruit power ups, the tombstones, etc) and the hand drawn sprites Steve was making, and I would use a rendering package to create the backgrounds. In steps ZBrush!

ZBrush has got to be the finest character creation tool I’ve used yet (beating out such packages as Carrara Studio, for example). My good luck in the 2002 uDevGames Contest nabbed me a copy of ZBrush, and utilizing it for Pirate Isle helped give the game some character. I used ZBrush when creating the “tiki” statues, the jackal statue at the end of each level, and the “big-boss” octopus at the end of the sixth level. Using ZBrush for this purpose was incredibly simple and an enormous time saver. ZBrush allows you to start with a simple geometric object (I used a sphere when creating the octopus and a cylinder when creating the tiki statues) or you can use their unique modeling technique known as ZSpheres (ZSpheres are the 3D modeler’s equivalent of the little 2D mannequin most artists use to get proportions and posture right. I used ZSpheres when creating the jackal statue). Once you have your basic object, you can then mold and sculpt that object in a very intuitive manner, allowing for the creation of eyes, nose, mouth, and other facial characteristics in a matter of minutes.

In the end, the mixed-and-matched nature of Pirate Isles graphics hurt it more than helped. Poor planning in the beginning and my underestimation of the amount of art work required to make a good platformer caused Pirate Isle to suffer more than it should have. The experience was not a waste however, since I had a blast learning how to create “pixel art,” as well as spending more time with ZBrush.

Clear sailing ahead!

pirate_isle_3.jpg

Game Map Screen

Building upon past experience

Although the uDevGames Contests are only three short months long, I always try hard to make sure I code with an eye for the future. In some cases this “future planning” results in some wasted time, but in all too many cases it results in saving even more time. Adventures on Pirate Isle uses the same engine code that I wrote for The Belt last year, and it is even an evolution of the base code I wrote for Imp Fodder in the very first uDevGames Contest. Reusing this code allowed me not to worry about the average stuff such as how to open a window, or take over the fullscreen properly, or develop an architecture for my animation…you get the picture.

Utilizing a Scripting Language

We’ll be revisiting scripting languages in the “What went wrong” stuff below, but using a scripting language had many advantages. It allowed for quick bug changes, provided for much more stable code (when there is a problem with a script it simply displays an error and doesn’t crash the entire program), and it allows for artists and gamers to easily modify the game to their liking. All in all using Lua saved me both time and effort.

Non-tile Based, Polygonal Collision Detection

Although this may be a little noticed feature, Pirate Isle was not based on tile like most traditional platformers. All of the objects in Pirate Isle could be an arbitrary size, and all of them could have an arbitrary polygon as their collision boundary. This allowed for Pirate Isle to develop a non-tiled, more natural look, although the added complexity in the collision detection routines required some last minute fine-tuning for it to work on older computers.

An Enthusiastic Musician

Dori Eggan is the wife of a relatively new friend of mine, Nate. Dori and Nate both came from my home state of Ohio, and Dori happens to have started a career as an educator in music. I approached her to see if she would be interested in experimenting in the world of game music, and I found she was quite enthusiastic about creating some original content for Pirate Isle. This panned out well, considering this was her first foray into the digital music realm and Pirate Isle scored sixth in the Sound and Music category. I sure next year she’ll be bursting with ideas and pent up talent, so watch out!

A Cool Artist

While I did 95% of the artwork for Pirate Isle, all of the creative genius which provided for the enemy sprites came from Steven. For his day job Steve does the cool art for many of Freeverse’s titles, but sometimes drawing monkeys for a living can get repetitive. When Steve let me know he’d be interested in redrawing a few sprites for Pirate Isle I was ecstatic, and would have been a fool to say no to such a talented artist. The various enemies Slash encounters are one of my favorite parts of the game, and thanks to Steve they didn’t disappoint!

Good Vocal Talent

Finding vocal talent for a game is challenging, especially for a freeware title being developed in under three months! So when the time came to create voice-overs for Slash my wife and I both sat down and recorded our voices. Needless to say her voice-overs were an order of magnitude better than mine, and thanks to her Slash has a voice instead of just little text bubbles. Some extra work could have gone into the sound processing of the vocals (to help reduce some of the static and such), but all in all I was pleased with the results.

Anyone want a peanut?

pirate_isle_4.jpg

Battleboard Screen

Interpreted Languages are Slow

Here is where we admit that scripting languages have their faults. First and foremost is performance. Lua is also deficient in that it does not have a C API for separate compilation and later loading of these pre-compiled chunks. Now, before I get a ton of emails saying that luac can input a Lua script and output the compiled version, note that this is not what is needed in this instance. The whole point of XML encapsulated Lua code is that it becomes simple for gamers to modify the game. This means that pre-compilation or running the scripts through a conversion tool is not ideal. What I really needed was a lua_compilestring() and lua_runcompiledstring(), but even after digging into the Lua library code myself I was unable figure out a good way of doing this. In the end, I was able to simulate pre-compilation by having my C code encapsulate all of the scripts in their own unique function. This reduced my script compilations from 60-200 lines of code to a single line of code. This managed to get the game to run well on 400MHz machines.

Lack of Audio Input

When my powerbook died late last year, I was forced to upgrade to a “Windtunnel” G4. This was nice development-wise, but one small speed-bump is that regular old microphones don’t work with this computer. I’m no audiophile, but apparently you need a special kind of microphone that I didn’t have the money for in order to use the audio input jack. I ended up borrowing my mother’s DV camera and recorded sounds and voice that way, but this turned out to be incredibly cumbersome. My disappointment in spending a little over $2,000 for a new computer and not being able to use a regular old microphone was profound.

HID Manager Woes

HID manager is actually a simple API to use. In a few days I developed a nice wrapper for it, had it integrated into my game, and was running Slash around with my little Gravis Gamepad. Unfortunately, it was something as simple as keyboard input that seemed to give HID manager all kinds of trouble. Yes, I understand all keyboards are evil since keyboard rollover is in their hardware, but for some odd reason HID manager itself was missing some key combinations which regular Carbon events were getting fine. My particular example is with the arrow keys. When I was gathering events with Carbon events, using the left, right, and up arrow keys in conjunction with the space bar worked flawlessly. When I switched to HID manager only, this key combination no longer worked. So although keyboard rollover still effects the Carbon events code, there must be some other bug in HID manager which caused that oddity in behavior. In the end I used a hybrid system of Carbon events for keyboard and HID manager for other input, and that seemed to work best.

Limited by the Design

As I mentioned earlier, I underestimated the amount of work that a platformer needs. My original plan for Pirate Isle was to release the uDevGames version with three separate worlds having different scenery and enemies, and each world with 5-7 individual levels. As you can see, I only got one world with six levels completed, and by then there was not enough time left to consider making an entire new world.

Hoist Anchor!

This year for uDevGames I wanted to explore new areas of game development, experiment with different art techniques, and ultimately just have a fun time creating a game that children of all ages could play with their parents. It is doubly satisfying hearing from others that “the sugar glider hero is very cool” or that “Slash is so cute,” because coming up with a good hero character and portraying that character well to the audience is probably the hardest thing to do in any medium, be it movies, literature, or games. Although my willingness to explore new areas resulted in somewhat of a “melting pot” of graphical styles, I had fun doing it and feel that I’ve gained much from the experience.

  • Development hardware: “Wind Tunnel” PowerMac G4

Recent Forum Threads

About iDevGames

Since 1998, iDevGames has been educating, supporting and enhancing the community of game developers that produce video games for the Apple Mac and iPhone platforms. Get the latest game development news by subscribing to our news feed.