Tag Archives: orientation

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.