TIGSource Forums

Developer => Technical => Topic started by: Jason Bakker on October 16, 2009, 04:12:12 PM



Title: Cross-Platform Development
Post by: Jason Bakker on October 16, 2009, 04:12:12 PM
Inspired by some of the responses in the Changing Language (http://forums.tigsource.com/index.php?topic=8547.0) thread, I thought I'd start a discussion about cross-platform development so that we can discuss and share information about the process of developing a game for multiple platforms.

Developing a game for multiple platforms is a process that, while definitely more time consuming that just doing single platform, can be sped up heaps by smart programming practices such as:

Code:
sndMusic *myMusic = new sndMusic("MusicFile.ogg");
myMusic->Play();
...
myMusic->Stop(); // optional -- deleting a sndMusic object will stop it, too.
delete myMusic;

And then inside my sndMusic class, I do whatever has to be done to play music on that platform.  It means that when porting a game to a new platform, I only have to port the sndMusic class;  I don't have to change a single line of code inside the game itself -- it can still use my abstraction layer without any changes.

Basically, any time when you'd consider using a native API inside your game code, don't do it -- instead, just create a function in your abstraction layer which will call into the native API for you.  That's all you have to do, and it makes cross-platform coding much, much easier.

There's a few classes that will need platform specific versions of them:
- Sound Class
- Input Manager
- File Loader
- Renderer and associating parts, such as Texture (and if it's a 3D game, Model)
- Save Manager
- Other hardware implementation (Rumble, etc)

And often the difficulty is just in creating a platform independent model of a system that you can map to multiple platforms.

One that is particularly difficult to find a good model for these days is the InputManager. If your game just wants to know whether an action has been done, if that action can be a button press on one system/configuration, an analogue trigger on another system (360, PS3) and a Gesture on a third (Wii, DS or iPhone), how do you account for that?

One other thing to mention - another advantage of setting up your own system in this way is that, as long as a cross-platform engine (such as Unity) is set up properly, you should be able to put that engine into your platform-specific layer, and then you only have to write one version that uses that cross-platform engine. (Of course, it's still good to have the ability to change your use of the cross-platform engine slightly in the implementation for each platform, as there would no doubt be some things that you need to change.)

Of course, there are other pitfalls of cross-platform development, one that I know of being the Wii/DS still just using C, and requiring your C++ code to be wrapped somehow... what other pitfalls have you guys come across?


Title: Re: Cross-Platform Development
Post by: BlueSweatshirt on October 16, 2009, 04:32:38 PM
OpenGL basically works with anything and everything, last time I checked. A few older console aside, more than likely. So I don't think you'd need to worry too much. Same with OpenAL, I would imagine.

Input managing usually comes with interfacing with an OS. Which you kind of forgot to mention. Unless you meant OS input when you said input management.  :P

[EDIT]
After reading the input manager section over, it's not too hard.
Instead of checking "is key pressed, if yes....", check for: "is action set to true? if yes...".
And if a key is pressed, it would set the variable for such and such action to true. You could have multiple checks for different control sets to work with the same action variables. You could even do a variable like "ButtonPress_1", not specifically tied to any form of input.

Abstraction layers, for the win.


Title: Re: Cross-Platform Development
Post by: Average Software on October 17, 2009, 09:07:47 AM
One that is particularly difficult to find a good model for these days is the InputManager. If your game just wants to know whether an action has been done, if that action can be a button press on one system/configuration, an analogue trigger on another system (360, PS3) and a Gesture on a third (Wii, DS or iPhone), how do you account for that?

Input is easier than you think.  My platform independent backend has an input event queue, and the platform frontends just feed events into this queue as they happen.

I used to organize this stuff so that the backend contained most of the high-level logic and called the front end to get the data it needed.  Now I do it the other way, the front-end drives the system and tells the backend what to do and when to do it.  This has resulted in a much cleaner and simpler design for me.


Title: Re: Cross-Platform Development
Post by: increpare on October 17, 2009, 09:37:27 AM
i'm generally ok with input; usually it's file i/o that bites me in the ass (different file structures and conventions on where to save what on different systems; boost filesystem library helps, but I've had compatibility troubles with it in the past on windows).


Title: Re: Cross-Platform Development
Post by: Aquin on October 17, 2009, 09:52:42 AM
Yeah, the libraries I use now are awesome because everything is cross-platform.

At this point I can literally take my source code, unchanged, and compile it pretty much anywhere.  I doubt it's useful, but I do enjoy it from a theoretical point of view.  I don't just want code that makes sense.  I want code that makes sense *everywhere*.


Title: Re: Cross-Platform Development
Post by: increpare on October 17, 2009, 10:24:01 AM
Yeah, the libraries I use now are awesome because everything is cross-platform.
I am very sceptical of any such claims!

Say you want to make a game with a level editor that will let people store and share levels; can you do that without writing platform-specific code?



Title: Re: Cross-Platform Development
Post by: Average Software on October 17, 2009, 10:24:29 AM
i'm generally ok with input; usually it's file i/o that bites me in the ass (different file structures and conventions on where to save what on different systems; boost filesystem library helps, but I've had compatibility troubles with it in the past on windows).

This is where you use environment variables and the genenv() function.  HOME on Unixy systems and APPDATA I believe, on Windows systems.  Put a function in the front end called GetSavePath or something that just refers to environment variable to get you the correct location.


Title: Re: Cross-Platform Development
Post by: mcc on October 17, 2009, 10:32:28 AM
So what I find is I can do graphics with ES-compliant OpenGL, input and sound with SDL, compile with MinGW for POSIX compliance, add one or two functions for things like filesystem management and hey, stuff works pretty much anywhere. Most libraries I'd want to use can be layered on top of that base. (See also my sig.)

Problems:

1. Base OpenGL is really very simplistic in terms of what it does with graphics. I'm not sure about which libraries to use if one wants to do graphics programming at a high level rather than OpenGL's ultra-low level, the ones I've heard of (OGRE?) sound questionable or like timesinks (I know some people who decided, okay, we're going to make a game, they spent a full year learning OGRE and never produced so much as a playable demo). All the game plans I have involve very simplistic graphics, so this isn't a problem for me, but if I ever want to attempt a different graphical style I'm not sure where to start.

2. The iPhone kinda throws a wrench in things. Graphics and sound code are easy enough to share with an iPhone app, and all the POSIX stuff works out of the box... but: The problem here is it's easy enough to abstract away things like controls or interfaces so long as the medium is more or less similar. Controls can be handled pretty much the same whether the button being pressed is on a controller or a keyboard, I could even imagine porting a game to a Wii or DS and just routing pointer or stylus stuff into the same function that on the PC would handle a mouse click. But the iPhone is just so totally different as a device from anything else it's hard to imagine where to start with cross-platform...ness. On controls you have no buttons at all, you have abilities you don't have with a mouse because of the multi-touch, you don't have abilities you would have with a mouse because the touchscreen is so imprecise and you can't use it without covering up whatever you're interacting with... you need to come up with an entirely different way of approaching controls, and it's probably the case that once you've done that your game design or mechanics will need adjusting. For GUIs, there's this entire set of interface primitives that don't exist on other platforms, and if you don't use those interface primitives your app will seem "wrong" both because of what people expect on the iPhone and because of the small screen. I think what I eventually decided is I can use one codebase, with abstractions as appropriate, for "all platforms except iPhone" but then on the iPhone I just need to maintain a parallel codebase so that I can make fundamental changes to the game if necessary.


Title: Re: Cross-Platform Development
Post by: mcc on October 17, 2009, 10:37:08 AM
Say you want to make a game with a level editor that will let people store and share levels; can you do that without writing platform-specific code?
I don't see why not? What I did was just cheap out and say "all level packs live in the same directory as the program executable". The editor creates them there, the user dumps them there when they download them. I don't have to think about the larger directory structure. Users don't seem to notice how simplistic this is, I don't think people really expect games to be "good citizens" wrt OS integration.

If you want to allow the user to share levels online from within the application, there's always stuff like libcurl.


Title: Re: Cross-Platform Development
Post by: increpare on October 17, 2009, 10:41:21 AM
I don't see why not? What I did was just cheap out and say "all level packs live in the same directory as the program executable".
Because that's strongly recommended against on osx (where an app might not have permissions to write to the directory it's in).  OSX recommends that you save all program files to a particular directory that's a bit out-of-the way and so isn't something you'd expect them to navigate to, so you'd maybe be best off setting up a new folder in the user's documents folder and maybe setting up file-associations so they can double-click on the files to open them if you want them to share the things. (this would include registering icons/&c.)  OSX also tends to enforce that there's only one instance of an application active at any time, so command-line stuff wouldn't suffice.  And what if they try to drag a level file onto the application window?  If you store the levels in the binary directory then they'll have to navigate into the package to find them, but if you store them in the application package directory you risk shitting up their applications folder if they have the application in it directly (as do most programs do) rather than in its own folder (which is unidiomatic and against osx guidelines pretty much).


Title: Re: Cross-Platform Development
Post by: mcc on October 17, 2009, 12:04:08 PM
I don't see why not? What I did was just cheap out and say "all level packs live in the same directory as the program executable".
Because that's strongly recommended against on osx (where an app might not have permissions to write to the directory it's in).  OSX recommends that you save all program files to a particular directory that's a bit out-of-the way and so isn't something you'd expect them to navigate to, so you'd maybe be best off setting up a new folder in the user's documents folder and maybe setting up file-associations so they can double-click on the files to open them if you want them to share the things. (this would include registering icons/&c.)  OSX also tends to enforce that there's only one instance of an application active at any time, so command-line stuff wouldn't suffice.  And what if they try to drag a level file onto the application window?  If you store the levels in the binary directory then they'll have to navigate into the package to find them, but if you store them in the application package directory you risk shitting up their applications folder if they have the application in it directly (as do most programs do) rather than in its own folder (which is unidiomatic and against osx guidelines pretty much).
Hm, so let me think about this for a minute.

So as you point out, my way of doing things will fail on os x under a particular situation: Jumpman.app is installed directly in the /Applications folder; and it is run by a non-Administrator user.

Though I could totally imagine this happening, and it hadn't previously occurred to me, this is not a scenario that worries me very much, I don't think. First off, in order for this to happen the user would have to actually be using OS X's multi-user feature. Second off the program would have to have been installed by someone else-- if the user lacks Administrator privileges sufficient to write to /Applications then they obviously can't install the game there either. Finally the program would have to have been installed "wrong"-- I'd have expected the user to install the program by dragging the whole folder (which would come along with its own permissions) into /Applications, rather than just the app. (This last thing wouldn't help in the case of Jumpman specifically because checking the download package only the file owner has permissions to write to the Jumpman directory, but if I'd thought ahead I could have 777'd the directory between zipping it. Actually the problem's a little worse than that, Jumpman will break completely in a multi-user environment because only the application file owner will be able to write to the save-game file. Um, oops. I think I was expecting users would usually be running the game out of their Downloads directories...)

Anyway my solution here would be to look at this as a distribution problem- I think you could avoid this entire scenario if you just distributed the game in a way that makes it unlikely someone would install the app "wrong". One way to do this would be the sort of "poor man's installer" that many OS X applications use. Many OS X applications are distributed by putting the app to be installed into a .dmg along with an alias to /Applications, and giving the .dmg's Finder window a background image that looks like a big arrow-- something like this:

(http://www.publicspace.net/images/abfl2_disk_image.jpg)
If you do this, you could have the "drag this" file just be the entire application directory. You could then have the application directory contain a subdirectory something like "user files" or "level packs", which you have already set to have the appropriate permissions. (You could also just use a real, .pkg based installer, but that's annoying and it might screw over people who again don't have write access to /Applications).

Failing this, the only really "right" way to solve this would be to set the "levels and such are saved here" directory to be a directory which on windows/linux is the application directory, and on os x is somewhere under NSHomeDirectory(). This would have the disadvantage that the users would have no idea where their files are saved, but you could maybe get around this if your level upload/download mechanism were built into the app-- and if the users never see the files, there would be the additional advantage that users would not feel tempted to expect those files to behave like the files of a normal application (such that you can drag them to the dock, etc). This still seems like overkill to me though, storing files in /Applications may not be what Apple's standards recommend but again I think people expect games to violate OS standards in certain ways.

---

One last thing. Let's compare how an existing game handles this exact problem we're talking about: Braid. In Braid, the way that you run a level pack is that you open up the application resources directory, go a couple levels deep, create a directory called "universes", and then drag the level pack in. Then, you have to launch the program with a --universe command line argument; if you mistype this argument, the screen will flash and the program will silently quit. On the mac, this all means that you actually have to open up the .app package to install the universe, and in order to specify the command line argument you have to actually type it in in a mystery box in the little settings/launcher window that runs before the game itself. I bring this up to observe that using the level editor in Braid is an incredible pain in the ass. But: People do it anyway! There is a healthy third-party levels/mods community for Braid. The lesson to be learned here is that if someone likes a game so much they're using the level editor, they probably like it enough that they're willing to overlook a certain amount of bullshit. (In the case of Braid the mods community actually created their own third-party installer/uninstaller/launcher program for mods to get around the games' issues, and most of the mods online are laid out to be compatible with this installer program...)


Title: Re: Cross-Platform Development
Post by: increpare on October 17, 2009, 12:49:30 PM
The lesson to be learned here is that if someone likes a game so much they're using the level editor, they probably like it enough that they're willing to overlook a certain amount of bullshit.
But the less bullshit the more people who will use it.  Say he had some on-line database that people could browse in-game and easily upload/download stuff from, that might be the best possible situation for braid.  You can say that some/many people will learn to cope with certain strange program behaviours, but that doesn't make them optimal, and this sort of behaviour is what cross-platform libraries should I think in principle aim to tackle (though maybe as a lower priority to other tasks).

Anyway, these heaps and heaps of considerations are what make cross-platformness really very much an endless process.  Because being cross-platform doesn't just mean that it will run if you click on it, it also does (or should) claim to fit in with the conventions of the various platforms its made for.

[In general, I have to say I have quite a bit of respect for your porting prowess :) ].

[ also, disclaimer: for sdl I tend to toss my app bundle in a directory and keep the other files separate, like rohrer did for the osx port of passage. ]


Title: Re: Cross-Platform Development
Post by: Average Software on October 17, 2009, 12:53:48 PM
So as you point out, my way of doing things will fail on os x under a particular situation: Jumpman.app is installed directly in the /Applications folder; and it is run by a non-Administrator user.

This is a problem you really should consider, because this is the "right" way to run a system.  It's the way I run all my systems (my user account is NOT an administrator) and it annoys the hell out of me when programs think they can write wherever they want.

Granted, most people do this the wrong way, but it really pisses off people like me that do it right.

I believe the correct place to store add-on stuff for your game is ~/Library/Application Support/Your Game Here/

Most commercial games do this right, try running an id Software game and connecting to server that requires a map download, and this is where it puts it.

On Windows I believe the APP_DATA environment variable gets you the right place, I think it's /Documents And Settings/your name/Application Data/Your Game Here

On traditional unix systems, you just make a hidden directory in the user's home: ~/.yourgamehere/


Title: Re: Cross-Platform Development
Post by: Klaim on October 18, 2009, 08:37:07 AM
While thinking about the user directory way of doing things, I asked myself : where to put log files? In the user directory too?


Title: Re: Cross-Platform Development
Post by: Average Software on October 18, 2009, 08:48:57 AM
While thinking about the user directory way of doing things, I asked myself : where to put log files? In the user directory too?

Yes.

The user directory is the only place where you're guaranteed to have write access (if you don't, the user has bigger problems than your game).  Logs, temporary working files, saved games, preferences... all that stuff should go in the user's directory.


Title: Re: Cross-Platform Development
Post by: Klaim on October 18, 2009, 09:35:30 AM
Good to know.
In my game, lot of content will be written.

I separated all "fixed" paths in my game in some constant strings so I just have to add macro-style OS dependant adresses I guess.


So, what about "updates"? I mean, if your game have some kind of auto-updater soft (outside or inside the game), you need to do something special to allow writing in the application installation directory?


Title: Re: Cross-Platform Development
Post by: increpare on October 18, 2009, 09:40:18 AM
So, what about "updates"? I mean, if your game have some kind of auto-updater soft (outside or inside the game), you need to do something special to allow writing in the application installation directory?
Yeah; a lot of osx apps end up prompting for root password.  I'm pretty sure there's some standard auto-updating framework/set of guidelines in existence for osx.  In windows it's a bit of a free-for-all.  In linux, if you're open-source and on a repository it's not really an issue.  But yeah: be prepared to prompt for passwords whether you're on windows, osx, or linux.


Title: Re: Cross-Platform Development
Post by: Klaim on October 18, 2009, 09:50:22 AM
OK but on the code side you don't need to do something special then?

If it's only passwords, just warning the user before the os prompt might be enough I guess.


Title: Re: Cross-Platform Development
Post by: increpare on October 18, 2009, 10:10:21 AM
OK but on the code side you don't need to do something special then?

If it's only passwords, just warning the user before the os prompt might be enough I guess.
I don't really know.  If you're running a game in fullscreen, you might want to go to windowed mode, say, or you might be denied permissions outright if you don't call the correct system function/&c..


Title: Re: Cross-Platform Development
Post by: Klaim on October 18, 2009, 10:22:29 AM
Will have to check that.


By the way, to get back to the topic, I guess build pipeline (build scripts etc.) is a big concern in getting your app cross-platform...

I heard about CMake to replace project files. I use Python for build scripts but I know it's not enough to have a full build pipeline working on several platforms.

Any good suggestions on this side?

(for infos : I work mainly on Windows, trying to make all cross-platform but didn't yet tried to get all working on other platforms)


Title: Re: Cross-Platform Development
Post by: Average Software on October 18, 2009, 12:01:09 PM
Will have to check that.


By the way, to get back to the topic, I guess build pipeline (build scripts etc.) is a big concern in getting your app cross-platform...

I heard about CMake to replace project files. I use Python for build scripts but I know it's not enough to have a full build pipeline working on several platforms.

Any good suggestions on this side?

(for infos : I work mainly on Windows, trying to make all cross-platform but didn't yet tried to get all working on other platforms)

I have a project directory structure that looks something like this:

Code:
drwxr-xr-x 5 ryan users 4096 2009-10-17 11:05 base
drwxr-xr-x 3 ryan users 4096 2009-10-13 10:32 game_objects
drwxr-xr-x 4 ryan users 4096 2009-10-16 17:04 graphics
drwxr-xr-x 4 ryan users 4096 2009-10-17 11:05 linux
drwxr-xr-x 3 ryan users 4096 2009-10-17 11:05 logics
drwxr-xr-x 6 ryan users 4096 2009-10-16 06:36 mac
drwxr-xr-x 4 ryan users 4096 2009-10-16 06:36 windows

The linux, mac, and windows directories contain project files and all the OS specific front-end code.  Everything else is platform independent resources and code.  I got the idea from the Quake 3 source, which does something similar.  Combine this with a source control system, and you're all set.


Title: Re: Cross-Platform Development
Post by: mewse on October 18, 2009, 01:22:58 PM
One that is particularly difficult to find a good model for these days is the InputManager. If your game just wants to know whether an action has been done, if that action can be a button press on one system/configuration, an analogue trigger on another system (360, PS3) and a Gesture on a third (Wii, DS or iPhone), how do you account for that?

It's actually not too difficult;  in my game engine, I map all input sources onto what I call an "Axis".  Each axis can range in value from zero to one for "unpressed" to "pressed".  Analogue input sources (such as joysticks, or the triggers on X360 controllers) use that whole range, while digital buttons just set zero or one to indicate unpressed/pressed.

Since under this system all your inputs from joysticks, keyboards, and mice are basically identical (exception: mouse position is expressed in pixels), you can have a simple configuration process which tells the system which input source to use for each Axis.

If you have anything else (gestures, multitouch, etc), you could pretty easily just write an extra module which would check the platform-specific input data, and fill out one or more axes with the results.  As long as the game code is only reading input via the generic axes presented by the input system, you can basically do anything you want, and still be able to port your game from one system to another without touching the game code.


Title: Re: Cross-Platform Development
Post by: mewse on October 18, 2009, 01:26:08 PM
I'm pretty sure there's some standard auto-updating framework/set of guidelines in existence for osx.

You're thinking of Sparkle (http://sparkle.andymatuschak.org/).  I've never used it myself, but it's extremely popular and seems well-designed.  Also, free.


Title: Re: Cross-Platform Development
Post by: Ivan on October 18, 2009, 06:11:58 PM
I'm using Sparkle in my current project. It's really an amazing framework.


Title: Re: Cross-Platform Development
Post by: mcc on October 18, 2009, 07:45:30 PM
[In general, I have to say I have quite a bit of respect for your porting prowess :) ].
Well thanks much! Although I note this comment comes after you successfully demonstrate my game doesn't currently work in multiuser mode at all on a whole platform :)

In my case cross platform cleanliness is an absolute necessity because I develop exclusively on macs and actually have to go to some difficulty to even test on Windows... so it's either I'm crossplatform, or 90% of people don't play the game. Of course this makes it kind of funny when I actually somehow manage to fail to be mac-platform compliant in some way... when I was developing Jumpman I actually initially made the editor totally dependent on having a three-button mouse, and didn't remember until several months in and a playtesting cycle that most normal mac users aren't using scrollmice like I am.

---

So here's actually a cross platform question I've been wondering about awhile: Does anyone know of a cross platform way to do internationalization / languages? I know both mac and windows have APIs where at any time you can get the users' preferred language, and switch out strings based on that preference (I don't know what Linux has). Are there any cross platform APIs that can let you pack multiple languages into a single program and picks the correct language for you based on local OS settings?