X-Type – Making Of
For this year's Google IO, Google asked me to do a Chrome experiment for Mobile for them. They initially wanted me to vamp up Biolab Disaster – it's still a good game, but because of it's retro style it wouldn't be that impressive. Modern mobile browsers can do a lot more.
I suggested I would try to take another game of mine – X-Type – and make it work on mobile browsers. The game was made with my JavaScript Game Engine, so it mostly "just worked" on mobile browsers already. Yet, I still had a lot of work to do.
Have a look at X-Type over at chromeexperiments.com.
Screen Size
One of the most difficult things for HTML5 games is dealing with the vast amount of different screen sizes and aspect ratios out there. I experimented a lot with different solutions and ended with a fairly simple one: the internal width the game's viewport is always 480px. These 480px get scaled to whatever is available on the device. The height of the viewport is variable, so that it fills the screen with the same scaling factor as the width.
// The internal width for our canvas is fixed at 480px. // The internal height is set so that it fills the screen when scaled canvas.width = 480; canvas.height = window.innerHeight * (canvas.width / window.innerWidth); // Scale the canvas via CSS to fill the screen canvas.style.width = window.innerWidth + 'px'; canvas.style.height = window.innerHeight + 'px';
In older browsers (Mobile and Desktop), scaling the <canvas> element was a horrible idea – it decreased performance to a tenth of what it would be unscaled. I'm happy to report that this is no longer true; Mobile Safari on iOS5 and the Chrome Beta on Android work just fine with scaled canvas. It still makes the game unplayable in Android's "Browser", though.
I also took care to only display the game in portrait mode and show a "Please Rotate the Device" message otherwise. Mobile Safari and Chrome both support the orientationchange event, which makes this easy. However, we can not rely on window.orientation, which reports the rotation in degrees (0, 90, 180 or 270), because some devices report 0° for portrait mode, while others report 0° for landscape. How convenient!
The solution is to just check if the window height is bigger than the width – if so, we're obviously in portrait mode! But as this would be too easy, Chrome's Browser offers another challenge for us: it only updates the window dimensions after it has fired the orientationchange event. So we listen for orientationchange and resize events. Sigh.
var wasPortrait = -1; var checkOrientation = function() { var isPortrait = (window.innerHeight > window.innerWidth); if( isPortrait === wasPortrait ) { return; // Nothing to do here } wasPortrait = isPortrait; // Do your stuff... }; window.addEventListener( 'orientationchange', checkOrientation, false ); window.addEventListener( 'resize', checkOrientation, false );
Performance
Since iOS 5 the <canvas> element is hardware accelerated and it really shows. You can draw hundreds of sprites on the screen without any slowdowns at all. The same is true for Chrome on Android – to a certain degree.
All drawing is scheduled via requestAnimationFrame and thus bound to the display's refresh rate. This works nicely on iOS, but Chrome refuses to draw at the 60hz even for the simplest scenes. You can use setInterval to process more frames, but only a portion of them is really presented on the screen.
So while Chrome's JavaScript engine is fast enough to process and render 60 FPS, it fails to display all of the rendered frames. I have no doubt that this bug(?) will get fixed.
While the game works in a multitude of other browser's on Android, such as Firefox, Dolphin or Opera, none of them provided good performance. I suspect the <canvas> element is not hardware acclerated in any of these, but didn't investigate further.
Controls
In the desktop version of the game you move the player with the arrow keys and aim and shoot with the mouse. Of course this doesn't work on touch screens, so I opted for dual virtual analog sticks. This worked out surprisingly well – with a bit of practice, you can control your spaceship quite precisely.
I also tried to make the analog sticks appear where you touch the screen first, so that you can always change the position. This made everything quite a bit confusing; it's easier to grasp the concept when the position of the analog sticks is fixed. Providing the dynamic positioning is probably more of "pro gamer" feature that should be optional, if at all.
Sound
This is the sad part. I complained about support for the <audio> element in mobile browsers last year already – and guess what: it's still the same shit. Apple hasn't done anything at all to improve the situation; same goes for Android's Browser. The Chrome Beta on Android seems to have some support for Audio, but it's not really usable for real time games at the moment. I'll investigate this further.
As always, I have high hopes though. Never give up, never surrender!
All in all, I'm very pleased with the results. Rendering performance in modern mobile browsers is really awesome and the quirks I encountered were workaroundable.
I learned a lot with this project and will use this new gained knowledge to make mobile browser support much more easy in the next version of Impact.
24 Comments:
Actually, with the Beta 2 of the upcoming iOS6 you can already use Web Audio API in Mobile Safari. Also <audio> tag get some sort of improvement. You still can't rely on syncronyzed sound, but it's already playing more than 1 sound.
Heavily inspired by Warning Forever and it's inspirations. Looks good, otherwise.
HTML5 has got the moves like Jagger.
How to replace audio elements in browser? Does Javascript solve this problem? ex. buzz.jaysalvat.com/ (Buzz is a small but powerful Javascript library that allows you to easily take advantage of the new HTML5 audio element. It degrades gracefully on non-modern browsers.)
Thanks for the writeup. I'm impressed with your continued advocacy for Javascript, and I think the Javascript + mobile situation is slowly getting better.
Nice, inspiring too. Up till now, I'd still not seen a graphic-intensive, truly cross-platform html5 game.
It'll be interesting to see some test again now that A4.1 and iOS6 have been anounced.
Congratulations, that looks awesome. The lack of support for the audio tag is maddening tho. I can't understand what's wrong with browser developers...
Good article, thanks for sharing.
I'm wondering if you have used this two sticks kind of control because of the multitouch in iOS (www.phoboslab.org/crap/mt.html).
Great game, excellent work, and really love the short concise write up breaking down each challenge and solution.
I scored 500,000 at only stage 1.
There is a scoring trick.
Each triangle figured bullet have 20 points.
Make the target's all arm removed. and remaining body only.
The body will shot multiple triangle figured bullets to downward.
Move to ship up-left (or up-right) corner and shoot downward.
Also, mouse click and drag outside of windows will make auto-fire.
www.valken.net/510
I upload screenshot to my blog.
- Valken Lee -
@Valken Lee: Thanks for mentioning! I changed it so that the bullets don't give any kill score.
For the mobile version of Fruit Killer, I used a completely different approach to scale the canvas: I used a fixed size (480x300), and then scaled it to match the viewport dimensions, so everyone shares the same aspect ratio.
Of course I have low definition for bigger screens and sometimes the canvas does not fit the screen, but the game works about the same way everywhere.
Anyway good post ;)
Hello, I have played with X-type and really enjoyed it, specially the music. I saw it was created by Andreas Loesch, but i couldn't find any download possiblitys (googled it).
So where and how i can download / buy the music?
Sorry for bad english.
Thanks!
This is really the best Canvas game running smoothly on an iPhone I have seen. State of the art.
This is great because I can show it to my products manager and tell them "See, that run on your iPhone !"
Thanks for the hard work.
Awesome inspired by you and started leaning :)
I have test on IOS5 to draw animation sprite in canvas.
I can got 60fps when using non retina image with 50 animation sprite.
But when i update the image to retina version, the fps will turn down to 17fps.
I also do a testing in IOS 6 they can go up to 60fps.
So That mean retina in IOS5 is not good enough?
Can I download the game
canvas.width = 480;
canvas.height = window.innerHeight * (canvas.width / window.innerWidth);
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';var wasPortrait = -1;
var checkOrientation = function() {
var isPortrait = (window.innerHeight > window.innerWidth);
if( isPortrait === wasPortrait )
wasPortrait = isPortrait;};
window.addEventListener( 'orientationchange', checkOrientation, false );
window.addEventListener( 'resize', checkOrientation, false );
LOL
Plays On Wii U LOL
I got a website with one HTML5 game on WWW.BVHGJUG.weebly.com
Its BrowserQuest
dh
ssssssssssssssssswwwwwwwwwwwwwwwwwweeeeeeeeeeeeeeeeeettttttttttttttt!!!!!!!!!!!!!!!!!!!!!!!!!!!
no srsly this game is the best way to have fun in the computer class :D
Could you add Joystick Controls like for a Gamecube or Xbox controller? That would be AMAZING!!!