Thursday, November 14, 2013

Screen Orientation and moz Prefixes (Game Programming)

I was planning to write a post comparing the game graphics capabilities of CSS, Canvas, and SVG, but I realized it would be smarter to compare all the game issues, so I'll wait until I write about some other programming stuff first. Collision detection is also important, and so are special effects!

So today I'd like to cover the subject of Screen Orientation. This concept is often confused with Device Orientation but the two are different. Screen Orientation is only about portrait and landscape. How does the screen orient itself to the device? Device Orientation is about how does the device orient itself to the world. Sometimes there's overlap, sometimes not.

Screen Orientation isn't something you need to worry about on a laptop or desktop. You usually don't turn your screen sideways (although I once had a monitor that would do that so you could read documents to match paper size orientation). But with a phone, playing games in landscape is very common. And if a game needs a long left-to-right playing field, landscape is good. Similarly, if the playing field needs to be more up and down, portrait is the way to go. Personally, I like portrait-style games; I like the way they feel in my hand.

Firefox OS provides ways to detect, change, and lock orientation. I've written a little app that has three buttons, a line for a message, and picture so you can see the orientation. Here's a screenshot of the app when it starts up:


Before you do anything else, tilt the phone sideways and see what happens. If you rotate the device counter-clockwise, it should look like this:




The image rotates to match. The message at the top should say "landscape-primary". Firefox OS uses the convention that primary is the standard way to view an app. So landscape-primary means that the phone has been normal up and down by going 90 degrees in a counter-clockwise manner. If you rotate the device 90 degrees clockwise (back to the starting position), the screen will look like this:



And surprise! The screen is now in "portrait-primary" orientation. But it doesn't stop there. You can rotate the screen 90 clockwise from the main portrait position and get this:


This is called "landscape-secondary" and might feel odd because most games use the landscape-primary setting if they use landscape at all. But the oddest of all would be last, which is if you rotate the screen 180 degrees from the original portrait position.


It looks the same as portrait-primary, but the phone itself is upside down. While this is fun, the purpose of this in gaming is that you might want to require a particular screen orientation. The buttons in my app will lock the orientation.

If you touch the Portrait button, the screen will be locked in portrait-primary position. Now if you rotate the phone, the screen orientation will be locked to the orientation of the phone. So if you turn the phone upside down, the screen will be upside down also.

Similarly, if you touch the Landscape button, the screen will lock into landscape-primary and will flip sideways even if you are in portrait position.

Finally, the Float button will release the locks and let the screen orientation match however you are holding the phone. Pretty cool, huh. Playing with this is so much fun I should put it in the Firefox OS Marketplace ... not!

The code for this is pretty straight-forward:

<!DOCTYPE HTML>
<html>  
  <head>
  <title>orientation</title>
  <meta charset="UTF-8">
 
  <style>
  
    #myPara
    {
      position:absolute;
      top: 10px;
      left: 50px;
    }
   
    #myButton1
    {
      position:absolute;
      top: 70px;
      left: 50px;
    }

    #myButton2
    {
      position:absolute;
      top: 70px;
      left: 120px;
    }
   
    #myButton3
    {
      position:absolute;
      top: 70px;
      left: 215px;
    } 
   
    #myFox
    {
      position:absolute;
      top: 120px;
      left: 40px;
    }
   
  </style>

    <script type="text/javascript">
       
      // Add load event listener to run first function.
      window.addEventListener("load", runFirst, false);
                  
      // This function runs when the document loads.
      function runFirst() {
        
        myButton1.addEventListener(
          "mousedown", myClick1,false);

        myButton2.addEventListener(
          "mousedown", myClick2,false);

        myButton3.addEventListener(
          "mousedown", myClick3,false);
         
        window.screen.addEventListener(
          "mozorientationchange", screenChange, false);
       
        // Initial message.
        myPara.innerHTML = "Tilt the device.";
      }
             
      function myClick1(evt){    
        window.screen.mozLockOrientation("portrait");
        myPara.textContent = window.screen.mozOrientation;     
      }
     
      function myClick2(evt){    
        window.screen.mozLockOrientation("landscape");
        myPara.textContent = window.screen.mozOrientation;    
      } 

      function myClick3(evt){    
        screen.mozUnlockOrientation();
        myPara.textContent = window.screen.mozOrientation;    
      }  

      function screenChange(){
        myPara.textContent = window.screen.mozOrientation;
      }       
     
    </script>
  </head>
   
  <body> 
    <p id="myPara">Text goes here.</p>

    <button id="myButton1">Portrait</button>
    <button id="myButton2">Landscape</button>
    <button id="myButton3">Float</button>
   
    <img id="myFox" src="fox.png" />

</body>

</html>


This is a straight HTML5 page. It starts out with some simple CSS definitions for the text caption, the three buttons, and the picture of a fiery fox.


The code then has a function that runs when the page loads. This function sets up event listeners for the three buttons and then a fourth event listener that listens for a change in screen orientation. This will be called when you rotate the screen enough to be considered landscape or portrait, depending on where you are. The event is called mozorientationchange.

At one point in history, this was called onmozorientationchange, but is now mozorientationchange. It should probably become orientationchange at some point, but I don't know whether it will or not or when. However, there is an MDN page for orientationchange at https://developer.mozilla.org/en-US/docs/Web/Reference/Events/orientationchange, but it doesn't mention mozorientationchange and doesn't work today.

It would be nice to see a table of mozXXX methods and events, what's in and what's not, but the developers have plenty of more important things to do. You can do something similar to what I did for requestAnimationFrame (see here) but I'm waiting to see if this will change again soon.

Then I have three functions that will be called, one for each button. The first two use the mozLockOrientation method and display the new status. Here's the one for portrait:

     function myClick1(evt){    
        window.screen.mozLockOrientation("portrait");
        myPara.textContent = window.screen.mozOrientation;     
      }


Note that the prefix moz is used for mozLockOrientation and that mozLockOrientation takes the parameter value of portrait, locking the screen into portrait-primary position. The position is displayed by using mozOrientation. Lots of moz around here in the land of moz.

The second button is the same as the first, but locks the screen using secondary. You can read about lockOrientation at  https://developer.mozilla.org/en-US/docs/Web/API/Screen.lockOrientation and it does say This API is currently in draft form. It is only implemented as a prefixed method (mozLockOrientation) in B2G and Firefox for Android. The page has a link to onorientationchange but not orientationchange. It does have a link to unlockOrientation, which is used in the third button.

If you want to unlock the orientation and let the screen follow the way the phone is oriented, use mozUnlockOrientation (and maybe someday unlockOrientation). Read about it here: https://developer.mozilla.org/en-US/docs/Web/API/Screen.lockOrientation.

mozOrientation just returns the value of the current orientation. Read about it at https://developer.mozilla.org/en-US/docs/Web/API/Screen.orientation.

There's also a good overview page about screen orientation at https://developer.mozilla.org/en-US/docs/WebAPI/Managing_screen_orientation

The prefixes are documented inconsistently, but once you know that, you can code away and the code above works fine on my Firefox OS ZTE Open.

Prefixes are a pain in the industry and Mozilla has recently said that they won't be using them any longer. When a new API is introduced, it will only be available by setting a flag in the about:config section. Read about that here: https://wiki.mozilla.org/WebAPI/ExposureGuidelines

Fun stuff!

Next I'd like to investigate Device Orientation, which is a bit more complicated, but is very important for game programming. If you don't want to touch the screen, you have an alternative in Device Orientation. You can tilt the device to move something. Like this old wooden game:



 But on your phone!

No comments:

Post a Comment