Friday, April 29, 2011

Making HTML5 Games Match Your Screen

Sand Trap was our first opportunity to try supporting multiple resolutions, when we chose to enter it into SPIL Games' HTML5 Contest, geared towards mobile devices. At the time I decided to make it fluidly adjust to match any resolution it was opened on. This way it could not only match any width and height combination of a mobile device but also any resolution of a conventional computer browser. It worked well for Sand Trap, so we're re-using some of the same tricks on Thwack!!

Thwack!! on a maximized 1024x768 browser window
Implementing this requires taking advantage of CSS and JavaScript. Using just CSS, filling the whole screen is trivial, but CSS didn't allow us to maintain the same width-to-height ratio to prevent stretching of the gameboard, so that's where the JavaScript comes in.

Since we're not completely concerned about the exact width or height, the first piece of information we need to set is the ratio of width to height. In Thwack!!, we have it set to 4/3 (the game area is 4 units wide to 3 units high). Once we have determined this, it's a matter of making adjustments whenever the document is resized or, in the case of mobile devices, the screen orientation is changed. We handle these events by setting:
 window.addEventListener('resize', resizeGame, false);
 window.addEventListener('orientationchange', resizeGame, false);
Now we create a "resizeGame" function to handle these two events. With Thwack!! it's a bit more complicated since we're using multiple canvases, but if the game is running on a single canvas, it might look something like this:
 function resizeGame()
 {
  var gameBoard        = document.getElementById('canvas');
  var widthToHeight    = 4 / 3;

  var newWidth         = window.innerWidth;
  var newHeight        = window.innerHeight;
  var newWidthToHeight = newWidth / newHeight;

  if (newWidthToHeight > widthToHeight)
  {  // window width is too wide relative to desired game width
      gameBoard.style.height = newHeight + 'px';
      newWidth               = newHeight * widthToHeight;
      gameBoard.style.width  = newWidth + 'px';
  } else {  // window height is too high relative to desired game height
      gameBoard.style.width  = newWidth + 'px';
      newHeight              = newWidth / widthToHeight;
      gameBoard.style.height = newHeight + 'px';
  }

  // center the canvas
  gameBoard.style.marginTop  = (-newHeight / 2) + 'px';
  gameBoard.style.marginLeft = (-newWidth / 2) + 'px';
 };
Thwack!! on mobile Safari
Basically, if the window is too tall, we make width 100% of the window; if the window is too wide, we make height 100% of the window. The remaining dimension is sized according to the width-to-height ratio we previously set.

The last part re-centers our canvas in the middle of the screen. Many of the CSS properties we are concerned with are manipulated directly by the function above, but in order for those to work, we set up a few other CSS properties as follows:
 #canvas
 {
  position: absolute;
  left:     50%;
  top:      50%;
 }
This allows us to put the top left corner of the canvas in the center of the screen, and then our resizeGame() function gives the canvas a negative top and left margin half of the width and height of the game board so it is centered in the window.

Thursday, April 28, 2011

See you at Google I/O


Todd and I have been invited to show some of our work in HTML5 at the Google I/O Sandbox. We're really excited about this opportunity to connect with developers, field questions, and learn from the other developers showcasing their HTML5 work. We will be showing a special preview of Thwack!!, our latest game in development, as well as Entanglement: going behind the scenes on both to look at how we built them.

If you are planning to attend, we'll be handing out a few physical Thwack!! discs so you will be prepared should a game of table football break out over lunch. No, we're not Lego, but Todd does occasionally hang from the ceiling.

In other, unrelated news, we have over 10,000 Facebook fans! All of you are amazing - thanks for befriending us. To celebrate, we're handing out Sakura Grove codes to a few folks; check out our Facebook page if you want in on a chance to try Sakura Grove for free!

Wednesday, April 20, 2011

Making Thwack!! Fill Up Your Screen

One of the design decisions we made with Entanglement was to use up as much of the screen real estate as the browser would give us. This gives the game a more conventional, installed application atmosphere, especially if you hit F11 while playing. We're heading in a similar direction with Thwack!!, but have run into a few hiccups with the fast nature of the game-play and the slow nature of drawing to an HTML5 canvas element. Here's what we have found so far to keep things moving on a full-screen game:

Here only one disc needs to be re-rendered.
The first and most important take-away we found with our testing was to not draw to canvas unless we have to. The easiest way to keep the animation rendering short is to not draw anything. With a full-screen game, we have only a few parts of the game animating at any given time and have structured our canvases so that only the active parts of the game are being updated graphically.

To render as little as necessary, the game area is composed of several layers of canvases, similar to the layers you might work with in a paint application. Each disc and active game element has its own canvas, and its canvas is only redrawn if the game element has changed in some way. In the example at right, the yellow disc's canvas is erased and the disc is rendered in its new position while the background and the other discs remain static on the screen and no rendering calls are made.

The second drawing optimization we made was in clearing the canvas. We found that the above method works well for drawing itself, but clearing an entire canvas (or multiple canvases depending on how much action was occurring) proved to be expensive. I tried several different methods to clear a canvas before settling on using ctx.clearRect on the immediate area of the disc's last position. Using "ctx.globalCompositeOperation = 'destination-out'" and then rendering the disc at its last position would have been an elegant way to remove the last frame, but I found it's a bit more time-consuming than the ever-ready ctx.clearRect.

Are you a developer and have some wisdom to share? Let us know! Are you not a developer and just read through this post because you want to be? Awesome! You rock.

Thursday, April 14, 2011

Chrome's Excellent Developer Tools

Thank you Chrome for your excellent developer tools. I’m a little late to the web development party, and equally late to appreciating these tools, but I couldn’t imagine developing a web game without them and felt it was my duty to express my thanks.

On Thwack we’re using a mixture of HTML, CSS, and Javascript to construct the game. Javascript is used for the game simulation and graphics, while HTML and CSS are used to construct the interface and in-game menus. My appreciation for the debug tools blossomed while using CSS to construct one of these menus. In particular, I loved the elegant representation of CSS and the ability to edit it on the fly.

CSS is inherative in nature, with child elements inheriting styles from parents and grandparents. This can make for elegantly structured websites whose entire look can be changed with a few well placed edits. It can also make for a frustrating nightmare when you’re trying to determine why your menu won’t sit exactly where you want it and what is causing your font size to multiply 3x on mouse rollover. When you’re creating more complex sites, or in our case, creating menus dynamically in Javascript, these frustrating cases pop up more and more frequently. Thankfully, that’s where these tools shine.

You can even inspect lolcats, though I'm not sure how much you'll learn.
In Chrome, visualizing the CSS that’s affecting an element is as easy as right-clicking on that element and selecting ‘inspect element’. On doing so, the debug window will appear. In the right column you’ll find all your CSS questions answered. This column shows all of the styles affecting an element, grouping rules under the selectors that apply. The groups are stacked in order of inheritance with those directly applied to the element on top. Rules that have been overridden by more closely related rules are stricken through, invalid rules have handy “you’re doing something wrong” warning signs next to them, and more. With all of these things visually displayed it’s easy to determine exactly why an element is behaving as it is.

The developer tools!
Even better, this window allows you to edit and visualize rules in real-time. This is a giant time-saver when you’re tweaking things or experimenting. I find it easiest to make a rough guess of what I want, and then do the fine tuning from within the debug window. When I’ve settled on what I want I copy the final rules back into my code.


So once again, thanks for the great tools. They make my life easier by helping me see exactly what’s going on inside my game.

Friday, April 08, 2011

Learning Localization Lessons

Entanglement has been a great learning experience for us at Gopherwood Studios. When Derek originally developed Entanglement we were unaware what it would become and where it would take us. For that reason, the game was written with the naive expectation that we would never deal with many of the typical challenges of "real" game development. One such challenge, that I've been dealing with this week, is translating the game into other languages. What seemed like an unnecessary precaution when the game was a fun side-project is now a very real need as the Chrome Web Store expands worldwide. So, what did we do wrong? How are we fixing it? And what are we doing in future projects such as Thwack!!?

What did we do wrong?

Three things, we embedded text in the code, we embedded text in images, and we created interfaces that can't adapt to languages that require more space. These all seem like simple problems to anticipate, but it's easy to neglect them when you're coding in a hurry, or developing something for "fun".

How are we fixing it?


Fixing the text embedded in the code has been a painful process of locating all the text, putting it into a spreadsheet and replacing it with a variable in code. Each column in the spreadsheet will eventually be filled with the translated text. Using the spreadsheet we export and generate JavaScript files for each language that assign the text variable to the appropriate translation.

The artist-made text merged with the background looks great, but good luck translating it.
For the text embedded in images, we've decided to keep the English text images since they're already made, but for other languages we'll be replacing the images with regular text using the same method we're using for the rest of the text. This makes the code a bit messier, but we think it's worth it to keep the game looking as close to the original for our English audience.

If the English just fits, you know you have no chance in German.
To adapt the interface for longer languages we're taking a two pronged approach. First, in a few special cases we're modifying the interface in to hold the longer text. This is only done in some cases because it is somewhat cumbersome and time-consuming since the interface in Entanglement has largely solidified at this point. In cases where the font size is large, we will attempt to support longer language texts by shrinking the font size so text fits better.

What will we do in the future?

On future projects, starting with Thwack!!, we'll be applying the lessons we've learned from Entanglement should the need arise to translate one of our games.

For Thwack!!, we already have a spreadsheet set up to handle any text that will appear in the game. Our artist has (politely) recommended we handle all of the text code-side (rather than embedding it images) which should make the display code simpler and negate that problem entirely. And we're planning ahead on how to make scalable interfaces that can handle longer text.

A nice aspect about CSS3 that brings together the beauty of the interface with the necessities of localization is that we are now able to do programmatically to text what could, in earlier specs, only be done via images:
  1. We can add shadows and glow to text using the text-shadow property. Making a nice shadow only requires a single line of CSS: "text-shadow: 2px 2px 3px #333333;".
  2. We can use a growing variety of fonts that are not tied to those already installed on a majority of user's computers, without creating the text via images like we did with Herculanum (the font used in the images like "High Scores" above). For Entanglement, licensing Herculanum proved prohibitively expensive, but there are a growing number of services and fonts that are making this much easier. Many, like Google Web Fonts, only require including an extra CSS file link in our HTML. Providing fonts via our own server, as we did with most of the text in Entanglement, is likewise relatively easy using @font-face directly:

    @font-face { /* A font by Jos Buivenga (exljbris) - www.exljbris.com */
      font-family: 'Fontin-SmallCaps';
      font-style: normal;
      font-weight: normal;
      src: local('Fontin-SmallCaps'), url('Fontin-SmallCaps.ttf') format('truetype');
    }

  3. We can also rotate text vertically by using the CSS transform property like so:

    .vertical-text
    {
     -moz-transform:rotate(-90deg); 
     -webkit-transform: rotate(-90deg);
     -o-transform: rotate(-90deg);
     -ms-transform: rotate(-90deg);
     transform: rotate(-90deg);
    }
Here's to hoping when Thwack!! asks for some localization, we'll be better prepared.

Friday, April 01, 2011

Starting on "Thwack!!"

Thwack!! with intense prototyping art
We thought it might be cool to go ahead and throw up a screenshot of our latest game that's in development, so you can get an early preview and see how it evolves over time as we iterate on making it fun and add in professional art and audio. For those more interested in the code, you may find these bits interesting:
  • We're currently localizing Entanglement, which has changed the way we are coding Thwack!! (ie. smarter). All the text is being exported from a single spreadsheet into language-specific javascript and html files that are generated from "language-less" templates. I plan to go into this with more detail in another blog post about Entanglement, but everything is being carried over to this project.
  • We're using a wonderful Javascript port of the Box2d physics engine: http://code.google.com/p/box2dweb/. If you're not familiar with Box2d, it was created by Erin Catto: http://www.gphysics.com/.
  • We're doing our best to make Thwack!! function well on portable devices from the ground up. The three biggest considerations for this are game loop and animation speed, the touch interface, and screen display size. We have a bit of experience with this from our work on Sand Trap, so we are using what we learned there to try to make this game work even better.
    1. Given that there's a lot of movement and we've added Box2d to the mix, getting animation and loop speed up may prove tough on slower mobile devices. If anyone has found great ways to speed up canvas draws on mobiles, we've already noticed we will need all the optimization we can get.
    2. Having touch events call somewhat equivalent mouse events has proved to work rather well so far. Thanks to Ross Boucher for a nice concise lead on how to go about this: http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/
    3. For entering Sand Trap into the SPIL Games HTML5 mobile competition last year, we put together a bit of code to auto-scale game-boards according to screen size and have used a variation of that in Thwack!! (as well as Entanglement). The hiccup with this, as before, will be scaling fonts appropriately.
Back to work now... ...oh wait... ...if you haven't seen the new Blogger layouts, my favorite: http://blog.gopherwoodstudios.com/view/mosaic