Tag Archives: Unity3d

Unity Version Control Using Mercurial

I’ve recently started putting my Unity projects in version control. Even though my Unity work is mostly done solo, version control is still extremely useful for recovering from mistakes. It also gives me confidence to make big changes that require breaking my game for a while in order to improve it.

I chose Mercurial, for a variety of reasons that I won’t go into here. A very good overview of how to get Unity projects working with Mercurial can be found on the blog of Josh Sutphin.

Like Josh I found SourceTree to be the best of the handful of Mac Mercurial clients I tried.

I own a copy of Mercurial: The Definitive Guide, which I use as a reference. You can read it online for free.

Not all the files Unity creates should be stored in version control. Josh’s blog mentions how to filter out the Library and Temp folders from within SourceTree. If you are using MonoDevelop or Visual Studio, and have told Unity to generate those project files, you will probably want those files to be ignored as well.

Rather than filter from inside SourceTree as Josh describes, I simply copied an .hgignore file that someone else had posted online. If you google “Unity3d hgignore” you can find ready-to-use .hgignore files that others have posted. (Here’s one.) Generally these all do the same thing, but I did run into one “gotcha”. I had some scripts in a subfolder called Scripts/Library, and it was getting excluded without me knowing it (because it too was named Library.) Eventually I noticed and renamed the folder. (The .hgignore file I linked to above does not have this problem, as it carefully only filters out the Library folder from the top-most directory.)

This leads me to my most important tip.

Test Your Version Control

It’s all very well adding your project to source control but unless you test it on occasion you can’t be certain that you’ve done it correctly. If you have multiple people working on the project then you will quickly learn when someone has made a mistake; other team members will suddenly not be able to build the project. But if you are working solo you need to occasionally check out a new working directory (SVN), clone the repository (Mercurial) or do whatever is needed to make a fresh copy from scratch. Load it into Unity and run some tests.

Of the three projects I added to Mercurial recently, it turned out that two of them had simple mistakes that caused fresh working copies not to build.

In a professional setting you also want to worry about other dependencies as well. For example, which version of Unity was used, which version of Blender, Photoshop, XCode, etc. At a minimum I’d suggest recording the version of Unity in your commit log messages, or tagging the project, when you upgrade to a new version of Unity. (Before each major Unity upgrade I also archive a copy of the previous version so that I have a way to open old copies of my project in their original environment.)

Simple precautions like these are enough for a hobbyist maybe, but if you spend thousands (or hundreds of thousands) of dollars developing a game, you want to be able to build or restore the entire development environment from scratch in the future. (One way would be to archive a virtual machine– a snapshop of the OS, tools, and source code used to build the shipping version of the game.) Disaster recovery is one reason, emergency patches are another, but a happier scenario is wanting to port a game years later to a new platform. There are plenty of stories out there about games whose source code was lost forever. (Though occasionally someone gets lucky, as when Jordan Mechner recently rescued the long-lost source code for the original Prince of Persia.)

This doesn’t just apply to source code. Game textures are often reduced in size and quality for speed/space considerations, but hi-def versions can be generated as long as the original art assets are kept safe. For example, apparently the original art assets for Baldur’s Gate were not kept safe so plans for an HD version had to be shelved.)

Okay, I’ve digressed quite a bit from my original topic (reminder: it was “using Mercurial with Unity”) but I hope I’ve made my point: test your backups and version control repositories, and give some thought to what other tools and assets you want to save, and how.

Why I’m Removing OpenFeint From My Unity Game

I have decided to remove OpenFeint from the next release of Pawns! for iOS.

This is not something I do lightly. I have several meaty blog posts about how to integrate OpenFeint into your Unity iOS game (here, here, and here), and I thought it was well worth the effort.

Unfortunately, continuing to use the old OpenFeint 2.7.5 SDK, the one I’m familiar with, is not an option in the long run. As many developers are aware, Apple is phasing out use of the UDID that OpenFeint used to rely on. Eventually Apple will release a version of iOS that removes the UDID entirely, breaking Pawn’s OpenFeint features (and possible the game itself.)

To work around this OpenFeint requires a two-phase migration. First we must upgrade to SDK 2.12.7, which acts as a bridge between earlier UDID-based SDK’s and future ones. This will migrate your OpenFeint users off the UDID, assuming they run your game at least once. Then you must upgrade the SDK again when the UDID is phased out for good.

As usual, OpenFeint’s Unity plugin is lagging their SDK. They seem to be hard at work on fixing the problems– this thread in the OpenFeint developer forums is a good one to watch. But all this has led me to review the benefits I did and didn’t get by adding OpenFeint:

  • I never saw a sales bump from adding OpenFeint. Other developers have reported a similar experience. Your mileage may vary.
  • OpenFeint gave us Achievements across all iOS versions. But most players have moved on to iOS 4 now, which has GameCenter.
  • Unity now has a built-in API for basic GameCenter features. It doesn’t require editing the Xcode project that Unity generates.

Naturally there are some downsides to my decision.

  • Game Center lacks dashboard metrics to let me (the developer) know things like how many players have earned each achievement. OpenFeint has this. However, this isn’t critical and I am looking into alternatives.
  • I will be losing access to some OpenFeint features I’m not currently taking advantage of, such as in-game forums and challenges (but apparently many of these aren’t yet supported by the beta Unity plugin anyway.)
  • OpenFeint of course supports more platforms than Game Center.
  • OpenFeint gives players ways to share their Pawns achievements to social media, and Game Center doesn’t.

My decision comes down to the fact that it’s easier for me to rip OpenFeint out than to upgrade to their new SDK. I may revisit this decision in the future, after the UDID issue is settled, and/or if I write a new game with different requirements than Pawns.

OpenFeint and Unity 3.3, iOS SDK 4.2

Developers seem to be having quite a few problems trying to integrate the latest versions of OpenFeint (2.8, 2.9) with their Unity 3 iOS games. See the following for some discussions of the problems:

Unity Forum: OpenFeint-iOS-2.9-problems
Unity Forum: my-iPhone-application-is-getting-crash
Answers.Unity3d: crash-at-first-launch-with-openfeint.html

To save time as I try to put out a bug-fix for Pawns, I decided to stick with OpenFeint 2.7.5.

However, I ran into some of the problems people had with later versions of OpenFeint. Specifically, the app was crashing with one of the following errors when I closed the OpenFeint dashboard to return to the game:
mi_cmd_stack_list_frames: Not enough frames in stack.
or:
[CAMediaTimingFunctionBuiltin deactivate]: unrecognized selector sent to instance

So apparently the upgrade to Unity 3.3 and/or iOS SDK 4.2 is where this problem started, not because of changes to OpenFeint. The solution, as reported by developers using later versions of OpenFeint, was to comment out calls to UnitySetAudioSessionActive in the dashboardWillAppear, dashboardDidDisappear methods in AppController+OpenFeint.mm:

// OpenFeintDelegate //
- (void)dashboardWillAppear
{
	unityPaused = YES;
	//UnitySetAudioSessionActive(false);
	UnityPause(true);
}

- (void)dashboardDidDisappear
{
	unityPaused = NO;
	//UnitySetAudioSessionActive(true); 
	UnityPause(false);
}

Another symptom I noticed was that when my game was exited under iOS 4 and then brought back to the foreground, the game would appear but then immediately quit (though iOS still listed it as running for some reason.) Bringing it forward a second time would basically run it over from scratch. I concluded that it was crashing on resume, and the culprit was the same call to UnitySetAudioSessionActive, this time in two other delegates. Commenting those out fixed the issue:

- (void) applicationDidBecomeActive:(UIApplication*)application
{
	printf_console("-> applicationDidBecomeActive()\n");
	
    if (gDidResignActive == true)
    {
	    //UnitySetAudioSessionActive(true);
	    UnityPause(false);
    }
	
    gDidResignActive = false;
	
	[OpenFeint applicationDidBecomeActive];
}

- (void) applicationWillResignActive:(UIApplication*)application
{
	[OpenFeint applicationWillResignActive];
	
	printf_console("-> applicationDidResignActive()\n");
	// UnitySetAudioSessionActive(false);
	UnityPause(true);
    gDidResignActive = true;
}

The fact that this problem apparently persists in OpenFeint 2.8 and 2.9 isn’t good. I get the distinct impression that OpenFeint’s Unity wrapper is not very well supported.

Fixing Unity and OpenFeint iPad Rotation Issues

Unlike iPhone games, Apple requires iPad games to support orientations symmetrically. For example, if a game works in one landscape orientation, it should also work when rotated 180 degrees. And this should be true whether the iPad is rotated before the game is run, or while it is played.

There are well-known Unity scripts to address the two major rotation issues most iPad developers run into. I’ll review those solutions first, then describe how to fix new problems introduced with OpenFeint.

Basic iPad Rotation Behavior

There are two behaviors that Unity games should implement for the iPad:
• Change the game’s orientation when a new (supported) orientation occurs
• Turn off the “rotating black square” seen as iOS rotates its menu bar (the one that is normally hidden behind your Unity game.)

I take no credit for the following solution, although I combined them into one script for my own convenience:

public class iPadRotationFixer : MonoBehaviour 
{
    void Start()
    {
        // Turn off the visible iOS menu rotation
        iPhoneKeyboard.autorotateToPortrait = false;
        iPhoneKeyboard.autorotateToPortraitUpsideDown = false;
        iPhoneKeyboard.autorotateToLandscapeLeft = false;
        iPhoneKeyboard.autorotateToLandscapeRight = false;
    }
	
    void FixedUpdate () 
    {
        // In this example, only the two landscape modes are supported
        if ((Input.deviceOrientation == DeviceOrientation.LandscapeLeft) 
                && (iPhoneSettings.screenOrientation != iPhoneScreenOrientation.LandscapeLeft))
        { 	
            iPhoneSettings.screenOrientation = iPhoneScreenOrientation.LandscapeLeft;
        }
	   
        if ((Input.deviceOrientation == DeviceOrientation.LandscapeRight) 
                && (iPhoneSettings.screenOrientation != iPhoneScreenOrientation.LandscapeRight))
        { 
            iPhoneSettings.screenOrientation = iPhoneScreenOrientation.LandscapeRight;
        }
    }
}

Just put this script on an empty GameObject in every scene of your game. (I usually name the object something like “ziOSRotationFixer” so that it sorts to the bottom of the Hierarchy view.) The Start method is only needed in the initial scene, but does no harm to run it more often.

Startup Logo

In your iOS project settings you can also set the Default Orientation, but I don’t think it matters for iPad games. Unity for iPhone 1.7 and earlier had a problem where the Unity splash screen would only show in one orientation on the iPad- you can still find old discussions about how to fix that, but as of Unity 3.0 the splash screen orients correctly on startup.

OpenFeint and iOS 4.2

The above solution has worked with only minor changes since the iPad first came out. So you can imagine my dismay when a tester found rotation problems after I added OpenFeint to Pawns. The tester found that when he double-clicked the Home button during a game, the multitasking bar would sometimes be upside-down. I found the game’s OpenFeint dashboard had the same problem.

Both problems stemmed from my misuse of OpenFeint. Just as Unity needs to be told to rotate the screen orientation, OpenFeint also needs to be told. This just requires adding a couple lines to the FixedUpdate method above, which I’ve marked as new.

    void FixedUpdate () 
    {
        if ((Input.deviceOrientation == DeviceOrientation.LandscapeLeft) 
            && (iPhoneSettings.screenOrientation != iPhoneScreenOrientation.LandscapeLeft))
        { 	
            iPhoneSettings.screenOrientation = iPhoneScreenOrientation.LandscapeLeft;
            OpenFeint.SetDashboardOrientation(DeviceOrientation.LandscapeLeft); // ** NEW **
        }
	   
        if ((Input.deviceOrientation == DeviceOrientation.LandscapeRight) 
            && (iPhoneSettings.screenOrientation != iPhoneScreenOrientation.LandscapeRight))
        { 
            iPhoneSettings.screenOrientation = iPhoneScreenOrientation.LandscapeRight;
            OpenFeint.SetDashboardOrientation(DeviceOrientation.LandscapeRight);   // ** NEW **
        }

        // The above is for Landscape. Don't forget to add Portrait cases if you need them
    }

(Source: http://forum.unity3d.com/threads/50822-OpenFeint-iPad-screen-orientation-on-startup)

This solution works great when the orientation changes as the game is running.

However, the initial OpenFeint dialog can still show upside-down! This problem was discussed in the above thread and in other places, but there doesn’t seem to be widespread understanding of the cause or how to fix it. So I looked into it myself and came up with the following.

The problem is simply that, when you first set up the OpenFeint plugin for Unity, you have to specify the startup orientation. OpenFeint relies on this for the initial orientation.

(Why is the initial orientation fixed and not dynamic? I think it’s mainly because it was originally developed for the iPhone. Also note that the developer can trash OpenFeint’s Portrait or Landscape resources if the game doesn’t need them to save space. So OpenFeint can’t just orient itself dynamically to any direction it pleases. It needs to be told what orientations to use.)

Happily, we can make it check the device’s orientation by adding a few lines to the OpenFeint initialization code in the Xcode project. This is going to work like the FixedUpdate method: we’ll explicitly code for the orientations we need to support.

Here is the old code that we’ll change. It takes the Initial Dashboard Orientation setting and puts it right into the dictionary. (Note: this is the same chunk of code that gets edited when you want to enable Game Center.) Currently the code is in the file classes/AppController+OpenFeint.mm.

    NSDictionary* settings = [NSDictionary dictionaryWithObjectsAndKeys:
         [NSNumber numberWithInt:UOF_INITIAL_DASHBOARD_ORIENTATION], OpenFeintSettingDashboardOrientation,

The replacement code checks the device’s orientation dynamically. Again, I am only supporting left and right landscape modes for my game:

    id orientation = [NSNumber numberWithInt:UIDeviceOrientationLandscapeLeft];
    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight)
    {
        orientation = [NSNumber numberWithInt:UIDeviceOrientationLandscapeRight];
    }
    NSDictionary* settings = [NSDictionary dictionaryWithObjectsAndKeys:
                orientation, OpenFeintSettingDashboardOrientation,

Now OpenFeint’s initial orientation is correct, and so is the iOS multitasking bar.

Note that this code may get overwritten if I install a new version of OpenFeint’s API into my project. That’s the downside of going in and tweaking OpenFeint’s Unity plugin or their code. Like my last tweak (adding support for percent-complete achievements) it’s possible OpenFeint will fix it themselves in a future version. While they are at it, maybe they’ll add the Game Center switch to the Unity plugin as well. Then there would be no need to edit this code at all.

OpenFeint, Game Center Integration Tips for iOS

I have been adding OpenFeint Achievements (with Game Center integration) to my game, Pawns! for iOS. Here is a collection of time-saving tips that I wish I’d had to start with, particularly the Troubleshooting section. I include links to documents and forum posts that gave me useful answers.

Some of this information is specific to games made with Unity, but most isn’t. Some details may change when new versions of the OpenFeint SDK are released.

General Resources

OpenFeint’s developer website is a little disorganized, in my humble opinion. (For example, the developer forums are not listed in the main menu of the Developer Support page; they are mentioned in an announcement further down the page. ) Here are the main links developers need:

OpenFeint Developer Support: http://openfeint.com/ofdeveloper
OpenFeint Developer Forums: http://openfeint.com/developers/forum/
OpenFeint Developer Dashboard: https://api.openfeint.com/dd

Plus there are the usual Unity resources: answers.unity.com, the Unity forums (more active than OpenFeint’s), and this humble blog. 🙂

Setting up OpenFeint in Unity

° The instructions in the UnitySupport folder in the OpenFeint SDK covers most of what you need to know.

° As instructed I added the file openfeint_offline_config.xml to the Unity editor directory “Offline Config File Goes Here“. However, it didn’t copy automatically into my Xcode project so I had to add it manually. OpenFeint’s documentation does not tell you exactly where to put it. Inside the Xcode project folder OpenFeint/resources works, though it’s possible other places work as well. (Source: http://openfeint.com/developers/forum/showthread.php?89-Offline-Mode-Setup)

Achievements and Offline Mode

OpenFeint supports offline Achievements. After the first successful OpenFeint login and connection to the network, the player can view OpenFeint’s Achievements dashboard even if the device is offline. Achievements earned offline will be synchronized with OpenFeint’s servers later. But users who refuse OpenFeint in the first place cannot see the list.

Because of this I decided to implement my own Achievements page, as well as my own notification at the end of each level when they’ve earned one or more Achievements. It was more work than relying on OpenFeint’s dashboard and notifications, but it’s nice to know that even players who don’t use OpenFeint will be able to see their achievements.

Adding Game Center

° OpenFeint’s instructions for adding Game Center can be found in the Developer Support knowledge base. Currently the document is here: http://www.openfeint.com/ofdeveloper/index.php/kb/article/000089 It’s essential reading (it doesn’t cover Unity specifics, though.)

° As of OpenFeint 2.7.5, the Unity Editor plugin does not give access to the setting that turns on Game Center integration. For now you’ll have to go into the Xcode project and add it to the OpenFeint initialization settings manually, exactly as explained in the instructions. (Currently the code to change is in the file classes/AppController+OpenFeint.mm.)

° The instructions state to add your “OFGameCenter.plist” file to your Xcode project, but as usual they don’t suggest where. Put it in the folder OpenFeint/resources.

° Some versions of the instructions call the file “OFGame Center.plist”, but the filename should NOT have a space in it. (Thank you, Pete Royle for posting this tip in the comments!)

° Note that when you define your Game Center achievements with Apple’s dashboard, there’s nothing stopping you from reusing the OpenFeint Achievement ids. This makes your plist mapping even simpler:

    <?xml version=“1.0” encoding=“UTF-8”?>
    <!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
    <plist version=“1.0”>
    <dict>
          <key>Achievements</key>
          <dict>
                <key>677092</key>
                  <string>677092</string>
                <key>718142</key>
                  <string>718142</string>

                <-- etc. -->

          </dict>
    </dict>
    </plist>

° For comparison, here is an achievement image I uploaded to iTunes Connect, followed by the version Game Center presents it to the player. Keep the final appearance in mind when designing your achievement icons (e.g. keep away from the borders.)

Achievement icon as uploaded to iTunes Connect


Achievement as displayed by Game Center

Testing OpenFeint and Game Center

° Before testing your OpenFeint features, go to your OpenFeint developer dashboard and register the OpenFeint user you’ll use for testing. I used my regular OpenFeint user for this, or you could create a new account beforehand using any OpenFeint-enabled app.

If you have beta-testers you’ll unfortunately need the email and password of each of their logins, and your beta testers may not wish to share their passwords with you. So you will either have to create new email accounts and associated OpenFeint users for the testers to use, or ask them to create new test accounts first and send you the particulars.

° Apple recommends you do not use your real Game Center user for testing. To set up a new test account, simply run Game Center on your iOS device, and use it to log your regular account out before you start to test. This tells Game Center to prompt you to login (or create a new user) when it starts up in your game.

° When your app is first run, OpenFeint will let you pick from a list of existing users on the device (if any) or allow you to type a new one. If your test user wasn’t already active on this device you will need to link this new profile to the test user’s account. Do this in OpenFeint’s in-game dashboard: open the user profile and give the test user’s email address and password.

Once that’s done OpenFeint should then attempt to connect to Game Center. Since you logged out from Game Center beforehand it will prompt you to login. This is where you can create a new Game Center user.

° Don’t forget to also test the offline mode. After a successful OpenFeint test, try running the app again with no network connection, and try out the OpenFeint buttons.

Troubleshooting

° If OpenFeint doesn’t mention Game Center at all at startup, double-check that you properly enabled Game Center in OpenFeint’s initialization settings.

° If you get an error that “This game is not recognized by Game Center”, try deleting your app off the device and let Xcode reinstall it from scratch. (Source: http://www.cocos2d-iphone.org/forum/topic/10528)

° When testing offline mode, if you get an error that says that offline mode was not enabled, check that an up-to-date copy of your openfeint_offline_config.xml is in your Xcode project, inside the OpenFeint/resources folder.

° OpenFeint not posting to Facebook and Twitter: this is normal when testing with an app that hasn’t yet been released. Once it is submitted to OpenFeint (to let them know the version with OpenFeint has been submitted to Apple) they’ll turn on the social media links. (Source: http://openfeint.com/developers/forum/showthread.php?273-Can-t-able-to-see-published-event-in-facebook-after-submission-got-succeded&highlight=twitter)

° I had a problem with OpenFeint 2.7.5 notifications never showing when an Achievement was unlocked. I posted a solution for this last month.
http://www.mindthecube.com/blog/2010/11/openfeint-2-7-5-not-notifying-of-achievement
Alternatively, see the section “Achievements and Offline Mode” above for reasons to write your own notifications instead.

* If OpenFeint is working but there is no Achievements dashboard for your game, or some achievements are missing, make sure your game’s bundle version is set high enough. For example, you may have configured your OpenFeint achievements to be visible with version 1.1 or higher. (In Unity, the version is set in the project’s Player settings before rebuilding the XCode project. Non-Unity developers would update directly the Bundle Version in their game’s Info.plist file.)

If the achievements still aren’t visible, then make sure you registered the test user in OpenFeint’s Developer Dashboard. Also double-check that you added the test user’s email and password on the player dashboard on the device.

Conclusion

Adding OpenFeint and Game Center wasn’t difficult, but there was some trial and error, a couple of gotchas, and I had to do a bit of searching for some of the answers. Hopefully these tips will smooth the way for others, and for myself when I start working on my next game.