From 1ae93fdba800615faca28668d0e5aab2ded3e941 Mon Sep 17 00:00:00 2001
From: Martin Drapeau
- An elementary HTML5 Canvas game engine built on Backbone. Examples:
+ An elementary HTML5 Canvas game engine built on Backbone. Specialized for 2D platformers, and optimized for mobile. Examples:
HTML5 Canvas & Backbone
Features:
-
Features:
Mobile Devices
- Backbone.Input, Backbone.Button and Backbone.WorldEditor support touch and mouse events transparently. Works on Android, iOS and Windows. + Backbone.Engine, Backbone.Input, Backbone.Button and Backbone.WorldEditor support touch and mouse events transparently. Works on Android, iOS and Windows.
- In addition, we provide global function adjustViewport(canvas, width, height)
to dynamically adjust the viewport size and center the canvas when an orientation change occurs. This function can be found in adjust-viewport.js located in the
- On mobile devices the orientation of the web page can change between protrait and landscape. Since we cannot lock the orientation, we must find a way to adjust the viewport width to ensure the canvas is always visible. We use the meta tag viewport for that purpose. -
-
- As an example, let's assume our canvas is 960x700 pixels; therefore in landscape. In order for it to be visible and maximized on any portrait screen, we must control the width of the viewport. In index.html
we declare the viewport meta tag to be the width of the canvas:
+ On mobile devices, the meta
tag viewport
is set to 960 pixels wide.
+ On iOS, Android and Windows mobile devices, this will ensure the canvas is full width.
+ The HTML file contains the necessary header tags to ensure everything works.
+ You can change the viewport width value to whatever you want.
<meta name="viewport" content="width=960, user-scalable=no"/>+
+<meta name="viewport" content="width=960, user-scalable=no"/> +<meta name="mobileoptimized" content="0" /> +
- When the device is rotated to landscape, we need to adjust so that the height of the canvas is used instead.
- The natural solution would be to set content="height=700, user-scalable=no"
.
- However this is not supported (as reported by Quirksmode).
- Instead, we must derive the width based on the viewport ratio using this formula:
+ Not all screens have the same aspec ratio.
+ To take care of the height, you can change the height of the canvas upon start by calling the global function adjustViewport()
(see file adjust-viewport.js
for details).
700 * window.innerWidth / window.innerHeight+
+var canvas = document.getElementById("foreground"); +adjustViewport(canvas); +
- Since the mobile device orientation changes when we rotate it, we must recalculate and reset the viewport width dynamically. We can do so using the resize
event. Finally, we are also able to center the canvas by adjusting its left
position. Here is the final code:
+ If you want to maintain the aspect ratio, pass true. The canvas will be centered on screen.
-function adjustViewport(canvas, width, height) { - - var viewport = document.querySelector("meta[name=viewport]"); - - function onResize() { - if (window.innerWidth > window.innerHeight) { - // Landscape - canvas.style.left = _.max([0, (window.innerWidth - width) / 2]) + "px"; - viewport.setAttribute("content", "width=" + Math.ceil(height * window.innerWidth / window.innerHeight) + ",user-scalable=no"); - } else { - // Portrait - canvas.style.left = "0px"; - viewport.setAttribute("content", "width=" + width + ",user-scalable=no"); - } - } - - window.addEventListener("resize", _.debounce(onResize, 300)); - onResize(); -} ++var canvas = document.getElementById("foreground"); +adjustViewport(canvas, true);++ On desktop the
+viewport
meta tag is ignored. +adjustViewport
will center the canvas, even handling resizes. + It will try to reduce the height of the canvas if too tall unless you omit thekeepRatio
argument. +Web App
++ These meta tags are set to enable Web App support: +
++<meta name="apple-mobile-web-app-capable" content="yes" /> +<meta name="mobile-web-app-capable" content="yes" /> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +++ To suggest users to put add the home page to the home screen, checkout this great plugin: + Cubiq's Add To Homescreen. +
diff --git a/mario/index.html b/mario/index.html index d7ba967..aa0b2a5 100644 --- a/mario/index.html +++ b/mario/index.html @@ -8,6 +8,7 @@ + diff --git a/mario/main.js b/mario/main.js index cd8c211..f068ebe 100644 --- a/mario/main.js +++ b/mario/main.js @@ -19,6 +19,7 @@ $(window).on("load", function() { }); var canvas = document.getElementById("foreground"); + adjustViewport(canvas); var spriteSheets = new Backbone.SpriteSheetCollection([{ id: "mario", @@ -38,6 +39,8 @@ $(window).on("load", function() { var mario = new Backbone.Mario({ x: 400, y: 200, floor: 500 + }, { + input: input }); var world = new Backbone.World({ @@ -68,8 +71,5 @@ $(window).on("load", function() { world: world, mario: mario }); - - // Ensure the canvas is always visible and centered - adjustViewport(canvas, 960, 700); }); \ No newline at end of file diff --git a/src/adjust-viewport.js b/src/adjust-viewport.js index 31589a9..c6dbca4 100644 --- a/src/adjust-viewport.js +++ b/src/adjust-viewport.js @@ -9,31 +9,56 @@ * */ - // Ensures the canvas is always visible and centered by adjusting - // the viewport and the canvas left position. - var resizeCount = 0; - function adjustViewport(canvas, width, height) { + // Ensures the canvas is always full size and/or centered. + // + // On mobile: + // Works in conjunction with meta tag viewport where width is set to the canvas width. + // + // Will modify the canvas height to fit the device aspect ratio, never exceeding the + // origin canvas height. + // Set keepRatio to true to maintain your aspect ratio. In such a case, the viewport + // is adjusted to the height of the canvas. The canvas is kept centered on screen (with + // black bars left and right to fill empty space). + // + // On Desktop: + // The viewport meta tag is ignored. Instead, the canvas is kept centered. The height + // may be reduced if the window height is less than the canvas (to avoid scrolling). + // Set keepRatio to maintain the canvas height. - var viewport = document.querySelector("meta[name=viewport]"); + function adjustViewport(canvas, keepRatio) { + + var viewport = document.querySelector("meta[name=viewport]"), + mobile = "onorientationchange" in window || + window.navigator.msMaxTouchPoints || + window.navigator.isCocoonJS; function onResize() { if (window.innerWidth > window.innerHeight) { // Landscape - canvas.style.left = _.max([0, (window.innerWidth - width) / 2]) + "px"; - viewport.setAttribute("content", "width=" + Math.ceil(height * window.innerWidth / window.innerHeight) + ",user-scalable=no"); + canvas.style.left = _.max([0, (window.innerWidth - canvas.width) / 2]) + "px"; + if (mobile && viewport) + viewport.setAttribute("content", "width=" + Math.ceil(canvas.height * window.innerWidth / window.innerHeight) + ",user-scalable=no"); } else { // Portrait canvas.style.left = "0px"; - viewport.setAttribute("content", "width=" + width + ",user-scalable=no"); + if (mobile && viewport) + viewport.setAttribute("content", "width=" + canvas.width + ",user-scalable=no"); } } - window.addEventListener("resize", _.debounce(onResize, 300)); - setTimeout(onResize, 10); + if (mobile && !keepRatio) { + canvas.height = Math.round(Math.min(canvas.height, canvas.width * Math.min(window.innerHeight, window.innerWidth) / Math.max(window.innerHeight, window.innerWidth) )); + } else { + if (!keepRatio) + canvas.height = Math.round(Math.min(canvas.height, window.innerHeight)); + window.addEventListener("resize", _.debounce(onResize, 300)); + setTimeout(onResize, 10); + } + } _.extend(window, { - adjustViewport: adjustViewport, + adjustViewport: adjustViewport }); }).call(this); \ No newline at end of file diff --git a/super-mario-bros/main.js b/super-mario-bros/main.js index ec32ead..719afbe 100644 --- a/super-mario-bros/main.js +++ b/super-mario-bros/main.js @@ -12,6 +12,7 @@ $(window).on("load", function() { var canvas = document.getElementById("foreground"), context = canvas.getContext("2d"); + adjustViewport(canvas); var spriteNames = [ "ground", "brick-top", "brick", "ground2", "block", "block2", "question-block", "pennie", @@ -250,7 +251,4 @@ $(window).on("load", function() { controller: controller, }); - // Ensure the canvas is always visible and centered - adjustViewport(canvas, canvas.width, canvas.height); - }); \ No newline at end of file