Building a Game for multiple Platforms with SFML
We used SFML for our Gamejam Game Huitzilopochtli and it fully supports Windows, OSX and Linux and has experimental support for iOS and Android.
The only Libraries used were Box2D and SFML. SFML has a couple of dependecies though.
We used CLion as IDE which uses cmake files for the project.
In total it took about two additional days to get it running on all the different platforms (except Android, yet).
Using the cmake UI I did set all the missing library paths manually (which kinda isn’t the point of cmake…) but once I had it all setup I generated a Visual Studio project and made a release build. The SFML dependencies are all in its repository in the “extlibs” folder.
I would have made it an x64 build, but I didn’t set that up correctly for Box2D which is linked statically and thus settled with a x86 build.
Then I copied the games executable, assets folder, SFML DLLs and the openal DLL from the SFML dependencies all together in one folder and it just worked.
Only issue is that I built it with VC++14 which is the latest and most people don’t have the runtime installed. So I packaged the runtime installer with the game.
I don’t have Linux setup on any system, so I installed VirtualBox and setup a virtual machine with the latest version of openSUSE.
I started with installing cmake and g++ and then tried generating make files for SFML and installed dev packages until it stopped complaining about any missing dependencies. Finding the correct names for those packages wasn’t much fun, but I figured them out eventually with the help of google. And unfortunately can’t remember those names anymore…
Compiling and installing Box2D did again just work and so did installing SFML once it was build.
Then cmake could do its magic on Huitzilopochtli and again there were no complications.
The tricky part was putting it all together. I started by putting the executable and the assets in the same folder and added the shared libaries for SFML together with the symlinks to them, since the project was linking against some of those.
I made another clean installation of openSUSE and also one with the latest version of Ubuntu and tested it on both. For openSUSE I was just linking against a much newer version of libjpeg and on Ubuntu openAL was missing. So I added both to the folder and was done.
One texture didn’t load which was due to Linux being case sensitive for file names.
I was developing on OSX so I didn’t expect there to be any issues, turned out I was wrong. The working directory relative to which it was looking for the assets was not the same the executable was in.
To solve this I put everything together into an App-Bundle which has a quite strict structure. It is a folder with a folder inside that is called “Contents” which includes an “Info.plist”, “PkgInfo”, a “MacOS” folder including the executable and in my case the sfml dylibs and symlinks, a “Frameworks” folder containing the frameworks SFML provides in the “extlibs” folder and a “Resources” folder containing the assets.
Since this way I know where the assets are I added some code for OSX release builds generating an absolute path to the assets and appended the assets relative paths to it everywhere they are loaded in the code.
Getting the path looks like this:
CFBundleRef bundle = CFBundleGetMainBundle();
CFURLRef url = CFBundleCopyBundleURL(bundle);
CFStringRef urlString = CFURLCopyPath(url);
const char *file = CFStringGetCStringPtr(urlString, kCFStringEncodingUTF8);
_resourcePath = file + "Contents/Resources/";
Another problem was the executable searching for its dependencies in a wrong place. The solution was to use “install_name_tool” to set the rpath to the executable path:
install_name_tool -add_rpath @executable_path Huitzilopochtli
The resulting app bundle did work (I double checked it on an old Mac Mini on which I had just reinstalled the OS), but refused to open the first time when just double clicking it. You could do a “Right Click -> Open -> Really Open” but that is not much fun. The reason for this was that I hadn’t codesigned it.
So I generated a new OSX developer profile on apples dev center and codesigned all libraries, frameworks, the executable and finally the whole App-Bundle:
codesign --force --verify --verbose --sign "Developer ID Application: Nils Daumann" Huitzilopochtli
The result seems to work without any issues now.
This took me a while to figure out, but is also working very well now.
At first SFML needs to be build for iOS. To do so the “IOS” define has to be set to “TRUE” and I generated an Xcode project which may or may not be needed for this.
ccmake -DIOS=TRUE -G Xcode ..
I like to use ccmake instead of just cmake in case I want to change some settings… I may or may not had to enable OpenGL ES, not sure.
Then I setup a new xcode iOS Objective-C Game project and only kept the “LaunchScreen.storyboard”, “Assets.xcassets” and “Info.plist”.
Then I added all of Huitzilopochtlis header and source files to the new project and a reference to the assets folder (this way it keeps the folder structure when copying the files to the App Bundle). Instead of statically linking Box2D I also just added all its source and header files to the project, which is not great, but was the easiest way to make it work without setting up another Xcode project for it with the correct architecture.
On the build targets “General” Tab I removed the “Main Interface”. (Otherwise it will crash on startup)
I also had to set the header and library search paths to the correct folders for the SFML libs and its dependencies as well as the Box2D include path.
This made it compile, but caused lots of linker errors. So I added the SFML libs and extlibs to the xcode project as well as “Foundation.framework”, “QuartzCore.framework”, “OpenAL.framework”, “OpenGLES.framework”, “UIKit.framework” and “CoreMotion.framework”.
But the libraries coming with SFML were not build for arm64, to fix this I also had to set the “Architectures” to $(ARCHS_STANDARD_32_BIT) in the projects “Build Settings”.
The result compiles, links and runs! But it renders in a low resolution ignoring the “retina screen”. But SFML checks the “Info.plist” and supports the “NSHighResolutionCapable” key. Just set it to “YES”. The last issue with this was that orientation changes messed everything up and just forcing one landscape orientation in the plist didn’t work out. I settled with hacking it into SFML, which was overriding my settings.
I also had the status bar appearing for a short moment during startup of the app. A solution was setting “UIViewControllerBasedStatusBarAppearance” to “NO” in the “Info.plist”.
I added touch controls and it is quite awesome :).
Edit: Apple only accepts 64bit builds for the Appstore, so I recompiled all the dependencies and somehow got it to work at some point…
I did submit it for testflight and they accepted it, so they probably won’t refuse it on the Appstore for anything SFML related and the game might get away with a rating of 12+.
I applied for an Apple TV Dev Kit and first got an email telling me that I won’t get one, but another email two weeks later telling me I could get one from a second batch. So of course I did, but didn’t really got to use it yet and since I am already on a roll with porting this game to every platform I can, I decided to give it a try.
I started out with what I had for iOS but set the SDK and target for the Apple TV. It did complain about the CoreMotion framework not being supported, so I removed it and then it complained about all the used libraries not being compiled for tvOS.
I started out with recompiling SFML which unfortunately uses some unsupported features which are CoreMotion and anything related to device rotation.
I fixed all those issues by putting the poblematic code in blocks excluding it for tvOS build:
Once I could build SFML I tried compiling Huitzilopochtli again and it was still complaining about the dependencies of SFML. It turned out that for some reason libjpeg was not needed, so I just stopped linking against it. Also I recompiled all the other dependencies.
Somehow the FLACiOS project I found includes a couple of main functions which got in a conflict with the one from SFML, so I just removed all of those from its code…
The resulting game just works with the Apple TV remotes touch surface and even the audio is playing flawlessly.
I didn’t do this yet, but will add it here if I do.