1 /**
  2  * enchant.js v0.8.3
  3  * http://enchantjs.com
  4  *
  5  * Copyright UEI Corporation
  6  * Released under the MIT license.
  7  */
  8 
  9 (function(window, undefined) {
 10 
 11 // ECMA-262 5th edition Functions
 12 if (typeof Object.defineProperty !== 'function') {
 13     Object.defineProperty = function(obj, prop, desc) {
 14         if ('value' in desc) {
 15             obj[prop] = desc.value;
 16         }
 17         if ('get' in desc) {
 18             obj.__defineGetter__(prop, desc.get);
 19         }
 20         if ('set' in desc) {
 21             obj.__defineSetter__(prop, desc.set);
 22         }
 23         return obj;
 24     };
 25 }
 26 if (typeof Object.defineProperties !== 'function') {
 27     Object.defineProperties = function(obj, descs) {
 28         for (var prop in descs) {
 29             if (descs.hasOwnProperty(prop)) {
 30                 Object.defineProperty(obj, prop, descs[prop]);
 31             }
 32         }
 33         return obj;
 34     };
 35 }
 36 if (typeof Object.create !== 'function') {
 37     Object.create = function(prototype, descs) {
 38         function F() {
 39         }
 40 
 41         F.prototype = prototype;
 42         var obj = new F();
 43         if (descs != null) {
 44             Object.defineProperties(obj, descs);
 45         }
 46         return obj;
 47     };
 48 }
 49 if (typeof Object.getPrototypeOf !== 'function') {
 50     Object.getPrototypeOf = function(obj) {
 51         return obj.__proto__;
 52     };
 53 }
 54 
 55 if (typeof Function.prototype.bind !== 'function') {
 56     Function.prototype.bind = function(thisObject) {
 57         var func = this;
 58         var args = Array.prototype.slice.call(arguments, 1);
 59         var Nop = function() {
 60         };
 61         var bound = function() {
 62             var a = args.concat(Array.prototype.slice.call(arguments));
 63             return func.apply(
 64                 this instanceof Nop ? this : thisObject || window, a);
 65         };
 66         Nop.prototype = func.prototype;
 67         bound.prototype = new Nop();
 68         return bound;
 69     };
 70 }
 71 
 72 window.getTime = (function() {
 73     var origin;
 74     if (window.performance && window.performance.now) {
 75         origin = Date.now();
 76         return function() {
 77             return origin + window.performance.now();
 78         };
 79     } else if (window.performance && window.performance.webkitNow) {
 80         origin = Date.now();
 81         return function() {
 82             return origin + window.performance.webkitNow();
 83         };
 84     } else {
 85         return Date.now;
 86     }
 87 }());
 88 
 89 // define requestAnimationFrame
 90 window.requestAnimationFrame =
 91     window.requestAnimationFrame ||
 92     window.mozRequestAnimationFrame ||
 93     window.webkitRequestAnimationFrame ||
 94     window.msRequestAnimationFrame ||
 95     (function() {
 96         var lastTime = window.getTime();
 97         var frame = 1000 / 60;
 98         return function(func) {
 99             var _id = setTimeout(function() {
100                 lastTime = window.getTime();
101                 func(lastTime);
102             }, Math.max(0, lastTime + frame - window.getTime()));
103             return _id;
104         };
105     }());
106 
107 /**
108  * Export the library classes globally.
109  *
110  * When no arguments are given, all classes defined in enchant.js as well as all classes defined in
111  * plugins will be exported. When more than one argument is given, by default only classes defined
112  * in enchant.js will be exported. When you wish to export plugin classes you must explicitly deliver
113  * the plugin identifiers as arguments.
114  *
115  * @example
116  * enchant();     // All classes will be exported.
117  * enchant('');   // Only classes in enchant.js will be exported.
118  * enchant('ui'); // enchant.js classes and ui.enchant.js classes will be exported.
119  *
120  * @param {...String} [modules] Export module. Multiple designations possible.
121  * @function
122  * @global
123  * @name enchant
124  */
125 var enchant = function(modules) {
126     if (modules != null) {
127         if (!(modules instanceof Array)) {
128             modules = Array.prototype.slice.call(arguments);
129         }
130         modules = modules.filter(function(module) {
131             return [module].join();
132         });
133     }
134     (function include(module, prefix) {
135         var submodules = [],
136             i, len;
137         for (var prop in module) {
138             if (module.hasOwnProperty(prop)) {
139                 if (typeof module[prop] === 'function') {
140                     window[prop] = module[prop];
141                 } else if (typeof module[prop] === 'object' && module[prop] !== null && Object.getPrototypeOf(module[prop]) === Object.prototype) {
142                     if (modules == null) {
143                         submodules.push(prop);
144                     } else {
145                         i = modules.indexOf(prefix + prop);
146                         if (i !== -1) {
147                             submodules.push(prop);
148                             modules.splice(i, 1);
149                         }
150                     }
151                 }
152             }
153         }
154 
155         for (i = 0, len = submodules.length; i < len; i++) {
156             include(module[submodules[i]], prefix + submodules[i] + '.');
157         }
158     }(enchant, ''));
159 
160     // issue 185
161     if (enchant.Class.getInheritanceTree(window.Game).length <= enchant.Class.getInheritanceTree(window.Core).length) {
162         window.Game = window.Core;
163     }
164 
165     if (modules != null && modules.length) {
166         throw new Error('Cannot load module: ' + modules.join(', '));
167     }
168 };
169 
170 // export enchant
171 window.enchant = enchant;
172 
173 window.addEventListener("message", function(msg, origin) {
174     try {
175         var data = JSON.parse(msg.data);
176         if (data.type === "event") {
177             enchant.Core.instance.dispatchEvent(new enchant.Event(data.value));
178         } else if (data.type === "debug") {
179             switch (data.value) {
180                 case "start":
181                     enchant.Core.instance.start();
182                     break;
183                 case "pause":
184                     enchant.Core.instance.pause();
185                     break;
186                 case "resume":
187                     enchant.Core.instance.resume();
188                     break;
189                 case "tick":
190                     enchant.Core.instance._tick();
191                     break;
192                 default:
193                     break;
194             }
195         }
196     } catch (e) {
197         // ignore
198     }
199 }, false);
200 
201 /**
202  * @name enchant.Class
203  * @class
204  * A Class representing a class which supports inheritance.
205  * @param {Function} [superclass] The class from which the
206  * new class will inherit the class definition.
207  * @param {*} [definition] Class definition.
208  * @constructor
209  */
210 enchant.Class = function(superclass, definition) {
211     return enchant.Class.create(superclass, definition);
212 };
213 
214 /**
215  * Creates a class.
216  *
217  * When defining a class that extends from another class, 
218  * the constructor of the other class will be used by default.
219  * Even if you override this constructor, you must still call it
220  * to ensure that the class is initialized correctly.
221  *
222  * @example
223  * // Creates a Ball class.
224  * var Ball = Class.create({ 
225  *
226  *     // Ball's constructor
227  *     initialize: function(radius) {
228  *       // ... code ...
229  *     }, 
230  *
231  *     // Defines a fall method that doesn't take any arguments.
232  *     fall: function() { 
233  *       // ... code ...
234  *     }
235  * });
236  *
237  * // Creates a Ball class that extends from "Sprite"
238  * var Ball = Class.create(Sprite);  
239  *
240  * // Creates a Ball class that extends from "Sprite"
241  * var Ball = Class.create(Sprite, { 
242  *
243  *     // Overwrite Sprite's constructor
244  *     initialize: function(radius) { 
245  *
246  *         // Call Sprite's constructor.
247  *         Sprite.call(this, radius * 2, radius * 2);
248  *
249  *         this.image = core.assets['ball.gif'];
250  *     }
251  * });
252  *
253  * @param {Function} [superclass] The class from which the
254  * new class will inherit the class definition.
255  * @param {*} [definition] Class definition.
256  * @static
257  */
258 enchant.Class.create = function(superclass, definition) {
259     if (superclass == null && definition) {
260         throw new Error("superclass is undefined (enchant.Class.create)");
261     } else if (superclass == null) {
262         throw new Error("definition is undefined (enchant.Class.create)");
263     }
264 
265     if (arguments.length === 0) {
266         return enchant.Class.create(Object, definition);
267     } else if (arguments.length === 1 && typeof arguments[0] !== 'function') {
268         return enchant.Class.create(Object, arguments[0]);
269     }
270 
271     for (var prop in definition) {
272         if (definition.hasOwnProperty(prop)) {
273             if (typeof definition[prop] === 'object' && definition[prop] !== null && Object.getPrototypeOf(definition[prop]) === Object.prototype) {
274                 if (!('enumerable' in definition[prop])) {
275                     definition[prop].enumerable = true;
276                 }
277             } else {
278                 definition[prop] = { value: definition[prop], enumerable: true, writable: true };
279             }
280         }
281     }
282     var Constructor = function() {
283         if (this instanceof Constructor) {
284             Constructor.prototype.initialize.apply(this, arguments);
285         } else {
286             return new Constructor();
287         }
288     };
289     Constructor.prototype = Object.create(superclass.prototype, definition);
290     Constructor.prototype.constructor = Constructor;
291     if (Constructor.prototype.initialize == null) {
292         Constructor.prototype.initialize = function() {
293             superclass.apply(this, arguments);
294         };
295     }
296 
297     var tree = this.getInheritanceTree(superclass);
298     for (var i = 0, l = tree.length; i < l; i++) {
299         if (typeof tree[i]._inherited === 'function') {
300             tree[i]._inherited(Constructor);
301             break;
302         }
303     }
304 
305     return Constructor;
306 };
307 
308 /**
309  * Get the inheritance tree of this class.
310  * @param {Function} Constructor
311  * @return {Function[]} Parent's constructor
312  */
313 enchant.Class.getInheritanceTree = function(Constructor) {
314     var ret = [];
315     var C = Constructor;
316     var proto = C.prototype;
317     while (C !== Object) {
318         ret.push(C);
319         proto = Object.getPrototypeOf(proto);
320         C = proto.constructor;
321     }
322     return ret;
323 };
324 
325 /**
326  * @namespace
327  * enchant.js environment variables.
328  * Execution settings can be changed by modifying these before calling new Core().
329  */
330 enchant.ENV = {
331     /**
332      * Version of enchant.js
333      * @type String
334      */
335     VERSION: '0.8.3',
336     /**
337      * Identifier of the current browser.
338      * @type String
339      */
340     BROWSER: (function(ua) {
341         if (/Eagle/.test(ua)) {
342             return 'eagle';
343         } else if (/Opera/.test(ua)) {
344             return 'opera';
345         } else if (/MSIE|Trident/.test(ua)) {
346             return 'ie';
347         } else if (/Chrome/.test(ua)) {
348             return 'chrome';
349         } else if (/(?:Macintosh|Windows).*AppleWebKit/.test(ua)) {
350             return 'safari';
351         } else if (/(?:iPhone|iPad|iPod).*AppleWebKit/.test(ua)) {
352             return 'mobilesafari';
353         } else if (/Firefox/.test(ua)) {
354             return 'firefox';
355         } else if (/Android/.test(ua)) {
356             return 'android';
357         } else {
358             return '';
359         }
360     }(navigator.userAgent)),
361     /**
362      * The CSS vendor prefix of the current browser.
363      * @type String
364      */
365     VENDOR_PREFIX: (function() {
366         var ua = navigator.userAgent;
367         if (ua.indexOf('Opera') !== -1) {
368             return 'O';
369         } else if (/MSIE|Trident/.test(ua)) {
370             return 'ms';
371         } else if (ua.indexOf('WebKit') !== -1) {
372             return 'webkit';
373         } else if (navigator.product === 'Gecko') {
374             return 'Moz';
375         } else {
376             return '';
377         }
378     }()),
379     /**
380      * Determines if the current browser supports touch.
381      * True, if touch is enabled.
382      * @type Boolean
383      */
384     TOUCH_ENABLED: (function() {
385         var div = document.createElement('div');
386         div.setAttribute('ontouchstart', 'return');
387         return typeof div.ontouchstart === 'function';
388     }()),
389     /**
390      * Determines if the current browser is an iPhone with a retina display.
391      * True, if this display is a retina display.
392      * @type Boolean
393      */
394     RETINA_DISPLAY: (function() {
395         if (navigator.userAgent.indexOf('iPhone') !== -1 && window.devicePixelRatio === 2) {
396             var viewport = document.querySelector('meta[name="viewport"]');
397             if (viewport == null) {
398                 viewport = document.createElement('meta');
399                 document.head.appendChild(viewport);
400             }
401             viewport.setAttribute('content', 'width=640');
402             return true;
403         } else {
404             return false;
405         }
406     }()),
407     /**
408      * Determines if for current browser Flash should be used to play 
409      * sound instead of the native audio class.
410      * True, if flash should be used.
411      * @type Boolean
412      */
413     USE_FLASH_SOUND: (function() {
414         var ua = navigator.userAgent;
415         var vendor = navigator.vendor || "";
416         // non-local access, not on mobile mobile device, not on safari
417         return (location.href.indexOf('http') === 0 && ua.indexOf('Mobile') === -1 && vendor.indexOf('Apple') !== -1);
418     }()),
419     /**
420      * If click/touch event occure for these tags the setPreventDefault() method will not be called.
421      * @type String[]
422      */
423     USE_DEFAULT_EVENT_TAGS: ['input', 'textarea', 'select', 'area'],
424     /**
425      * Method names of CanvasRenderingContext2D that will be defined as Surface method.
426      * @type String[]
427      */
428     CANVAS_DRAWING_METHODS: [
429         'putImageData', 'drawImage', 'drawFocusRing', 'fill', 'stroke',
430         'clearRect', 'fillRect', 'strokeRect', 'fillText', 'strokeText'
431     ],
432     /**
433      * Keybind Table.
434      * You can use 'left', 'up', 'right', 'down' for preset event.
435      * @example
436      * enchant.ENV.KEY_BIND_TABLE = {
437      *     37: 'left',
438      *     38: 'up',
439      *     39: 'right',
440      *     40: 'down',
441      *     32: 'a', //-> use 'space' key as 'a button'
442      * };
443      * @type Object
444      */
445     KEY_BIND_TABLE: {
446         37: 'left',
447         38: 'up',
448         39: 'right',
449         40: 'down'
450     },
451     /**
452      * If keydown event occure for these keycodes the setPreventDefault() method will be called.
453      * @type Number[]
454      */
455     PREVENT_DEFAULT_KEY_CODES: [37, 38, 39, 40],
456     /**
457      * Determines if Sound is enabled on Mobile Safari.
458      * @type Boolean
459      */
460     SOUND_ENABLED_ON_MOBILE_SAFARI: true,
461     /**
462      * Determines if "touch to start" scene is enabled.
463      * It is necessary on Mobile Safari because WebAudio Sound is
464      * muted by browser until play any sound in touch event handler.
465      * If set it to false, you should control this behavior manually.
466      * @type Boolean
467      */
468     USE_TOUCH_TO_START_SCENE: true,
469     /**
470      * Determines if WebAudioAPI is enabled. (true: use WebAudioAPI instead of Audio element if possible)
471      * @type Boolean
472      */
473     USE_WEBAUDIO: (function() {
474         return location.protocol !== 'file:';
475     }()),
476     /**
477      * Determines if animation feature is enabled. (true: Timeline instance will be generated in new Node)
478      * @type Boolean
479      */
480     USE_ANIMATION: true,
481     /**
482      * Specifies range of the touch detection.
483      * The detection area will be (COLOR_DETECTION_LEVEL * 2 + 1)px square.
484      * @type Boolean
485      */
486     COLOR_DETECTION_LEVEL: 2
487 };
488 
489 /**
490  * @scope enchant.Event.prototype
491  */
492 enchant.Event = enchant.Class.create({
493     /**
494      * @name enchant.Event
495      * @class
496      * A class for an independent implementation of events similar to DOM Events.
497      * Does not include phase concepts.
498      * @param {String} type Event type.
499      * @constructs
500      */
501     initialize: function(type) {
502         /**
503          * The type of the event.
504          * @type String
505          */
506         this.type = type;
507         /**
508          * The target of the event.
509          * @type *
510          */
511         this.target = null;
512         /**
513          * The x-coordinate of the event's occurrence.
514          * @type Number
515          */
516         this.x = 0;
517         /**
518          * The y-coordinate of the event's occurrence.
519          * @type Number
520          */
521         this.y = 0;
522         /**
523          * The x-coordinate of the event's occurrence relative to the object
524          * which issued the event.
525          * @type Number
526          */
527         this.localX = 0;
528         /**
529          * The y-coordinate of the event's occurrence relative to the object
530          * which issued the event.
531          * @type Number
532          */
533         this.localY = 0;
534     },
535     _initPosition: function(pageX, pageY) {
536         var core = enchant.Core.instance;
537         this.x = this.localX = (pageX - core._pageX) / core.scale;
538         this.y = this.localY = (pageY - core._pageY) / core.scale;
539     }
540 });
541 
542 /**
543  * An event dispatched once the core has finished loading.
544  *
545  * When preloading images, it is necessary to wait until preloading is complete
546  * before starting the game.
547  * Issued by: {@link enchant.Core}
548  *
549  * @example
550  * var core = new Core(320, 320);
551  * core.preload('player.gif');
552  * core.onload = function() {
553  *     ... // Describes initial core processing
554  * };
555  * core.start();
556  * @type String
557  */
558 enchant.Event.LOAD = 'load';
559 
560 /**
561  * An event dispatched when an error occurs.
562  * Issued by: {@link enchant.Core}, {@link enchant.Surface}, {@link enchant.WebAudioSound}, {@link enchant.DOMSound}
563  */
564 enchant.Event.ERROR = 'error';
565 
566 /**
567  * An event dispatched when the display size is changed.
568  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
569  @type String
570  */
571 enchant.Event.CORE_RESIZE = 'coreresize';
572 
573 /**
574  * An event dispatched while the core is loading.
575  * Dispatched each time an image is preloaded.
576  * Issued by: {@link enchant.LoadingScene}
577  * @type String
578  */
579 enchant.Event.PROGRESS = 'progress';
580 
581 /**
582  * An event which is occurring when a new frame is beeing processed.
583  * Issued object: {@link enchant.Core}, {@link enchant.Node}
584  * @type String
585  */
586 enchant.Event.ENTER_FRAME = 'enterframe';
587 
588 /**
589  * An event dispatched at the end of processing a new frame.
590  * Issued by: {@link enchant.Core}, {@link enchant.Node}
591  * @type String
592  */
593 enchant.Event.EXIT_FRAME = 'exitframe';
594 
595 /**
596  * An event dispatched when a Scene begins.
597  * Issued by: {@link enchant.Scene}
598  * @type String
599  */
600 enchant.Event.ENTER = 'enter';
601 
602 /**
603  * An event dispatched when a Scene ends.
604  * Issued by: {@link enchant.Scene}
605  * @type String
606  */
607 enchant.Event.EXIT = 'exit';
608 
609 /**
610  * An event dispatched when a Child is added to a Node.
611  * Issued by: {@link enchant.Group}, {@link enchant.Scene}
612  * @type String
613  */
614 enchant.Event.CHILD_ADDED = 'childadded';
615 
616 /**
617  * An event dispatched when a Node is added to a Group.
618  * Issued by: {@link enchant.Node}
619  * @type String
620  */
621 enchant.Event.ADDED = 'added';
622 
623 /**
624  * An event dispatched when a Node is added to a Scene.
625  * Issued by: {@link enchant.Node}
626  * @type String
627  */
628 enchant.Event.ADDED_TO_SCENE = 'addedtoscene';
629 
630 /**
631  * An event dispatched when a Child is removed from a Node.
632  * Issued by: {@link enchant.Group}, {@link enchant.Scene}
633  * @type String
634  * @type String
635  */
636 enchant.Event.CHILD_REMOVED = 'childremoved';
637 
638 /**
639  * An event dispatched when a Node is deleted from a Group.
640  * Issued by: {@link enchant.Node}
641  * @type String
642  */
643 enchant.Event.REMOVED = 'removed';
644 
645 /**
646  * An event dispatched when a Node is deleted from a Scene.
647  * Issued by: {@link enchant.Node}
648  * @type String
649  */
650 enchant.Event.REMOVED_FROM_SCENE = 'removedfromscene';
651 
652 /**
653  * An event dispatched when a touch event intersecting a Node begins.
654  * A mouse event counts as a touch event. Issued by: {@link enchant.Node}
655  * @type String
656  */
657 enchant.Event.TOUCH_START = 'touchstart';
658 
659 /**
660  * An event dispatched when a touch event intersecting the Node has been moved.
661  * A mouse event counts as a touch event. Issued by: {@link enchant.Node}
662  * @type String
663  */
664 enchant.Event.TOUCH_MOVE = 'touchmove';
665 
666 /**
667  * An event dispatched when a touch event intersecting the Node ends.
668  * A mouse event counts as a touch event. Issued by: {@link enchant.Node}
669  * @type String
670  */
671 enchant.Event.TOUCH_END = 'touchend';
672 
673 /**
674  * An event dispatched when an Entity is rendered.
675  * Issued by: {@link enchant.Entity}
676  * @type String
677  */
678 enchant.Event.RENDER = 'render';
679 
680 /**
681  * An event dispatched when a button is pressed.
682  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
683  * @type String
684  */
685 enchant.Event.INPUT_START = 'inputstart';
686 
687 /**
688  * An event dispatched when button inputs change.
689  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
690  * @type String
691  */
692 enchant.Event.INPUT_CHANGE = 'inputchange';
693 
694 /**
695  * An event dispatched when button input ends.
696  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
697  * @type String
698  */
699 enchant.Event.INPUT_END = 'inputend';
700 
701 /**
702  * An internal event which is occurring when a input changes.
703  * Issued object: {@link enchant.InputSource}
704  * @type String
705  */
706 enchant.Event.INPUT_STATE_CHANGED = 'inputstatechanged';
707 
708 /**
709  * An event dispatched when the 'left' button is pressed.
710  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
711  * @type String
712  */
713 enchant.Event.LEFT_BUTTON_DOWN = 'leftbuttondown';
714 
715 /**
716  * An event dispatched when the 'left' button is released.
717  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
718  * @type String
719  */
720 enchant.Event.LEFT_BUTTON_UP = 'leftbuttonup';
721 
722 /**
723  * An event dispatched when the 'right' button is pressed.
724  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
725  * @type String
726  */
727 enchant.Event.RIGHT_BUTTON_DOWN = 'rightbuttondown';
728 
729 /**
730  * An event dispatched when the 'right' button is released.
731  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
732  * @type String
733  */
734 enchant.Event.RIGHT_BUTTON_UP = 'rightbuttonup';
735 
736 /**
737  * An event dispatched when the 'up' button is pressed.
738  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
739  * @type String
740  */
741 enchant.Event.UP_BUTTON_DOWN = 'upbuttondown';
742 
743 /**
744  * An event dispatched when the 'up' button is released.
745  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
746  * @type String
747  */
748 enchant.Event.UP_BUTTON_UP = 'upbuttonup';
749 
750 /**
751  * An event dispatched when the 'down' button is pressed.
752  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
753  * @type String
754  */
755 enchant.Event.DOWN_BUTTON_DOWN = 'downbuttondown';
756 
757 /**
758  * An event dispatched when the 'down' button is released.
759  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
760  * @type String
761  */
762 enchant.Event.DOWN_BUTTON_UP = 'downbuttonup';
763 
764 /**
765  * An event dispatched when the 'a' button is pressed.
766  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
767  * @type String
768  */
769 enchant.Event.A_BUTTON_DOWN = 'abuttondown';
770 
771 /**
772  * An event dispatched when the 'a' button is released.
773  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
774  * @type String
775  */
776 enchant.Event.A_BUTTON_UP = 'abuttonup';
777 
778 /**
779  * An event dispatched when the 'b' button is pressed.
780  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
781  * @type String
782  */
783 enchant.Event.B_BUTTON_DOWN = 'bbuttondown';
784 
785 /**
786  * An event dispatched when the 'b' button is released.
787  * Issued by: {@link enchant.Core}, {@link enchant.Scene}
788  * @type String
789  */
790 enchant.Event.B_BUTTON_UP = 'bbuttonup';
791 
792 /**
793  * An event dispatched when an Action is added to a Timeline.
794  * When looped, an Action is removed from the Timeline and added back into it.
795  * @type String
796  */
797 enchant.Event.ADDED_TO_TIMELINE = "addedtotimeline";
798 
799 /**
800  * An event dispatched when an Action is removed from a Timeline.
801  * When looped, an Action is removed from the timeline and added back into it.
802  * @type String
803  */
804 enchant.Event.REMOVED_FROM_TIMELINE = "removedfromtimeline";
805 
806 /**
807  * An event dispatched when an Action begins.
808  * @type String
809  */
810 enchant.Event.ACTION_START = "actionstart";
811 
812 /**
813  * An event dispatched when an Action finishes.
814  * @type String
815  */
816 enchant.Event.ACTION_END = "actionend";
817 
818 /**
819  * An event dispatched when an Action has gone through one frame.
820  * @type String
821  */
822 enchant.Event.ACTION_TICK = "actiontick";
823 
824 /**
825  * An event dispatched to the Timeline when an Action is added.
826  * @type String
827  */
828 enchant.Event.ACTION_ADDED = "actionadded";
829 
830 /**
831  * An event dispatched to the Timeline when an Action is removed.
832  * @type String
833  */
834 enchant.Event.ACTION_REMOVED = "actionremoved";
835 
836 /**
837  * An event dispatched when an animation finishes, meaning null element was encountered
838  * Issued by: {@link enchant.Sprite}
839  * @type String
840  */
841 enchant.Event.ANIMATION_END = "animationend";
842 
843 /**
844  * @scope enchant.EventTarget.prototype
845  */
846 enchant.EventTarget = enchant.Class.create({
847     /**
848      * @name enchant.EventTarget
849      * @class
850      * A class for implementation of events similar to DOM Events.
851      * However, it does not include the concept of phases.
852      * @constructs
853      */
854     initialize: function() {
855         this._listeners = {};
856     },
857     /**
858      * Add a new event listener which will be executed when the event
859      * is dispatched.
860      * @param {String} type Type of the events.
861      * @param {Function(e:enchant.Event)} listener Event listener to be added.
862      */
863     addEventListener: function(type, listener) {
864         var listeners = this._listeners[type];
865         if (listeners == null) {
866             this._listeners[type] = [listener];
867         } else if (listeners.indexOf(listener) === -1) {
868             listeners.unshift(listener);
869 
870         }
871     },
872     /**
873      * Synonym for addEventListener.
874      * @param {String} type Type of the events.
875      * @param {Function(e:enchant.Event)} listener Event listener to be added.
876      * @see enchant.EventTarget#addEventListener
877      */
878     on: function() {
879         this.addEventListener.apply(this, arguments);
880     },
881     /**
882      * Delete an event listener.
883      * @param {String} [type] Type of the events.
884      * @param {Function(e:enchant.Event)} listener Event listener to be deleted.
885      */
886     removeEventListener: function(type, listener) {
887         var listeners = this._listeners[type];
888         if (listeners != null) {
889             var i = listeners.indexOf(listener);
890             if (i !== -1) {
891                 listeners.splice(i, 1);
892             }
893         }
894     },
895     /**
896      * Clear all defined event listeners of a given type.
897      * If no type is given, all listeners will be removed.
898      * @param {String} type Type of the events.
899      */
900     clearEventListener: function(type) {
901         if (type != null) {
902             delete this._listeners[type];
903         } else {
904             this._listeners = {};
905         }
906     },
907     /**
908      * Issue an event.
909      * @param {enchant.Event} e Event to be issued.
910      */
911     dispatchEvent: function(e) {
912         e.target = this;
913         e.localX = e.x - this._offsetX;
914         e.localY = e.y - this._offsetY;
915         if (this['on' + e.type] != null){
916             this['on' + e.type](e);
917         }
918         var listeners = this._listeners[e.type];
919         if (listeners != null) {
920             listeners = listeners.slice();
921             for (var i = 0, len = listeners.length; i < len; i++) {
922                 listeners[i].call(this, e);
923             }
924         }
925     }
926 });
927 
928 (function() {
929     var core;
930     /**
931      * @scope enchant.Core.prototype
932      */
933     enchant.Core = enchant.Class.create(enchant.EventTarget, {
934         /**
935          * @name enchant.Core
936          * @class
937          * A class for controlling the core’s main loop and scenes.
938          *
939          * There can be only one instance at a time. When the
940          * constructor is executed while an instance exists, the
941          * existing instance will be overwritten. The existing instance
942          * can be accessed from {@link enchant.Core.instance}.
943          *
944          * @param {Number} [width=320] The width of the core viewport.
945          * @param {Number} [height=320] The height of the core viewport.
946          * @constructs
947          * @extends enchant.EventTarget
948          */
949         initialize: function(width, height) {
950             if (window.document.body === null) {
951                 // @TODO postpone initialization after window.onload
952                 throw new Error("document.body is null. Please excute 'new Core()' in window.onload.");
953             }
954 
955             enchant.EventTarget.call(this);
956             var initial = true;
957             if (core) {
958                 initial = false;
959                 core.stop();
960             }
961             core = enchant.Core.instance = this;
962 
963             this._calledTime = 0;
964             this._mousedownID = 0;
965             this._surfaceID = 0;
966             this._soundID = 0;
967 
968             this._scenes = [];
969 
970             width = width || 320;
971             height = height || 320;
972 
973             var stage = document.getElementById('enchant-stage');
974             var scale, sWidth, sHeight;
975             if (!stage) {
976                 stage = document.createElement('div');
977                 stage.id = 'enchant-stage';
978                 stage.style.position = 'absolute';
979 
980                 if (document.body.firstChild) {
981                     document.body.insertBefore(stage, document.body.firstChild);
982                 } else {
983                     document.body.appendChild(stage);
984                 }
985                 scale = Math.min(
986                     window.innerWidth / width,
987                     window.innerHeight / height
988                 );
989                 this._pageX = stage.getBoundingClientRect().left;
990                 this._pageY = stage.getBoundingClientRect().top;
991             } else {
992                 var style = window.getComputedStyle(stage);
993                 sWidth = parseInt(style.width, 10);
994                 sHeight = parseInt(style.height, 10);
995                 if (sWidth && sHeight) {
996                     scale = Math.min(
997                         sWidth / width,
998                         sHeight / height
999                     );
1000                 } else {
1001                     scale = 1;
1002                 }
1003                 while (stage.firstChild) {
1004                     stage.removeChild(stage.firstChild);
1005                 }
1006                 stage.style.position = 'relative';
1007 
1008                 var bounding = stage.getBoundingClientRect();
1009                 this._pageX = Math.round(window.scrollX || window.pageXOffset + bounding.left);
1010                 this._pageY = Math.round(window.scrollY || window.pageYOffset + bounding.top);
1011             }
1012             stage.style.fontSize = '12px';
1013             stage.style.webkitTextSizeAdjust = 'none';
1014             stage.style.webkitTapHighlightColor = 'rgba(0, 0, 0, 0)';
1015             this._element = stage;
1016 
1017             this.addEventListener('coreresize', this._oncoreresize);
1018 
1019             this._width = width;
1020             this._height = height;
1021             this.scale = scale;
1022 
1023             /**
1024              * The frame rate of the core.
1025              * @type Number
1026              */
1027             this.fps = 30;
1028             /**
1029              * The number of frames processed since the core was started.
1030              * @type Number
1031              */
1032             this.frame = 0;
1033             /**
1034              * Indicates whether or not the core can be executed.
1035              * @type Boolean
1036              */
1037             this.ready = false;
1038             /**
1039              * Indicates whether or not the core is currently running.
1040              * @type Boolean
1041              */
1042             this.running = false;
1043             /**
1044              * Object which stores loaded assets using their paths as keys.
1045              * @type Object
1046              */
1047             this.assets = {};
1048             var assets = this._assets = [];
1049             (function detectAssets(module) {
1050                 if (module.assets) {
1051                     enchant.Core.instance.preload(module.assets);
1052                 }
1053                 for (var prop in module) {
1054                     if (module.hasOwnProperty(prop)) {
1055                         if (typeof module[prop] === 'object' && module[prop] !== null && Object.getPrototypeOf(module[prop]) === Object.prototype) {
1056                             detectAssets(module[prop]);
1057                         }
1058                     }
1059                 }
1060             }(enchant));
1061 
1062             /**
1063              * The Scene which is currently displayed. This Scene is on top of the Scene stack.
1064              * @type enchant.Scene
1065              */
1066             this.currentScene = null;
1067             /**
1068              * The root Scene. The Scene at the bottom of the Scene stack.
1069              * @type enchant.Scene
1070              */
1071             this.rootScene = new enchant.Scene();
1072             this.pushScene(this.rootScene);
1073             /**
1074              * The Scene to be displayed during loading.
1075              * @type enchant.Scene
1076              */
1077             this.loadingScene = new enchant.LoadingScene();
1078 
1079             /**
1080              [/lang:ja]
1081              * Indicates whether or not {@link enchant.Core#start} has been called.
1082              [/lang]
1083              * @type Boolean
1084              * @private
1085              */
1086             this._activated = false;
1087 
1088             this._offsetX = 0;
1089             this._offsetY = 0;
1090 
1091             /**
1092              * Object that saves the current input state for the core.
1093              * @type Object
1094              */
1095             this.input = {};
1096 
1097             this.keyboardInputManager = new enchant.KeyboardInputManager(window.document, this.input);
1098             this.keyboardInputManager.addBroadcastTarget(this);
1099             this._keybind = this.keyboardInputManager._binds;
1100 
1101             if (!enchant.ENV.KEY_BIND_TABLE) {
1102                 enchant.ENV.KEY_BIND_TABLE = {};
1103             }
1104 
1105             for (var prop in enchant.ENV.KEY_BIND_TABLE) {
1106                 this.keybind(prop, enchant.ENV.KEY_BIND_TABLE[prop]);
1107             }
1108 
1109             if (initial) {
1110                 stage = enchant.Core.instance._element;
1111                 var evt;
1112                 document.addEventListener('keydown', function(e) {
1113                     core.dispatchEvent(new enchant.Event('keydown'));
1114                     if (enchant.ENV.PREVENT_DEFAULT_KEY_CODES.indexOf(e.keyCode) !== -1) {
1115                         e.preventDefault();
1116                         e.stopPropagation();
1117                     }
1118                 }, true);
1119 
1120                 if (enchant.ENV.TOUCH_ENABLED) {
1121                     stage.addEventListener('touchstart', function(e) {
1122                         var tagName = (e.target.tagName).toLowerCase();
1123                         if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
1124                             e.preventDefault();
1125                             if (!core.running) {
1126                                 e.stopPropagation();
1127                             }
1128                         }
1129                     }, true);
1130                     stage.addEventListener('touchmove', function(e) {
1131                         var tagName = (e.target.tagName).toLowerCase();
1132                         if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
1133                             e.preventDefault();
1134                             if (!core.running) {
1135                                 e.stopPropagation();
1136                             }
1137                         }
1138                     }, true);
1139                     stage.addEventListener('touchend', function(e) {
1140                         var tagName = (e.target.tagName).toLowerCase();
1141                         if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
1142                             e.preventDefault();
1143                             if (!core.running) {
1144                                 e.stopPropagation();
1145                             }
1146                         }
1147                     }, true);
1148                 }
1149                 stage.addEventListener('mousedown', function(e) {
1150                     var tagName = (e.target.tagName).toLowerCase();
1151                     if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
1152                         e.preventDefault();
1153                         core._mousedownID++;
1154                         if (!core.running) {
1155                             e.stopPropagation();
1156                         }
1157                     }
1158                 }, true);
1159                 stage.addEventListener('mousemove', function(e) {
1160                     var tagName = (e.target.tagName).toLowerCase();
1161                     if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
1162                         e.preventDefault();
1163                         if (!core.running) {
1164                             e.stopPropagation();
1165                         }
1166                     }
1167                 }, true);
1168                 stage.addEventListener('mouseup', function(e) {
1169                     var tagName = (e.target.tagName).toLowerCase();
1170                     if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
1171                         e.preventDefault();
1172                         if (!core.running) {
1173                             e.stopPropagation();
1174                         }
1175                     }
1176                 }, true);
1177                 core._touchEventTarget = {};
1178                 if (enchant.ENV.TOUCH_ENABLED) {
1179                     stage.addEventListener('touchstart', function(e) {
1180                         var core = enchant.Core.instance;
1181                         var evt = new enchant.Event(enchant.Event.TOUCH_START);
1182                         var touches = e.changedTouches;
1183                         var touch, target;
1184                         for (var i = 0, l = touches.length; i < l; i++) {
1185                             touch = touches[i];
1186                             evt._initPosition(touch.pageX, touch.pageY);
1187                             target = core.currentScene._determineEventTarget(evt);
1188                             core._touchEventTarget[touch.identifier] = target;
1189                             target.dispatchEvent(evt);
1190                         }
1191                     }, false);
1192                     stage.addEventListener('touchmove', function(e) {
1193                         var core = enchant.Core.instance;
1194                         var evt = new enchant.Event(enchant.Event.TOUCH_MOVE);
1195                         var touches = e.changedTouches;
1196                         var touch, target;
1197                         for (var i = 0, l = touches.length; i < l; i++) {
1198                             touch = touches[i];
1199                             target = core._touchEventTarget[touch.identifier];
1200                             if (target) {
1201                                 evt._initPosition(touch.pageX, touch.pageY);
1202                                 target.dispatchEvent(evt);
1203                             }
1204                         }
1205                     }, false);
1206                     stage.addEventListener('touchend', function(e) {
1207                         var core = enchant.Core.instance;
1208                         var evt = new enchant.Event(enchant.Event.TOUCH_END);
1209                         var touches = e.changedTouches;
1210                         var touch, target;
1211                         for (var i = 0, l = touches.length; i < l; i++) {
1212                             touch = touches[i];
1213                             target = core._touchEventTarget[touch.identifier];
1214                             if (target) {
1215                                 evt._initPosition(touch.pageX, touch.pageY);
1216                                 target.dispatchEvent(evt);
1217                                 delete core._touchEventTarget[touch.identifier];
1218                             }
1219                         }
1220                     }, false);
1221                 }
1222                 stage.addEventListener('mousedown', function(e) {
1223                     var core = enchant.Core.instance;
1224                     var evt = new enchant.Event(enchant.Event.TOUCH_START);
1225                     evt._initPosition(e.pageX, e.pageY);
1226                     var target = core.currentScene._determineEventTarget(evt);
1227                     core._touchEventTarget[core._mousedownID] = target;
1228                     target.dispatchEvent(evt);
1229                 }, false);
1230                 stage.addEventListener('mousemove', function(e) {
1231                     var core = enchant.Core.instance;
1232                     var evt = new enchant.Event(enchant.Event.TOUCH_MOVE);
1233                     evt._initPosition(e.pageX, e.pageY);
1234                     var target = core._touchEventTarget[core._mousedownID];
1235                     if (target) {
1236                         target.dispatchEvent(evt);
1237                     }
1238                 }, false);
1239                 stage.addEventListener('mouseup', function(e) {
1240                     var core = enchant.Core.instance;
1241                     var evt = new enchant.Event(enchant.Event.TOUCH_END);
1242                     evt._initPosition(e.pageX, e.pageY);
1243                     var target = core._touchEventTarget[core._mousedownID];
1244                     if (target) {
1245                         target.dispatchEvent(evt);
1246                     }
1247                     delete core._touchEventTarget[core._mousedownID];
1248                 }, false);
1249             }
1250         },
1251         /**
1252          * The width of the core screen.
1253          * @type Number
1254          */
1255         width: {
1256             get: function() {
1257                 return this._width;
1258             },
1259             set: function(w) {
1260                 this._width = w;
1261                 this._dispatchCoreResizeEvent();
1262             }
1263         },
1264         /**
1265          * The height of the core screen.
1266          * @type Number
1267          */
1268         height: {
1269             get: function() {
1270                 return this._height;
1271             },
1272             set: function(h) {
1273                 this._height = h;
1274                 this._dispatchCoreResizeEvent();
1275             }
1276         },
1277         /**
1278          * The scaling of the core rendering.
1279          * @type Number
1280          */
1281         scale: {
1282             get: function() {
1283                 return this._scale;
1284             },
1285             set: function(s) {
1286                 this._scale = s;
1287                 this._dispatchCoreResizeEvent();
1288             }
1289         },
1290         _dispatchCoreResizeEvent: function() {
1291             var e = new enchant.Event('coreresize');
1292             e.width = this._width;
1293             e.height = this._height;
1294             e.scale = this._scale;
1295             this.dispatchEvent(e);
1296         },
1297         _oncoreresize: function(e) {
1298             this._element.style.width = Math.floor(this._width * this._scale) + 'px';
1299             this._element.style.height = Math.floor(this._height * this._scale) + 'px';
1300             var scene;
1301             for (var i = 0, l = this._scenes.length; i < l; i++) {
1302                 scene = this._scenes[i];
1303                 scene.dispatchEvent(e);
1304             }
1305         },
1306         /**
1307          * File preloader.
1308          *
1309          * Loads the files specified in the parameters when
1310          * {@link enchant.Core#start} is called.
1311          * When all files are loaded, a {@link enchant.Event.LOAD}
1312          * event is dispatched from the Core object. Depending on the
1313          * type of each file, different objects will be created and
1314          * stored in {@link enchant.Core#assets} Variable.
1315          *
1316          * When an image file is loaded, a {@link enchant.Surface} is
1317          * created. If a sound file is loaded, an {@link enchant.Sound}
1318          * object is created. Any other file type will be accessible
1319          * as a string.
1320          *
1321          * In addition, because this Surface object is created with
1322          * {@link enchant.Surface.load}, it is not possible to
1323          * manipulate the image directly.
1324          * Refer to the {@link enchant.Surface.load} documentation.
1325          *
1326          * @example
1327          * core.preload('player.gif');
1328          * core.onload = function() {
1329          *     var sprite = new Sprite(32, 32);
1330          *     sprite.image = core.assets['player.gif']; // Access via path
1331          *     ...
1332          * };
1333          * core.start();
1334          *
1335          * @param {...String|String[]} assets Path of images to be preloaded.
1336          * Multiple settings possible.
1337          * @return {enchant.Core} this
1338          */
1339         preload: function(assets) {
1340             var a;
1341             if (!(assets instanceof Array)) {
1342                 if (typeof assets === 'object') {
1343                     a = [];
1344                     for (var name in assets) {
1345                         if (assets.hasOwnProperty(name)) {
1346                             a.push([ assets[name], name ]);
1347                         }
1348                     }
1349                     assets = a;
1350                 } else {
1351                     assets = Array.prototype.slice.call(arguments);
1352                 }
1353             }
1354             Array.prototype.push.apply(this._assets, assets);
1355             return this;
1356         },
1357         /**
1358          * Loads a file.
1359          *
1360          * @param {String} src File path of the resource to be loaded.
1361          * @param {String} [alias] Name you want to designate for the resource to be loaded.
1362          * @param {Function} [callback] Function to be called if the file loads successfully.
1363          * @param {Function} [onerror] Function to be called if the file fails to load.
1364          * @return {enchant.Deferred}
1365          */
1366         load: function(src, alias, callback, onerror) {
1367             var assetName;
1368             if (typeof arguments[1] === 'string') {
1369                 assetName = alias;
1370                 callback = callback || function() {};
1371                 onerror = onerror || function() {};
1372             } else {
1373                 assetName = src;
1374                 var tempCallback = callback;
1375                 callback = arguments[1] || function() {};
1376                 onerror = tempCallback || function() {};
1377             }
1378 
1379             var ext = enchant.Core.findExt(src);
1380 
1381             return enchant.Deferred.next(function() {
1382                 var d = new enchant.Deferred();
1383                 var _callback = function(e) {
1384                     d.call(e);
1385                     callback.call(this, e);
1386                 };
1387                 var _onerror = function(e) {
1388                     d.fail(e);
1389                     onerror.call(this, e);
1390                 };
1391                 if (enchant.Core._loadFuncs[ext]) {
1392                     enchant.Core.instance.assets[assetName] = enchant.Core._loadFuncs[ext](src, ext, _callback, _onerror);
1393                 } else {
1394                     var req = new XMLHttpRequest();
1395                     req.open('GET', src, true);
1396                     req.onreadystatechange = function() {
1397                         if (req.readyState === 4) {
1398                             if (req.status !== 200 && req.status !== 0) {
1399                                 // throw new Error(req.status + ': ' + 'Cannot load an asset: ' + src);
1400                                 var e = new enchant.Event('error');
1401                                 e.message = req.status + ': ' + 'Cannot load an asset: ' + src;
1402                                 _onerror.call(enchant.Core.instance, e);
1403                             }
1404 
1405                             var type = req.getResponseHeader('Content-Type') || '';
1406                             if (type.match(/^image/)) {
1407                                 core.assets[assetName] = enchant.Surface.load(src, _callback, _onerror);
1408                             } else if (type.match(/^audio/)) {
1409                                 core.assets[assetName] = enchant.Sound.load(src, type, _callback, _onerror);
1410                             } else {
1411                                 core.assets[assetName] = req.responseText;
1412                                 _callback.call(enchant.Core.instance, new enchant.Event('load'));
1413                             }
1414                         }
1415                     };
1416                     req.send(null);
1417                 }
1418                 return d;
1419             });
1420         },
1421         /**
1422          * Start the core.
1423          *
1424          * Sets the framerate of the {@link enchant.Core#currentScene}
1425          * according to the value stored in {@link enchant.core#fps}. If
1426          * there are images to preload, loading will begin and the
1427          * loading screen will be displayed.
1428          * @return {enchant.Deferred}
1429          */
1430         start: function(deferred) {
1431             var onloadTimeSetter = function() {
1432                 this.frame = 0;
1433                 this.removeEventListener('load', onloadTimeSetter);
1434             };
1435             this.addEventListener('load', onloadTimeSetter);
1436 
1437             this.currentTime = window.getTime();
1438             this.running = true;
1439             this.ready = true;
1440 
1441             if (!this._activated) {
1442                 this._activated = true;
1443                 if (enchant.ENV.BROWSER === 'mobilesafari' &&
1444                     enchant.ENV.USE_WEBAUDIO &&
1445                     enchant.ENV.USE_TOUCH_TO_START_SCENE) {
1446                     var d = new enchant.Deferred();
1447                     var scene = this._createTouchToStartScene();
1448                     scene.addEventListener(enchant.Event.TOUCH_START, function waitTouch() {
1449                         this.removeEventListener(enchant.Event.TOUCH_START, waitTouch);
1450                         var a = new enchant.WebAudioSound();
1451                         a.buffer = enchant.WebAudioSound.audioContext.createBuffer(1, 1, 48000);
1452                         a.play();
1453                         core.removeScene(scene);
1454                         core.start(d);
1455                     }, false);
1456                     core.pushScene(scene);
1457                     return d;
1458                 }
1459             }
1460 
1461             this._requestNextFrame(0);
1462 
1463             var ret = this._requestPreload()
1464                 .next(function() {
1465                     enchant.Core.instance.loadingScene.dispatchEvent(new enchant.Event(enchant.Event.LOAD));
1466                 });
1467 
1468             if (deferred) {
1469                 ret.next(function(arg) {
1470                     deferred.call(arg);
1471                 })
1472                 .error(function(arg) {
1473                     deferred.fail(arg);
1474                 });
1475             }
1476 
1477             return ret;
1478         },
1479         _requestPreload: function() {
1480             var o = {};
1481             var loaded = 0,
1482                 len = 0,
1483                 loadFunc = function() {
1484                     var e = new enchant.Event('progress');
1485                     e.loaded = ++loaded;
1486                     e.total = len;
1487                     core.loadingScene.dispatchEvent(e);
1488                 };
1489             this._assets
1490                 .reverse()
1491                 .forEach(function(asset) {
1492                     var src, name;
1493                     if (asset instanceof Array) {
1494                         src = asset[0];
1495                         name = asset[1];
1496                     } else {
1497                         src = name = asset;
1498                     }
1499                     if (!o[name]) {
1500                         o[name] = this.load(src, name, loadFunc);
1501                         len++;
1502                     }
1503                 }, this);
1504 
1505             this.pushScene(this.loadingScene);
1506             return enchant.Deferred.parallel(o);
1507         },
1508         _createTouchToStartScene: function() {
1509             var label = new enchant.Label('Touch to Start'),
1510                 size = Math.round(core.width / 10),
1511                 scene = new enchant.Scene();
1512 
1513             label.color = '#fff';
1514             label.font = (size - 1) + 'px bold Helvetica,Arial,sans-serif';
1515             label.textAlign = 'center';
1516             label.width = core.width;
1517             label.height = label._boundHeight;
1518             label.y = (core.height - label.height) / 2;
1519 
1520             scene.backgroundColor = '#000';
1521             scene.addChild(label);
1522 
1523             return scene;
1524         },
1525         /**
1526          * Start application in debug mode.
1527          *
1528          * Core debug mode can be turned on even if the
1529          * {@link enchant.Core#_debug} flag is already set to true.
1530          * @return {enchant.Deferred}
1531          */
1532         debug: function() {
1533             this._debug = true;
1534             return this.start();
1535         },
1536         actualFps: {
1537             get: function() {
1538                 return this._actualFps || this.fps;
1539             }
1540         },
1541         /**
1542          * Requests the next frame.
1543          * @param {Number} delay Amount of time to delay before calling requestAnimationFrame.
1544          * @private
1545          */
1546         _requestNextFrame: function(delay) {
1547             if (!this.ready) {
1548                 return;
1549             }
1550             if (this.fps >= 60 || delay <= 16) {
1551                 this._calledTime = window.getTime();
1552                 window.requestAnimationFrame(this._callTick);
1553             } else {
1554                 setTimeout(function() {
1555                     var core = enchant.Core.instance;
1556                     core._calledTime = window.getTime();
1557                     window.requestAnimationFrame(core._callTick);
1558                 }, Math.max(0, delay));
1559             }
1560         },
1561         /**
1562          * Calls {@link enchant.Core#_tick}.
1563          * @param {Number} time
1564          * @private
1565          */
1566         _callTick: function(time) {
1567             enchant.Core.instance._tick(time);
1568         },
1569         _tick: function(time) {
1570             var e = new enchant.Event('enterframe');
1571             var now = window.getTime();
1572             var elapsed = e.elapsed = now - this.currentTime;
1573             this.currentTime = now;
1574 
1575             this._actualFps = elapsed > 0 ? (1000 / elapsed) : 0;
1576 
1577             var nodes = this.currentScene.childNodes.slice();
1578             var push = Array.prototype.push;
1579             while (nodes.length) {
1580                 var node = nodes.pop();
1581                 node.age++;
1582                 node.dispatchEvent(e);
1583                 if (node.childNodes) {
1584                     push.apply(nodes, node.childNodes);
1585                 }
1586             }
1587 
1588             this.currentScene.age++;
1589             this.currentScene.dispatchEvent(e);
1590             this.dispatchEvent(e);
1591 
1592             this.dispatchEvent(new enchant.Event('exitframe'));
1593             this.frame++;
1594             now = window.getTime();
1595             
1596             this._requestNextFrame(1000 / this.fps - (now - this._calledTime));
1597         },
1598         getTime: function() {
1599             return window.getTime();
1600         },
1601         /**
1602          * Stops the core.
1603          *
1604          * The frame will not be updated, and player input will not be accepted anymore.
1605          * Core can be restarted using {@link enchant.Core#resume}.
1606          */
1607         stop: function() {
1608             this.ready = false;
1609             this.running = false;
1610         },
1611         /**
1612          * Stops the core.
1613          *
1614          * The frame will not be updated, and player input will not be accepted anymore.
1615          * Core can be started again using {@link enchant.Core#resume}.
1616          */
1617         pause: function() {
1618             this.ready = false;
1619         },
1620         /**
1621          * Resumes core operations.
1622          */
1623         resume: function() {
1624             if (this.ready) {
1625                 return;
1626             }
1627             this.currentTime = window.getTime();
1628             this.ready = true;
1629             this.running = true;
1630             this._requestNextFrame(0);
1631         },
1632 
1633         /**
1634          * Switches to a new Scene.
1635          *
1636          * Scenes are controlled using a stack, with the top scene on
1637          * the stack being the one displayed.
1638          * When {@link enchant.Core#pushScene} is executed, the Scene is
1639          * placed top of the stack. Frames will be only updated for the
1640          * Scene which is on the top of the stack.
1641          *
1642          * @param {enchant.Scene} scene The new scene to display.
1643          * @return {enchant.Scene} The new Scene.
1644          */
1645         pushScene: function(scene) {
1646             this._element.appendChild(scene._element);
1647             if (this.currentScene) {
1648                 this.currentScene.dispatchEvent(new enchant.Event('exit'));
1649             }
1650             this.currentScene = scene;
1651             this.currentScene.dispatchEvent(new enchant.Event('enter'));
1652             return this._scenes.push(scene);
1653         },
1654         /**
1655          * Ends the current Scene and returns to the previous Scene.
1656          *
1657          * Scenes are controlled using a stack, with the top scene on
1658          * the stack being the one displayed.
1659          * When {@link enchant.Core#popScene} is executed, the Scene at
1660          * the top of the stack is removed and returned.
1661          *
1662          * @return {enchant.Scene} Removed Scene.
1663          */
1664         popScene: function() {
1665             if (this.currentScene === this.rootScene) {
1666                 return this.currentScene;
1667             }
1668             this._element.removeChild(this.currentScene._element);
1669             this.currentScene.dispatchEvent(new enchant.Event('exit'));
1670             this.currentScene = this._scenes[this._scenes.length - 2];
1671             this.currentScene.dispatchEvent(new enchant.Event('enter'));
1672             return this._scenes.pop();
1673         },
1674         /**
1675          * Overwrites the current Scene with a new Scene.
1676          *
1677          * Executes {@link enchant.Core#popScene} and {@link enchant.Core#pushScene}
1678          * one after another to replace the current scene with the new scene.
1679          *
1680          * @param {enchant.Scene} scene The new scene with which to replace the current scene.
1681          * @return {enchant.Scene} The new Scene.
1682          */
1683         replaceScene: function(scene) {
1684             this.popScene();
1685             return this.pushScene(scene);
1686         },
1687         /**
1688          * Removes a Scene from the Scene stack.
1689          *
1690          * If the scene passed in as a parameter is not the current
1691          * scene, the stack will be searched for the given scene.
1692          * If the given scene does not exist anywhere in the stack,
1693          * this method returns null.
1694          *
1695          * @param {enchant.Scene} scene Scene to be removed.
1696          * @return {enchant.Scene} The deleted Scene.
1697          */
1698         removeScene: function(scene) {
1699             if (this.currentScene === scene) {
1700                 return this.popScene();
1701             } else {
1702                 var i = this._scenes.indexOf(scene);
1703                 if (i !== -1) {
1704                     this._scenes.splice(i, 1);
1705                     this._element.removeChild(scene._element);
1706                     return scene;
1707                 } else {
1708                     return null;
1709                 }
1710             }
1711         },
1712         _buttonListener: function(e) {
1713             this.currentScene.dispatchEvent(e);
1714         },
1715         /**
1716          * Bind a key code to an enchant.js button.
1717          *
1718          * Binds the given key code to the given enchant.js button
1719          * ('left', 'right', 'up', 'down', 'a', 'b').
1720          *
1721          * @param {Number} key Key code for the button to be bound.
1722          * @param {String} button An enchant.js button.
1723          * @return {enchant.Core} this
1724          */
1725         keybind: function(key, button) {
1726             this.keyboardInputManager.keybind(key, button);
1727             this.addEventListener(button + 'buttondown', this._buttonListener);
1728             this.addEventListener(button + 'buttonup', this._buttonListener);
1729             return this;
1730         },
1731         /**
1732          * Delete the key binding for the given key.
1733          *
1734          * @param {Number} key Key code whose binding is to be deleted.
1735          * @return {enchant.Core} this
1736          */
1737         keyunbind: function(key) {
1738             var button = this._keybind[key];
1739             this.keyboardInputManager.keyunbind(key);
1740             this.removeEventListener(button + 'buttondown', this._buttonListener);
1741             this.removeEventListener(button + 'buttonup', this._buttonListener);
1742             return this;
1743         },
1744         changeButtonState: function(button, bool) {
1745             this.keyboardInputManager.changeState(button, bool);
1746         },
1747         /**
1748          * Get the core time (not actual) elapsed since {@link enchant.Core#start} was called.
1749          * @return {Number} Time elapsed (in seconds).
1750          */
1751         getElapsedTime: function() {
1752             return this.frame / this.fps;
1753         }
1754     });
1755 
1756     /**
1757      * Functions for loading assets of the corresponding file type.
1758      * The loading functions must take the file path, extension and
1759      * callback function as arguments, then return the appropriate
1760      * class instance.
1761      * @static
1762      * @private
1763      * @type Object
1764      */
1765     enchant.Core._loadFuncs = {};
1766     enchant.Core._loadFuncs['jpg'] =
1767         enchant.Core._loadFuncs['jpeg'] =
1768             enchant.Core._loadFuncs['gif'] =
1769                 enchant.Core._loadFuncs['png'] =
1770                     enchant.Core._loadFuncs['bmp'] = function(src, ext, callback, onerror) {
1771                         return enchant.Surface.load(src, callback, onerror);
1772                     };
1773     enchant.Core._loadFuncs['mp3'] =
1774         enchant.Core._loadFuncs['aac'] =
1775             enchant.Core._loadFuncs['m4a'] =
1776                 enchant.Core._loadFuncs['wav'] =
1777                     enchant.Core._loadFuncs['ogg'] = function(src, ext, callback, onerror) {
1778                         return enchant.Sound.load(src, 'audio/' + ext, callback, onerror);
1779                     };
1780 
1781     /**
1782      * Get the file extension from a path.
1783      * @param {String} path file path.
1784      * @return {*}
1785      */
1786     enchant.Core.findExt = function(path) {
1787         var matched = path.match(/\.\w+$/);
1788         if (matched && matched.length > 0) {
1789             return matched[0].slice(1).toLowerCase();
1790         }
1791 
1792         // for data URI
1793         if (path.indexOf('data:') === 0) {
1794             return path.split(/[\/;]/)[1].toLowerCase();
1795         }
1796         return null;
1797     };
1798 
1799     /**
1800      * The current Core instance.
1801      * @type enchant.Core
1802      * @static
1803      */
1804     enchant.Core.instance = null;
1805 }());
1806 
1807 /**
1808  * @name enchant.Game
1809  * @class
1810  * enchant.Game is moved to {@link enchant.Core} from v0.6
1811  * @deprecated
1812  */
1813 enchant.Game = enchant.Core;
1814 
1815 /**
1816  * @scope enchant.InputManager.prototype
1817  */
1818 enchant.InputManager = enchant.Class.create(enchant.EventTarget, {
1819     /**
1820      * @name enchant.InputManager
1821      * @class
1822      * Class for managing input.
1823      * @param {*} valueStore object that store input state.
1824      * @param {*} [source=this] source that will be added to event object.
1825      * @constructs
1826      * @extends enchant.EventTarget
1827      */
1828     initialize: function(valueStore, source) {
1829         enchant.EventTarget.call(this);
1830 
1831         /**
1832          * Array that store event target.
1833          * @type enchant.EventTarget[]
1834          */
1835         this.broadcastTarget = [];
1836         /**
1837          * Object that store input state.
1838          * @type Object
1839          */
1840         this.valueStore = valueStore;
1841         /**
1842          * source that will be added to event object.
1843          * @type Object
1844          */
1845         this.source = source || this;
1846 
1847         this._binds = {};
1848 
1849         this._stateHandler = function(e) {
1850             var id = e.source.identifier;
1851             var name = this._binds[id];
1852             this.changeState(name, e.data);
1853         }.bind(this);
1854     },
1855     /**
1856      * Name specified input.
1857      * Input can be watched by flag or event.
1858      * @param {enchant.InputSource} inputSource input source.
1859      * @param {String} name input name.
1860      */
1861     bind: function(inputSource, name) {
1862         inputSource.addEventListener(enchant.Event.INPUT_STATE_CHANGED, this._stateHandler);
1863         this._binds[inputSource.identifier] = name;
1864     },
1865     /**
1866      * Remove binded name.
1867      * @param {enchant.InputSource} inputSource input source.
1868      */
1869     unbind: function(inputSource) {
1870         inputSource.removeEventListener(enchant.Event.INPUT_STATE_CHANGED, this._stateHandler);
1871         delete this._binds[inputSource.identifier];
1872     },
1873     /**
1874      * Add event target.
1875      * @param {enchant.EventTarget} eventTarget broadcast target.
1876      */
1877     addBroadcastTarget: function(eventTarget) {
1878         var i = this.broadcastTarget.indexOf(eventTarget);
1879         if (i === -1) {
1880             this.broadcastTarget.push(eventTarget);
1881         }
1882     },
1883     /**
1884      * Remove event target.
1885      * @param {enchant.EventTarget} eventTarget broadcast target.
1886      */
1887     removeBroadcastTarget: function(eventTarget) {
1888         var i = this.broadcastTarget.indexOf(eventTarget);
1889         if (i !== -1) {
1890             this.broadcastTarget.splice(i, 1);
1891         }
1892     },
1893     /**
1894      * Dispatch event to {@link enchant.InputManager#broadcastTarget}.
1895      * @param {enchant.Event} e event.
1896      */
1897     broadcastEvent: function(e) {
1898         var target = this.broadcastTarget;
1899         for (var i = 0, l = target.length; i < l; i++) {
1900             target[i].dispatchEvent(e);
1901         }
1902     },
1903     /**
1904      * Change state of input.
1905      * @param {String} name input name.
1906      * @param {*} data input state.
1907      */
1908     changeState: function(name, data) {
1909     }
1910 });
1911 
1912 /**
1913  * @scope enchant.InputSource.prototype
1914  */
1915 enchant.InputSource = enchant.Class.create(enchant.EventTarget, {
1916     /**
1917      * @name enchant.InputSource
1918      * @class
1919      * Class that wrap input.
1920      * @param {String} identifier identifier of InputSource.
1921      * @constructs
1922      * @extends enchant.EventTarget
1923      */
1924     initialize: function(identifier) {
1925         enchant.EventTarget.call(this);
1926         /**
1927          * identifier of InputSource.
1928          * @type String
1929          */
1930         this.identifier = identifier;
1931     },
1932     /**
1933      * Notify state change by event.
1934      * @param {*} data state.
1935      */
1936     notifyStateChange: function(data) {
1937         var e = new enchant.Event(enchant.Event.INPUT_STATE_CHANGED);
1938         e.data = data;
1939         e.source = this;
1940         this.dispatchEvent(e);
1941     }
1942 });
1943 
1944 /**
1945  * @scope enchant.BinaryInputManager.prototype
1946  */
1947 enchant.BinaryInputManager = enchant.Class.create(enchant.InputManager, {
1948     /**
1949      * @name enchant.BinaryInputManager
1950      * @class
1951      * Class for managing input.
1952      * @param {*} flagStore object that store input flag.
1953      * @param {String} activeEventNameSuffix event name suffix.
1954      * @param {String} inactiveEventNameSuffix event name suffix.
1955      * @param {*} [source=this] source that will be added to event object.
1956      * @constructs
1957      * @extends enchant.InputManager
1958      */
1959     initialize: function(flagStore, activeEventNameSuffix, inactiveEventNameSuffix, source) {
1960         enchant.InputManager.call(this, flagStore, source);
1961         /**
1962          * The number of active inputs.
1963          * @type Number
1964          */
1965         this.activeInputsNum = 0;
1966         /**
1967          * event name suffix that dispatched by BinaryInputManager.
1968          * @type String
1969          */
1970         this.activeEventNameSuffix = activeEventNameSuffix;
1971         /**
1972          * event name suffix that dispatched by BinaryInputManager.
1973          * @type String
1974          */
1975         this.inactiveEventNameSuffix = inactiveEventNameSuffix;
1976     },
1977     /**
1978      * Name specified input.
1979      * @param {enchant.BinaryInputSource} inputSource input source.
1980      * @param {String} name input name.
1981      * @see enchant.InputManager#bind
1982      */
1983     bind: function(binaryInputSource, name) {
1984         enchant.InputManager.prototype.bind.call(this, binaryInputSource, name);
1985         this.valueStore[name] = false;
1986     },
1987     /**
1988      * Remove binded name.
1989      * @param {enchant.BinaryInputSource} inputSource input source.
1990      * @see enchant.InputManager#unbind
1991      */
1992     unbind: function(binaryInputSource) {
1993         var name = this._binds[binaryInputSource.identifier];
1994         enchant.InputManager.prototype.unbind.call(this, binaryInputSource);
1995         delete this.valueStore[name];
1996     },
1997     /**
1998      * Change state of input.
1999      * @param {String} name input name.
2000      * @param {Boolean} bool input state.
2001      */
2002     changeState: function(name, bool) {
2003         if (bool) {
2004             this._down(name);
2005         } else {
2006             this._up(name);
2007         }
2008     },
2009     _down: function(name) {
2010         var inputEvent;
2011         if (!this.valueStore[name]) {
2012             this.valueStore[name] = true;
2013             inputEvent = new enchant.Event((this.activeInputsNum++) ? 'inputchange' : 'inputstart');
2014             inputEvent.source = this.source;
2015             this.broadcastEvent(inputEvent);
2016         }
2017         var downEvent = new enchant.Event(name + this.activeEventNameSuffix);
2018         downEvent.source = this.source;
2019         this.broadcastEvent(downEvent);
2020     },
2021     _up: function(name) {
2022         var inputEvent;
2023         if (this.valueStore[name]) {
2024             this.valueStore[name] = false;
2025             inputEvent = new enchant.Event((--this.activeInputsNum) ? 'inputchange' : 'inputend');
2026             inputEvent.source = this.source;
2027             this.broadcastEvent(inputEvent);
2028         }
2029         var upEvent = new enchant.Event(name + this.inactiveEventNameSuffix);
2030         upEvent.source = this.source;
2031         this.broadcastEvent(upEvent);
2032     }
2033 });
2034 
2035 /**
2036  * @scope enchant.BinaryInputSource.prototype
2037  */
2038 enchant.BinaryInputSource = enchant.Class.create(enchant.InputSource, {
2039     /**
2040      * @name enchant.BinaryInputSource
2041      * @class
2042      * Class that wrap binary input.
2043      * @param {String} identifier identifier of BinaryInputSource.
2044      * @constructs
2045      * @extends enchant.InputSource
2046      */
2047     initialize: function(identifier) {
2048         enchant.InputSource.call(this, identifier);
2049     }
2050 });
2051 
2052 /**
2053  * @scope enchant.KeyboardInputManager.prototype
2054  */
2055 enchant.KeyboardInputManager = enchant.Class.create(enchant.BinaryInputManager, {
2056     /**
2057      * @name enchant.KeyboardInputManager
2058      * @class
2059      * Class that manage keyboard input.
2060      * @param {HTMLElement} dom element that will be watched.
2061      * @param {*} flagStore object that store input flag.
2062      * @constructs
2063      * @extends enchant.BinaryInputManager
2064      */
2065     initialize: function(domElement, flagStore) {
2066         enchant.BinaryInputManager.call(this, flagStore, 'buttondown', 'buttonup');
2067         this._attachDOMEvent(domElement, 'keydown', true);
2068         this._attachDOMEvent(domElement, 'keyup', false);
2069     },
2070     /**
2071      * Call {@link enchant.BinaryInputManager#bind} with BinaryInputSource equivalent of key code.
2072      * @param {Number} keyCode key code.
2073      * @param {String} name input name.
2074      */
2075     keybind: function(keyCode, name) {
2076         this.bind(enchant.KeyboardInputSource.getByKeyCode('' + keyCode), name);
2077     },
2078     /**
2079      * Call {@link enchant.BinaryInputManager#unbind} with BinaryInputSource equivalent of key code.
2080      * @param {Number} keyCode key code.
2081      */
2082     keyunbind: function(keyCode) {
2083         this.unbind(enchant.KeyboardInputSource.getByKeyCode('' + keyCode));
2084     },
2085     _attachDOMEvent: function(domElement, eventType, state) {
2086         domElement.addEventListener(eventType, function(e) {
2087             var core = enchant.Core.instance;
2088             if (!core || !core.running) {
2089                 return;
2090             }
2091             var code = e.keyCode;
2092             var source = enchant.KeyboardInputSource._instances[code];
2093             if (source) {
2094                 source.notifyStateChange(state);
2095             }
2096         }, true);
2097     }
2098 });
2099 
2100 /**
2101  * @scope enchant.KeyboardInputSource.prototype
2102  */
2103 enchant.KeyboardInputSource = enchant.Class.create(enchant.BinaryInputSource, {
2104     /**
2105      * @name enchant.KeyboardInputSource
2106      * @class
2107      * @param {String} keyCode key code of BinaryInputSource.
2108      * @constructs
2109      * @extends enchant.BinaryInputSource
2110      */
2111     initialize: function(keyCode) {
2112         enchant.BinaryInputSource.call(this, keyCode);
2113     }
2114 });
2115 /**
2116  * @private
2117  */
2118 enchant.KeyboardInputSource._instances = {};
2119 /**
2120  * @static
2121  * Get the instance by key code.
2122  * @param {Number} keyCode key code.
2123  * @return {enchant.KeyboardInputSource} instance.
2124  */
2125 enchant.KeyboardInputSource.getByKeyCode = function(keyCode) {
2126     if (!this._instances[keyCode]) {
2127         this._instances[keyCode] = new enchant.KeyboardInputSource(keyCode);
2128     }
2129     return this._instances[keyCode];
2130 };
2131 
2132 /**
2133  * @scope enchant.Node.prototype
2134  */
2135 enchant.Node = enchant.Class.create(enchant.EventTarget, {
2136     /**
2137      * @name enchant.Node
2138      * @class
2139      * Base class for objects in the display tree which is rooted at a Scene.
2140      * Not to be used directly.
2141      * @constructs
2142      * @extends enchant.EventTarget
2143      */
2144     initialize: function() {
2145         enchant.EventTarget.call(this);
2146 
2147         this._dirty = false;
2148 
2149         this._matrix = [ 1, 0, 0, 1, 0, 0 ];
2150 
2151         this._x = 0;
2152         this._y = 0;
2153         this._offsetX = 0;
2154         this._offsetY = 0;
2155 
2156         /**
2157          * The age (frames) of this node which will be increased before this node receives {@link enchant.Event.ENTER_FRAME} event.
2158          * @type Number
2159          */
2160         this.age = 0;
2161 
2162         /**
2163          * Parent Node of this Node.
2164          * @type enchant.Group
2165          */
2166         this.parentNode = null;
2167         /**
2168          * Scene to which Node belongs.
2169          * @type enchant.Scene
2170          */
2171         this.scene = null;
2172 
2173         this.addEventListener('touchstart', function(e) {
2174             if (this.parentNode) {
2175                 this.parentNode.dispatchEvent(e);
2176             }
2177         });
2178         this.addEventListener('touchmove', function(e) {
2179             if (this.parentNode) {
2180                 this.parentNode.dispatchEvent(e);
2181             }
2182         });
2183         this.addEventListener('touchend', function(e) {
2184             if (this.parentNode) {
2185                 this.parentNode.dispatchEvent(e);
2186             }
2187         });
2188 
2189         // Nodeが生成される際に, tl プロパティに Timeline オブジェクトを追加している.
2190         if (enchant.ENV.USE_ANIMATION) {
2191             this.tl = new enchant.Timeline(this);
2192         }
2193     },
2194     /**
2195      * Move the Node to the given target location.
2196      * @param {Number} x Target x coordinates.
2197      * @param {Number} y Target y coordinates.
2198      */
2199     moveTo: function(x, y) {
2200         this.x = x;
2201         this.y = y;
2202     },
2203     /**
2204      * Move the Node relative to its current position.
2205      * @param {Number} x x axis movement distance.
2206      * @param {Number} y y axis movement distance.
2207      */
2208     moveBy: function(x, y) {
2209         this.x += x;
2210         this.y += y;
2211     },
2212     /**
2213      * x coordinates of the Node.
2214      * @type Number
2215      */
2216     x: {
2217         get: function() {
2218             return this._x;
2219         },
2220         set: function(x) {
2221             if(this._x !== x) {
2222                 this._x = x;
2223                 this._dirty = true;
2224             }
2225         }
2226     },
2227     /**
2228      * y coordinates of the Node.
2229      * @type Number
2230      */
2231     y: {
2232         get: function() {
2233             return this._y;
2234         },
2235         set: function(y) {
2236             if(this._y !== y) {
2237                 this._y = y;
2238                 this._dirty = true;
2239             }
2240         }
2241     },
2242     _updateCoordinate: function() {
2243         var node = this;
2244         var tree = [ node ];
2245         var parent = node.parentNode;
2246         var scene = this.scene;
2247         while (parent && node._dirty) {
2248             tree.unshift(parent);
2249             node = node.parentNode;
2250             parent = node.parentNode;
2251         }
2252         var matrix = enchant.Matrix.instance;
2253         var stack = matrix.stack;
2254         var mat = [];
2255         var newmat, ox, oy;
2256         stack.push(tree[0]._matrix);
2257         for (var i = 1, l = tree.length; i < l; i++) {
2258             node = tree[i];
2259             newmat = [];
2260             matrix.makeTransformMatrix(node, mat);
2261             matrix.multiply(stack[stack.length - 1], mat, newmat);
2262             node._matrix = newmat;
2263             stack.push(newmat);
2264             ox = (typeof node._originX === 'number') ? node._originX : node._width / 2 || 0;
2265             oy = (typeof node._originY === 'number') ? node._originY : node._height / 2 || 0;
2266             var vec = [ ox, oy ];
2267             matrix.multiplyVec(newmat, vec, vec);
2268             node._offsetX = vec[0] - ox;
2269             node._offsetY = vec[1] - oy;
2270             node._dirty = false;
2271         }
2272         matrix.reset();
2273     },
2274     remove: function() {
2275         if (this.parentNode) {
2276             this.parentNode.removeChild(this);
2277         }
2278         if (this.childNodes) {
2279             var childNodes = this.childNodes.slice();
2280             for(var i = childNodes.length-1; i >= 0; i--) {
2281                 childNodes[i].remove();
2282             }
2283         }
2284         
2285         this.clearEventListener();
2286     }
2287 });
2288 
2289 var _intersectBetweenClassAndInstance = function(Class, instance) {
2290     var ret = [];
2291     var c;
2292     for (var i = 0, l = Class.collection.length; i < l; i++) {
2293         c = Class.collection[i];
2294         if (instance._intersectOne(c)) {
2295             ret.push(c);
2296         }
2297     }
2298     return ret;
2299 };
2300 
2301 var _intersectBetweenClassAndClass = function(Class1, Class2) {
2302     var ret = [];
2303     var c1, c2;
2304     for (var i = 0, l = Class1.collection.length; i < l; i++) {
2305         c1 = Class1.collection[i];
2306         for (var j = 0, ll = Class2.collection.length; j < ll; j++) {
2307             c2 = Class2.collection[j];
2308             if (c1._intersectOne(c2)) {
2309                 ret.push([ c1, c2 ]);
2310             }
2311         }
2312     }
2313     return ret;
2314 };
2315 
2316 var _intersectStrictBetweenClassAndInstance = function(Class, instance) {
2317     var ret = [];
2318     var c;
2319     for (var i = 0, l = Class.collection.length; i < l; i++) {
2320         c = Class.collection[i];
2321         if (instance._intersectStrictOne(c)) {
2322             ret.push(c);
2323         }
2324     }
2325     return ret;
2326 };
2327 
2328 var _intersectStrictBetweenClassAndClass = function(Class1, Class2) {
2329     var ret = [];
2330     var c1, c2;
2331     for (var i = 0, l = Class1.collection.length; i < l; i++) {
2332         c1 = Class1.collection[i];
2333         for (var j = 0, ll = Class2.collection.length; j < ll; j++) {
2334             c2 = Class2.collection[j];
2335             if (c1._intersectStrictOne(c2)) {
2336                 ret.push([ c1, c2 ]);
2337             }
2338         }
2339     }
2340     return ret;
2341 };
2342 
2343 var _staticIntersect = function(other) {
2344     if (other instanceof enchant.Entity) {
2345         return _intersectBetweenClassAndInstance(this, other);
2346     } else if (typeof other === 'function' && other.collection) {
2347         return _intersectBetweenClassAndClass(this, other);
2348     }
2349     return false;
2350 };
2351 
2352 var _staticIntersectStrict = function(other) {
2353     if (other instanceof enchant.Entity) {
2354         return _intersectStrictBetweenClassAndInstance(this, other);
2355     } else if (typeof other === 'function' && other.collection) {
2356         return _intersectStrictBetweenClassAndClass(this, other);
2357     }
2358     return false;
2359 };
2360 
2361 var _nodePrototypeClearEventListener = enchant.Node.prototype.clearEventListener;
2362 
2363 /**
2364  * @scope enchant.Entity.prototype
2365  */
2366 enchant.Entity = enchant.Class.create(enchant.Node, {
2367     /**
2368      * @name enchant.Entity
2369      * @class
2370      * A class with objects displayed as DOM elements. Not to be used directly.
2371      * @constructs
2372      * @extends enchant.Node
2373      */
2374     initialize: function() {
2375         var core = enchant.Core.instance;
2376         enchant.Node.call(this);
2377 
2378         this._rotation = 0;
2379         this._scaleX = 1;
2380         this._scaleY = 1;
2381 
2382         this._touchEnabled = true;
2383         this._clipping = false;
2384 
2385         this._originX = null;
2386         this._originY = null;
2387 
2388         this._width = 0;
2389         this._height = 0;
2390         this._backgroundColor = null;
2391         this._debugColor = '#0000ff';
2392         this._opacity = 1;
2393         this._visible = true;
2394         this._buttonMode = null;
2395 
2396         this._style = {};
2397         this.__styleStatus = {};
2398 
2399         this._isContainedInCollection = false;
2400 
2401         /**
2402          * @type String
2403          */
2404         this.compositeOperation = null;
2405 
2406         /**
2407          * Defines this Entity as a button.
2408          * When touched or clicked the corresponding button event is dispatched.
2409          * Valid buttonModes are: left, right, up, down, a, b. 
2410          * @type String
2411          */
2412         this.buttonMode = null;
2413         /**
2414          * Indicates if this Entity is being clicked.
2415          * Only works when {@link enchant.Entity.buttonMode} is set.
2416          * @type Boolean
2417          */
2418         this.buttonPressed = false;
2419         this.addEventListener('touchstart', function() {
2420             if (!this.buttonMode) {
2421                 return;
2422             }
2423             this.buttonPressed = true;
2424             this.dispatchEvent(new enchant.Event(this.buttonMode + 'buttondown'));
2425             core.changeButtonState(this.buttonMode, true);
2426         });
2427         this.addEventListener('touchend', function() {
2428             if (!this.buttonMode) {
2429                 return;
2430             }
2431             this.buttonPressed = false;
2432             this.dispatchEvent(new enchant.Event(this.buttonMode + 'buttonup'));
2433             core.changeButtonState(this.buttonMode, false);
2434         });
2435 
2436         this.enableCollection();
2437     },
2438     /**
2439      * The width of the Entity.
2440      * @type Number
2441      */
2442     width: {
2443         get: function() {
2444             return this._width;
2445         },
2446         set: function(width) {
2447             if(this._width !== width) {
2448                 this._width = width;
2449                 this._dirty = true;
2450             }
2451         }
2452     },
2453     /**
2454      * The height of the Entity.
2455      * @type Number
2456      */
2457     height: {
2458         get: function() {
2459             return this._height;
2460         },
2461         set: function(height) {
2462             if(this._height !== height) {
2463                 this._height = height;
2464                 this._dirty = true;
2465             }
2466         }
2467     },
2468     /**
2469      * The Entity background color.
2470      * Must be provided in the same format as the CSS 'color' property.
2471      * @type String
2472      */
2473     backgroundColor: {
2474         get: function() {
2475             return this._backgroundColor;
2476         },
2477         set: function(color) {
2478             this._backgroundColor = color;
2479         }
2480     },
2481     /**
2482      * The Entity debug color.
2483      * Must be provided in the same format as the CSS 'color' property.
2484      * @type String
2485      */
2486     debugColor: {
2487         get: function() {
2488             return this._debugColor;
2489         },
2490         set: function(color) {
2491             this._debugColor = color;
2492         }
2493     },
2494     /**
2495      * The transparency of this entity.
2496      * Defines the transparency level from 0 to 1
2497      * (0 is completely transparent, 1 is completely opaque).
2498      * @type Number
2499      */
2500     opacity: {
2501         get: function() {
2502             return this._opacity;
2503         },
2504         set: function(opacity) {
2505             this._opacity = parseFloat(opacity);
2506         }
2507     },
2508     /**
2509      * Indicates whether or not to display this Entity.
2510      * @type Boolean
2511      */
2512     visible: {
2513         get: function() {
2514             return this._visible;
2515         },
2516         set: function(visible) {
2517             this._visible = visible;
2518         }
2519     },
2520     /**
2521      * Indicates whether or not this Entity can be touched.
2522      * @type Boolean
2523      */
2524     touchEnabled: {
2525         get: function() {
2526             return this._touchEnabled;
2527         },
2528         set: function(enabled) {
2529             this._touchEnabled = enabled;
2530             if (enabled) {
2531                 this._style.pointerEvents = 'all';
2532             } else {
2533                 this._style.pointerEvents = 'none';
2534             }
2535         }
2536     },
2537     /**
2538      * Performs a collision detection based on whether or not the bounding rectangles are intersecting.
2539      * @param {*} other An object like Entity, with the properties x, y, width, height, which are used for the 
2540      * collision detection.
2541      * @return {Boolean} True, if a collision was detected.
2542      */
2543     intersect: function(other) {
2544         if (other instanceof enchant.Entity) {
2545             return this._intersectOne(other);
2546         } else if (typeof other === 'function' && other.collection) {
2547             return _intersectBetweenClassAndInstance(other, this);
2548         }
2549         return false;
2550     },
2551     _intersectOne: function(other) {
2552         if (this._dirty) {
2553             this._updateCoordinate();
2554         } if (other._dirty) {
2555             other._updateCoordinate();
2556         }
2557         return this._offsetX < other._offsetX + other.width && other._offsetX < this._offsetX + this.width &&
2558             this._offsetY < other._offsetY + other.height && other._offsetY < this._offsetY + this.height;
2559     },
2560     intersectStrict: function(other) {
2561         if (other instanceof enchant.Entity) {
2562             return this._intersectStrictOne(other);
2563         } else if (typeof other === 'function' && other.collection) {
2564             return _intersectStrictBetweenClassAndInstance(other, this);
2565         }
2566         return false;
2567     },
2568     _intersectStrictOne: function(other) {
2569         if (this._dirty) {
2570             this._updateCoordinate();
2571         } if (other._dirty) {
2572             other._updateCoordinate();
2573         }
2574         var rect1 = this.getOrientedBoundingRect(),
2575             rect2 = other.getOrientedBoundingRect(),
2576             lt1 = rect1.leftTop, rt1 = rect1.rightTop,
2577             lb1 = rect1.leftBottom, rb1 = rect1.rightBottom,
2578             lt2 = rect2.leftTop, rt2 = rect2.rightTop,
2579             lb2 = rect2.leftBottom, rb2 = rect2.rightBottom,
2580             ltx1 = lt1[0], lty1 = lt1[1], rtx1 = rt1[0], rty1 = rt1[1],
2581             lbx1 = lb1[0], lby1 = lb1[1], rbx1 = rb1[0], rby1 = rb1[1],
2582             ltx2 = lt2[0], lty2 = lt2[1], rtx2 = rt2[0], rty2 = rt2[1],
2583             lbx2 = lb2[0], lby2 = lb2[1], rbx2 = rb2[0], rby2 = rb2[1],
2584             t1 = [ rtx1 - ltx1, rty1 - lty1 ],
2585             r1 = [ rbx1 - rtx1, rby1 - rty1 ],
2586             b1 = [ lbx1 - rbx1, lby1 - rby1 ],
2587             l1 = [ ltx1 - lbx1, lty1 - lby1 ],
2588             t2 = [ rtx2 - ltx2, rty2 - lty2 ],
2589             r2 = [ rbx2 - rtx2, rby2 - rty2 ],
2590             b2 = [ lbx2 - rbx2, lby2 - rby2 ],
2591             l2 = [ ltx2 - lbx2, lty2 - lby2 ],
2592             cx1 = (ltx1 + rtx1 + lbx1 + rbx1) >> 2,
2593             cy1 = (lty1 + rty1 + lby1 + rby1) >> 2,
2594             cx2 = (ltx2 + rtx2 + lbx2 + rbx2) >> 2,
2595             cy2 = (lty2 + rty2 + lby2 + rby2) >> 2,
2596             i, j, poss1, poss2, dirs1, dirs2, pos1, pos2, dir1, dir2,
2597             px1, py1, px2, py2, dx1, dy1, dx2, dy2, vx, vy, c, c1, c2;
2598         if (t1[0] * (cy2 - lty1) - t1[1] * (cx2 - ltx1) > 0 &&
2599             r1[0] * (cy2 - rty1) - r1[1] * (cx2 - rtx1) > 0 &&
2600             b1[0] * (cy2 - rby1) - b1[1] * (cx2 - rbx1) > 0 &&
2601             l1[0] * (cy2 - lby1) - l1[1] * (cx2 - lbx1) > 0) {
2602             return true;
2603         } else if (t2[0] * (cy1 - lty2) - t2[1] * (cx1 - ltx2) > 0 &&
2604             r2[0] * (cy1 - rty2) - r2[1] * (cx1 - rtx2) > 0 &&
2605             b2[0] * (cy1 - rby2) - b2[1] * (cx1 - rbx2) > 0 &&
2606             l2[0] * (cy1 - lby2) - l2[1] * (cx1 - lbx2) > 0) {
2607             return true;
2608         } else {
2609             poss1 = [ lt1, rt1, rb1, lb1 ];
2610             poss2 = [ lt2, rt2, rb2, lb2 ];
2611             dirs1 = [ t1, r1, b1, l1 ];
2612             dirs2 = [ t2, r2, b2, l2 ];
2613             for (i = 0; i < 4; i++) {
2614                 pos1 = poss1[i];
2615                 px1 = pos1[0]; py1 = pos1[1];
2616                 dir1 = dirs1[i];
2617                 dx1 = dir1[0]; dy1 = dir1[1];
2618                 for (j = 0; j < 4; j++) {
2619                     pos2 = poss2[j];
2620                     px2 = pos2[0]; py2 = pos2[1];
2621                     dir2 = dirs2[j];
2622                     dx2 = dir2[0]; dy2 = dir2[1];
2623                     c = dx1 * dy2 - dy1 * dx2;
2624                     if (c !== 0) {
2625                         vx = px2 - px1;
2626                         vy = py2 - py1;
2627                         c1 = (vx * dy1 - vy * dx1) / c;
2628                         c2 = (vx * dy2 - vy * dx2) / c;
2629                         if (0 < c1 && c1 < 1 && 0 < c2 && c2 < 1) {
2630                             return true;
2631                         }
2632                     }
2633                 }
2634             }
2635             return false;
2636         }
2637     },
2638     /**
2639      * Performs a collision detection based on distance from the Entity's central point.
2640      * @param {*} other An object like Entity, with properties x, y, width, height, which are used for the 
2641      * collision detection.
2642      * @param {Number} [distance] The greatest distance to be considered for a collision.
2643      * The default distance is the average of both objects width and height.
2644      * @return {Boolean} True, if a collision was detected.
2645      */
2646     within: function(other, distance) {
2647         if (this._dirty) {
2648             this._updateCoordinate();
2649         } if (other._dirty) {
2650             other._updateCoordinate();
2651         }
2652         if (distance == null) {
2653             distance = (this.width + this.height + other.width + other.height) / 4;
2654         }
2655         var _;
2656         return (_ = this._offsetX - other._offsetX + (this.width - other.width) / 2) * _ +
2657             (_ = this._offsetY - other._offsetY + (this.height - other.height) / 2) * _ < distance * distance;
2658     },
2659     /**
2660      * Enlarges or shrinks this Entity.
2661      * @param {Number} x Scaling factor on the x axis.
2662      * @param {Number} [y] Scaling factor on the y axis.
2663      */
2664     scale: function(x, y) {
2665         this._scaleX *= x;
2666         this._scaleY *= (y != null) ? y : x;
2667         this._dirty = true;
2668     },
2669     /**
2670      * Rotate this Entity.
2671      * @param {Number} deg Rotation angle (degree).
2672      */
2673     rotate: function(deg) {
2674         this.rotation += deg;
2675     },
2676     /**
2677      * Scaling factor on the x axis of this Entity.
2678      * @type Number
2679      */
2680     scaleX: {
2681         get: function() {
2682             return this._scaleX;
2683         },
2684         set: function(scaleX) {
2685             if(this._scaleX !== scaleX) {
2686                 this._scaleX = scaleX;
2687                 this._dirty = true;
2688             }
2689         }
2690     },
2691     /**
2692      * Scaling factor on the y axis of this Entity.
2693      * @type Number
2694      */
2695     scaleY: {
2696         get: function() {
2697             return this._scaleY;
2698         },
2699         set: function(scaleY) {
2700             if(this._scaleY !== scaleY) {
2701                 this._scaleY = scaleY;
2702                 this._dirty = true;
2703             }
2704         }
2705     },
2706     /**
2707      * Entity rotation angle (degree).
2708      * @type Number
2709      */
2710     rotation: {
2711         get: function() {
2712             return this._rotation;
2713         },
2714         set: function(rotation) {
2715             if(this._rotation !== rotation) {
2716                 this._rotation = rotation;
2717                 this._dirty = true;
2718             }
2719         }
2720     },
2721     /**
2722      * The point of origin used for rotation and scaling.
2723      * @type Number
2724      */
2725     originX: {
2726         get: function() {
2727             return this._originX;
2728         },
2729         set: function(originX) {
2730             if(this._originX !== originX) {
2731                 this._originX = originX;
2732                 this._dirty = true;
2733             }
2734         }
2735     },
2736     /**
2737      * The point of origin used for rotation and scaling.
2738      * @type Number
2739      */
2740     originY: {
2741         get: function() {
2742             return this._originY;
2743         },
2744         set: function(originY) {
2745             if(this._originY !== originY) {
2746                 this._originY = originY;
2747                 this._dirty = true;
2748             }
2749         }
2750     },
2751     /**
2752      */
2753     enableCollection: function() {
2754         this.addEventListener('addedtoscene', this._addSelfToCollection);
2755         this.addEventListener('removedfromscene', this._removeSelfFromCollection);
2756         if (this.scene) {
2757             this._addSelfToCollection();
2758         }
2759     },
2760     /**
2761      */
2762     disableCollection: function() {
2763         this.removeEventListener('addedtoscene', this._addSelfToCollection);
2764         this.removeEventListener('removedfromscene', this._removeSelfFromCollection);
2765         if (this.scene) {
2766             this._removeSelfFromCollection();
2767         }
2768     },
2769     /**#nocode+*/
2770     clearEventListener: function() {
2771         _nodePrototypeClearEventListener.apply(this,arguments);
2772         if (this.scene) {
2773             this._removeSelfFromCollection();
2774         }
2775     },
2776     /**#nocode-*/
2777     _addSelfToCollection: function() {
2778         if (this._isContainedInCollection) {
2779             return;
2780         }
2781 
2782         var Constructor = this.getConstructor();
2783         Constructor._collectionTarget.forEach(function(C) {
2784             C.collection.push(this);
2785         }, this);
2786 
2787         this._isContainedInCollection = true;
2788     },
2789     _removeSelfFromCollection: function() {
2790         if (!this._isContainedInCollection) {
2791             return;
2792         }
2793 
2794         var Constructor = this.getConstructor();
2795         Constructor._collectionTarget.forEach(function(C) {
2796             var i = C.collection.indexOf(this);
2797             if (i !== -1) {
2798                 C.collection.splice(i, 1);
2799             }
2800         }, this);
2801 
2802         this._isContainedInCollection = false;
2803     },
2804     getBoundingRect: function() {
2805         var w = this.width || 0;
2806         var h = this.height || 0;
2807         var mat = this._matrix;
2808         var m11w = mat[0] * w, m12w = mat[1] * w,
2809             m21h = mat[2] * h, m22h = mat[3] * h,
2810             mdx = mat[4], mdy = mat[5];
2811         var xw = [ mdx, m11w + mdx, m21h + mdx, m11w + m21h + mdx ].sort(function(a, b) { return a - b; });
2812         var yh = [ mdy, m12w + mdy, m22h + mdy, m12w + m22h + mdy ].sort(function(a, b) { return a - b; });
2813 
2814         return {
2815             left: xw[0],
2816             top: yh[0],
2817             width: xw[3] - xw[0],
2818             height: yh[3] - yh[0]
2819         };
2820     },
2821     getOrientedBoundingRect: function() {
2822         var w = this.width || 0;
2823         var h = this.height || 0;
2824         var mat = this._matrix;
2825         var m11w = mat[0] * w, m12w = mat[1] * w,
2826             m21h = mat[2] * h, m22h = mat[3] * h,
2827             mdx = mat[4], mdy = mat[5];
2828 
2829         return {
2830             leftTop: [ mdx, mdy ],
2831             rightTop: [ m11w + mdx, m12w + mdy ],
2832             leftBottom: [ m21h + mdx, m22h + mdy ],
2833             rightBottom: [ m11w + m21h + mdx, m12w + m22h + mdy ]
2834         };
2835     },
2836     getConstructor: function() {
2837         return Object.getPrototypeOf(this).constructor;
2838     }
2839 });
2840 
2841 var _collectizeConstructor = function(Constructor) {
2842     if (Constructor._collective) {
2843         return;
2844     }
2845     var rel = enchant.Class.getInheritanceTree(Constructor);
2846     var i = rel.indexOf(enchant.Entity);
2847     if (i !== -1) {
2848         Constructor._collectionTarget = rel.splice(0, i + 1);
2849     } else {
2850         Constructor._collectionTarget = [];
2851     }
2852     Constructor.intersect = _staticIntersect;
2853     Constructor.intersectStrict = _staticIntersectStrict;
2854     Constructor.collection = [];
2855     Constructor._collective = true;
2856 };
2857 
2858 _collectizeConstructor(enchant.Entity);
2859 
2860 enchant.Entity._inherited = function(subclass) {
2861     _collectizeConstructor(subclass);
2862 };
2863 
2864 /**
2865  * @scope enchant.Sprite.prototype
2866  */
2867 enchant.Sprite = enchant.Class.create(enchant.Entity, {
2868     /**
2869      * @name enchant.Sprite
2870      * @class
2871      * Class which can display images.
2872      * @param {Number} width Sprite width.
2873      * @param {Number} height Sprite height.
2874      *
2875      * @example
2876      * var bear = new Sprite(32, 32);
2877      * bear.image = core.assets['chara1.gif'];
2878      *
2879      * @constructs
2880      * @extends enchant.Entity
2881      */
2882     initialize: function(width, height) {
2883         enchant.Entity.call(this);
2884 
2885         this.width = width;
2886         this.height = height;
2887         this._image = null;
2888         this._debugColor = '#ff0000';
2889         this._frameLeft = 0;
2890         this._frameTop = 0;
2891         this._frame = 0;
2892         this._frameSequence = null;
2893     },
2894     /**
2895      * Image displayed in the Sprite.
2896      * @type enchant.Surface
2897      */
2898     image: {
2899         get: function() {
2900             return this._image;
2901         },
2902         set: function(image) {
2903             if (image === undefined) {
2904                 throw new Error('Assigned value on Sprite.image is undefined. Please double-check image path, and check if the image you want to use is preload before use.');
2905             }
2906             if (image === this._image) {
2907                 return;
2908             }
2909             this._image = image;
2910             this._computeFramePosition();
2911         }
2912     },
2913     /**
2914      * Index of the frame to be displayed.
2915      * Frames with the same width and height as Sprite will be arrayed from upper left corner of the 
2916      * {@link enchant.Sprite#image} image. When a sequence of numbers is provided, the displayed frame 
2917      * will switch automatically. At the end of the array the sequence will restart. By setting 
2918      * a value within the sequence to null, the frame switching is stopped.
2919      *
2920      * @example
2921      * var sprite = new Sprite(32, 32);
2922      * sprite.frame = [0, 1, 0, 2]
2923      * //-> 0, 1, 0, 2, 0, 1, 0, 2,..
2924      * sprite.frame = [0, 1, 0, 2, null]
2925      * //-> 0, 1, 0, 2, (2, 2,.. :stop)
2926      *
2927      * @type Number|Array
2928      */
2929     frame: {
2930         get: function() {
2931             return this._frame;
2932         },
2933         set: function(frame) {
2934             if (((this._frameSequence == null) && (this._frame === frame)) || (this._deepCompareToPreviousFrame(frame))) {
2935                 return;
2936             }
2937             if (frame instanceof Array) {
2938                 this._frameSequence = frame;
2939             } else {
2940                 this._frameSequence = null;
2941                 this._frame = frame;
2942                 this._computeFramePosition();
2943             }
2944         }
2945     },
2946     _frameSequence: {
2947         get: function() {
2948             return this.__frameSequence;
2949         },
2950         set: function(frameSequence) {
2951             if(frameSequence && !this.__frameSequence) {
2952                 this.addEventListener(enchant.Event.ENTER_FRAME, this._rotateFrameSequence);
2953             } else if(!frameSequence && this.__frameSequence) {
2954                 this.removeEventListener(enchant.Event.ENTER_FRAME, this._rotateFrameSequence);
2955             }
2956             if(frameSequence) {
2957                 this.__frameSequence = frameSequence.slice();
2958                 this._originalFrameSequence = frameSequence.slice();
2959                 this._rotateFrameSequence();
2960             } else {
2961                 this.__frameSequence = null;
2962                 this._originalFrameSequence = null;
2963             }
2964         }
2965     },
2966     /**
2967      * If we are setting the same frame Array as animation,
2968      * just continue animating.
2969      * @private
2970      */
2971     _deepCompareToPreviousFrame: function(frameArray) {
2972         if (frameArray === this._originalFrameSequence) {
2973             return true;
2974         }
2975         if (frameArray == null || this._originalFrameSequence == null) {
2976             return false;
2977         }
2978         if (!(frameArray instanceof Array)) {
2979             return false;
2980         }
2981         if (frameArray.length !== this._originalFrameSequence.length) {
2982             return false;
2983         }
2984         for (var i = 0; i < frameArray.length; ++i) {
2985             if (frameArray[i] !== this._originalFrameSequence[i]){
2986                 return false;
2987             }
2988         }
2989         return true;
2990     },
2991     /**
2992      * 0 <= frame
2993      * @private
2994      */
2995     _computeFramePosition: function() {
2996         var image = this._image;
2997         var row;
2998         if (image != null) {
2999             row = image.width / this._width | 0;
3000             this._frameLeft = (this._frame % row | 0) * this._width;
3001             this._frameTop = (this._frame / row | 0) * this._height % image.height;
3002         }
3003     },
3004     _rotateFrameSequence: function() {
3005         var frameSequence = this._frameSequence;
3006         if (frameSequence && frameSequence.length !== 0) {
3007             var nextFrame = frameSequence.shift();
3008             if (nextFrame === null) {
3009                 this._frameSequence = null;
3010                 this.dispatchEvent(new enchant.Event(enchant.Event.ANIMATION_END));
3011             } else {
3012                 this._frame = nextFrame;
3013                 this._computeFramePosition();
3014                 frameSequence.push(nextFrame);
3015             }
3016         }
3017     },
3018     /**#nocode+*/
3019     width: {
3020         get: function() {
3021             return this._width;
3022         },
3023         set: function(width) {
3024             this._width = width;
3025             this._computeFramePosition();
3026             this._dirty = true;
3027         }
3028     },
3029     height: {
3030         get: function() {
3031             return this._height;
3032         },
3033         set: function(height) {
3034             this._height = height;
3035             this._computeFramePosition();
3036             this._dirty = true;
3037         }
3038     },
3039     /**#nocode-*/
3040     cvsRender: function(ctx) {
3041         var image = this._image,
3042             w = this._width, h = this._height,
3043             iw, ih, elem, sx, sy, sw, sh;
3044         if (image && w !== 0 && h !== 0) {
3045             iw = image.width;
3046             ih = image.height;
3047             if (iw < w || ih < h) {
3048                 ctx.fillStyle = enchant.Surface._getPattern(image);
3049                 ctx.fillRect(0, 0, w, h);
3050             } else {
3051                 elem = image._element;
3052                 sx = this._frameLeft;
3053                 sy = Math.min(this._frameTop, ih - h);
3054                 // IE9 doesn't allow for negative or 0 widths/heights when drawing on the CANVAS element
3055                 sw = Math.max(0.01, Math.min(iw - sx, w));
3056                 sh = Math.max(0.01, Math.min(ih - sy, h));
3057                 ctx.drawImage(elem, sx, sy, sw, sh, 0, 0, w, h);
3058             }
3059         }
3060     },
3061     domRender: (function() {
3062         if (enchant.ENV.VENDOR_PREFIX === 'ms') {
3063             return function(element) {
3064                 if (this._image) {
3065                     if (this._image._css) {
3066                         this._style['background-image'] = this._image._css;
3067                         this._style['background-position'] =
3068                             -this._frameLeft + 'px ' +
3069                             -this._frameTop + 'px';
3070                     } else if (this._image._element) {
3071                     }
3072                 }
3073             };
3074         } else {
3075             return function(element) {
3076                 if (this._image) {
3077                     if (this._image._css) {
3078                         this._style['background-image'] = this._image._css;
3079                         this._style['background-position'] =
3080                             -this._frameLeft + 'px ' +
3081                             -this._frameTop + 'px';
3082                     } else if (this._image._element) {
3083                     }
3084                 }
3085             };
3086         }
3087     }())
3088 });
3089 
3090 /**
3091  * @scope enchant.Label.prototype
3092  */
3093 enchant.Label = enchant.Class.create(enchant.Entity, {
3094     /**
3095      * @name enchant.Label
3096      * @class
3097      * A class for Label object.
3098      * @constructs
3099      * @extends enchant.Entity
3100      */
3101     initialize: function(text) {
3102         enchant.Entity.call(this);
3103 
3104         this.text = text || '';
3105         this.width = 300;
3106         this.font = '14px serif';
3107         this.textAlign = 'left';
3108 
3109         this._debugColor = '#ff0000';
3110     },
3111     /**#nocode+*/
3112     width: {
3113         get: function() {
3114             return this._width;
3115         },
3116         set: function(width) {
3117             this._width = width;
3118             this._dirty = true;
3119             // issue #164
3120             this.updateBoundArea();
3121         }
3122     },
3123     /**#nocode-*/
3124     /**
3125      * Text to be displayed.
3126      * @type String
3127      */
3128     text: {
3129         get: function() {
3130             return this._text;
3131         },
3132         set: function(text) {
3133             text = '' + text;
3134             if(this._text === text) {
3135                 return;
3136             }
3137             this._text = text;
3138             text = text.replace(/<br ?\/?>/gi, '<br/>');
3139             this._splitText = text.split('<br/>');
3140             this.updateBoundArea();
3141             for (var i = 0, l = this._splitText.length; i < l; i++) {
3142                 text = this._splitText[i];
3143                 var metrics = this.getMetrics(text);
3144                 this._splitText[i] = {};
3145                 this._splitText[i].text = text;
3146                 this._splitText[i].height = metrics.height;
3147                 this._splitText[i].width = metrics.width;
3148             }
3149         }
3150     },
3151     /**
3152      * Specifies horizontal alignment of text.
3153      * Can be set according to the format of the CSS 'text-align' property.
3154      * @type String
3155      */
3156     textAlign: {
3157         get: function() {
3158             return this._style['text-align'];
3159         },
3160         set: function(textAlign) {
3161             this._style['text-align'] = textAlign;
3162             this.updateBoundArea();
3163         }
3164     },
3165     /**
3166      * Font settings.
3167      * Can be set according to the format of the CSS 'font' property.
3168      * @type String
3169      */
3170     font: {
3171         get: function() {
3172             return this._style.font;
3173         },
3174         set: function(font) {
3175             this._style.font = font;
3176             this.updateBoundArea();
3177         }
3178     },
3179     /**
3180      * Text color settings.
3181      * Can be set according to the format of the CSS 'color' property.
3182      * @type String
3183      */
3184     color: {
3185         get: function() {
3186             return this._style.color;
3187         },
3188         set: function(color) {
3189             this._style.color = color;
3190         }
3191     },
3192     cvsRender: function(ctx) {
3193         var x, y = 0;
3194         var labelWidth = this.width;
3195         var charWidth, amount, line, text, c, buf, increase, length;
3196         var bufWidth;
3197         if (this._splitText) {
3198             ctx.textBaseline = 'top';
3199             ctx.font = this.font;
3200             ctx.fillStyle = this.color || '#000000';
3201             charWidth = ctx.measureText(' ').width;
3202             amount = labelWidth / charWidth;
3203             for (var i = 0, l = this._splitText.length; i < l; i++) {
3204                 line = this._splitText[i];
3205                 text = line.text;
3206                 c = 0;
3207                 while (text.length > c + amount || ctx.measureText(text.slice(c, c + amount)).width > labelWidth) {
3208                     buf = '';
3209                     increase = amount;
3210                     length = 0;
3211                     while (increase > 0) {
3212                         if (ctx.measureText(buf).width < labelWidth) {
3213                             length += increase;
3214                             buf = text.slice(c, c + length);
3215                         } else {
3216                             length -= increase;
3217                             buf = text.slice(c, c + length);
3218                         }
3219                         increase = increase / 2 | 0;
3220                     }
3221                     ctx.fillText(buf, 0, y);
3222                     y += line.height - 1;
3223                     c += length;
3224                 }
3225                 buf = text.slice(c, c + text.length);
3226                 if (this.textAlign === 'right') {
3227                     x = labelWidth - ctx.measureText(buf).width;
3228                 } else if (this.textAlign === 'center') {
3229                     x = (labelWidth - ctx.measureText(buf).width) / 2;
3230                 } else {
3231                     x = 0;
3232                 }
3233                 ctx.fillText(buf, x, y);
3234                 y += line.height - 1;
3235             }
3236         }
3237     },
3238     domRender: function(element) {
3239         if (element.innerHTML !== this._text) {
3240             element.innerHTML = this._text;
3241         }
3242     },
3243     detectRender: function(ctx) {
3244         ctx.fillRect(this._boundOffset, 0, this._boundWidth, this._boundHeight);
3245     },
3246     updateBoundArea: function() {
3247         var metrics = this.getMetrics();
3248         this._boundWidth = metrics.width;
3249         this._boundHeight = metrics.height;
3250         if (this.textAlign === 'right') {
3251             this._boundOffset = this.width - this._boundWidth;
3252         } else if (this.textAlign === 'center') {
3253             this._boundOffset = (this.width - this._boundWidth) / 2;
3254         } else {
3255             this._boundOffset = 0;
3256         }
3257     },
3258     getMetrics: function(text) {
3259         var ret = {};
3260         var div, width, height;
3261         if (document.body) {
3262             div = document.createElement('div');
3263             for (var prop in this._style) {
3264                 if(prop !== 'width' && prop !== 'height') {
3265                     div.style[prop] = this._style[prop];
3266                 }
3267             }
3268             text = text || this._text;
3269             div.innerHTML = text.replace(/ /g, ' ');
3270             div.style.whiteSpace = 'noWrap';
3271             div.style.lineHeight = 1;
3272             document.body.appendChild(div);
3273             var computedStyle = getComputedStyle(div);
3274             ret.height = parseInt(computedStyle.height, 10) + 1;
3275             div.style.position = 'absolute';
3276             ret.width = parseInt(computedStyle.width, 10) + 1;
3277             document.body.removeChild(div);
3278         } else {
3279             ret.width = this.width;
3280             ret.height = this.height;
3281         }
3282         return ret;
3283     }
3284 });
3285 
3286 /**
3287  * @scope enchant.Map.prototype
3288  */
3289 enchant.Map = enchant.Class.create(enchant.Entity, {
3290     /**
3291      * @name enchant.Map
3292      * @class
3293      * A class to create and display maps from a tile set.
3294      * @param {Number} tileWidth Tile width.
3295      * @param {Number} tileHeight Tile height.
3296      * @constructs
3297      * @extends enchant.Entity
3298      */
3299     initialize: function(tileWidth, tileHeight) {
3300         var core = enchant.Core.instance;
3301 
3302         enchant.Entity.call(this);
3303 
3304         var surface = new enchant.Surface(core.width, core.height);
3305         this._surface = surface;
3306         var canvas = surface._element;
3307         canvas.style.position = 'absolute';
3308         if (enchant.ENV.RETINA_DISPLAY && core.scale === 2) {
3309             canvas.width = core.width * 2;
3310             canvas.height = core.height * 2;
3311             this._style.webkitTransformOrigin = '0 0';
3312             this._style.webkitTransform = 'scale(0.5)';
3313         } else {
3314             canvas.width = core.width;
3315             canvas.height = core.height;
3316         }
3317         this._context = canvas.getContext('2d');
3318 
3319         this._tileWidth = tileWidth || 0;
3320         this._tileHeight = tileHeight || 0;
3321         this._image = null;
3322         this._data = [
3323             [
3324                 []
3325             ]
3326         ];
3327         this._dirty = false;
3328         this._tight = false;
3329 
3330         this.touchEnabled = false;
3331 
3332         /**
3333          * Two dimensional array to store if collision detection should be performed for a tile.
3334          * @type Number[][]
3335          */
3336         this.collisionData = null;
3337 
3338         this._listeners['render'] = null;
3339         this.addEventListener('render', function() {
3340             if(this._dirty) {
3341                 this._previousOffsetX = this._previousOffsetY = null;
3342             }
3343         });
3344     },
3345     /**
3346      * Set map data.
3347      * Sets the tile data, whereas the data (two-dimensional array with indizes starting from 0) 
3348      * is mapped on the image starting from the upper left corner.
3349      * When more than one map data array is set, they are displayed in reverse order.
3350      * @param {...Number[][]} data Two-dimensional array of tile indizes. Multiple designations possible.
3351      */
3352     loadData: function(data) {
3353         this._data = Array.prototype.slice.apply(arguments);
3354         this._dirty = true;
3355 
3356         this._tight = false;
3357         for (var i = 0, len = this._data.length; i < len; i++) {
3358             var c = 0;
3359             data = this._data[i];
3360             for (var y = 0, l = data.length; y < l; y++) {
3361                 for (var x = 0, ll = data[y].length; x < ll; x++) {
3362                     if (data[y][x] >= 0) {
3363                         c++;
3364                     }
3365                 }
3366             }
3367             if (c / (data.length * data[0].length) > 0.2) {
3368                 this._tight = true;
3369                 break;
3370             }
3371         }
3372     },
3373     /**
3374      * Checks what tile is present at the given position.
3375      * @param {Number} x x coordinates of the point on the map.
3376      * @param {Number} y y coordinates of the point on the map.
3377      * @return {*} The tile data for the given position.
3378      */
3379     checkTile: function(x, y) {
3380         if (x < 0 || this.width <= x || y < 0 || this.height <= y) {
3381             return false;
3382         }
3383         var width = this._image.width;
3384         var height = this._image.height;
3385         var tileWidth = this._tileWidth || width;
3386         var tileHeight = this._tileHeight || height;
3387         x = x / tileWidth | 0;
3388         y = y / tileHeight | 0;
3389         //		return this._data[y][x];
3390         var data = this._data[0];
3391         return data[y][x];
3392     },
3393     /**
3394      * Judges whether or not obstacles are on top of Map.
3395      * @param {Number} x x coordinates of detection spot on map.
3396      * @param {Number} y y coordinates of detection spot on map.
3397      * @return {Boolean} True, if there are obstacles.
3398      */
3399     hitTest: function(x, y) {
3400         if (x < 0 || this.width <= x || y < 0 || this.height <= y) {
3401             return false;
3402         }
3403         var width = this._image.width;
3404         var height = this._image.height;
3405         var tileWidth = this._tileWidth || width;
3406         var tileHeight = this._tileHeight || height;
3407         x = x / tileWidth | 0;
3408         y = y / tileHeight | 0;
3409         if (this.collisionData != null) {
3410             return this.collisionData[y] && !!this.collisionData[y][x];
3411         } else {
3412             for (var i = 0, len = this._data.length; i < len; i++) {
3413                 var data = this._data[i];
3414                 var n;
3415                 if (data[y] != null && (n = data[y][x]) != null &&
3416                     0 <= n && n < (width / tileWidth | 0) * (height / tileHeight | 0)) {
3417                     return true;
3418                 }
3419             }
3420             return false;
3421         }
3422     },
3423     /**
3424      * Image with which the tile set is displayed on the map.
3425      * @type enchant.Surface
3426      */
3427     image: {
3428         get: function() {
3429             return this._image;
3430         },
3431         set: function(image) {
3432             var core = enchant.Core.instance;
3433 
3434             this._image = image;
3435             if (enchant.ENV.RETINA_DISPLAY && core.scale === 2) {
3436                 var img = new enchant.Surface(image.width * 2, image.height * 2);
3437                 var tileWidth = this._tileWidth || image.width;
3438                 var tileHeight = this._tileHeight || image.height;
3439                 var row = image.width / tileWidth | 0;
3440                 var col = image.height / tileHeight | 0;
3441                 for (var y = 0; y < col; y++) {
3442                     for (var x = 0; x < row; x++) {
3443                         img.draw(image, x * tileWidth, y * tileHeight, tileWidth, tileHeight,
3444                             x * tileWidth * 2, y * tileHeight * 2, tileWidth * 2, tileHeight * 2);
3445                     }
3446                 }
3447                 this._doubledImage = img;
3448             }
3449             this._dirty = true;
3450         }
3451     },
3452     /**
3453      * Map tile width.
3454      * @type Number
3455      */
3456     tileWidth: {
3457         get: function() {
3458             return this._tileWidth;
3459         },
3460         set: function(tileWidth) {
3461             if(this._tileWidth !== tileWidth) {
3462                 this._tileWidth = tileWidth;
3463                 this._dirty = true;
3464             }
3465         }
3466     },
3467     /**
3468      * Map tile height.
3469      * @type Number
3470      */
3471     tileHeight: {
3472         get: function() {
3473             return this._tileHeight;
3474         },
3475         set: function(tileHeight) {
3476             if(this._tileHeight !== tileHeight) {
3477                 this._tileHeight = tileHeight;
3478                 this._dirty = true;
3479             }
3480         }
3481     },
3482     /**
3483      * @private
3484      */
3485     width: {
3486         get: function() {
3487             return this._tileWidth * this._data[0][0].length;
3488         }
3489     },
3490     /**
3491      * @private
3492      */
3493     height: {
3494         get: function() {
3495             return this._tileHeight * this._data[0].length;
3496         }
3497     },
3498     /**
3499      * @private
3500      */
3501     redraw: function(x, y, width, height) {
3502         if (this._image == null) {
3503             return;
3504         }
3505 
3506         var image, tileWidth, tileHeight, dx, dy;
3507         if (this._doubledImage) {
3508             image = this._doubledImage;
3509             tileWidth = this._tileWidth * 2;
3510             tileHeight = this._tileHeight * 2;
3511             dx = -this._offsetX * 2;
3512             dy = -this._offsetY * 2;
3513             x *= 2;
3514             y *= 2;
3515             width *= 2;
3516             height *= 2;
3517         } else {
3518             image = this._image;
3519             tileWidth = this._tileWidth;
3520             tileHeight = this._tileHeight;
3521             dx = -this._offsetX;
3522             dy = -this._offsetY;
3523         }
3524         var row = image.width / tileWidth | 0;
3525         var col = image.height / tileHeight | 0;
3526         var left = Math.max((x + dx) / tileWidth | 0, 0);
3527         var top = Math.max((y + dy) / tileHeight | 0, 0);
3528         var right = Math.ceil((x + dx + width) / tileWidth);
3529         var bottom = Math.ceil((y + dy + height) / tileHeight);
3530 
3531         var source = image._element;
3532         var context = this._context;
3533         var canvas = context.canvas;
3534         context.clearRect(x, y, width, height);
3535         for (var i = 0, len = this._data.length; i < len; i++) {
3536             var data = this._data[i];
3537             var r = Math.min(right, data[0].length);
3538             var b = Math.min(bottom, data.length);
3539             for (y = top; y < b; y++) {
3540                 for (x = left; x < r; x++) {
3541                     var n = data[y][x];
3542                     if (0 <= n && n < row * col) {
3543                         var sx = (n % row) * tileWidth;
3544                         var sy = (n / row | 0) * tileHeight;
3545                         context.drawImage(source, sx, sy, tileWidth, tileHeight,
3546                             x * tileWidth - dx, y * tileHeight - dy, tileWidth, tileHeight);
3547                     }
3548                 }
3549             }
3550         }
3551     },
3552     /**
3553      * @private
3554      */
3555     updateBuffer: function() {
3556         if (this._visible === undefined || this._visible) {
3557             var core = enchant.Core.instance;
3558             if (this._dirty || this._previousOffsetX == null) {
3559                 this.redraw(0, 0, core.width, core.height);
3560             } else if (this._offsetX !== this._previousOffsetX ||
3561                     this._offsetY !== this._previousOffsetY) {
3562                 if (this._tight) {
3563                     var x = -this._offsetX;
3564                     var y = -this._offsetY;
3565                     var px = -this._previousOffsetX;
3566                     var py = -this._previousOffsetY;
3567                     var w1 = x - px + core.width;
3568                     var w2 = px - x + core.width;
3569                     var h1 = y - py + core.height;
3570                     var h2 = py - y + core.height;
3571                     if (w1 > this._tileWidth && w2 > this._tileWidth &&
3572                             h1 > this._tileHeight && h2 > this._tileHeight) {
3573                         var sx, sy, dx, dy, sw, sh;
3574                         if (w1 < w2) {
3575                             sx = 0;
3576                             dx = px - x;
3577                             sw = w1;
3578                         } else {
3579                             sx = x - px;
3580                             dx = 0;
3581                             sw = w2;
3582                         }
3583                         if (h1 < h2) {
3584                             sy = 0;
3585                             dy = py - y;
3586                             sh = h1;
3587                         } else {
3588                             sy = y - py;
3589                             dy = 0;
3590                             sh = h2;
3591                         }
3592 
3593                         if (core._buffer == null) {
3594                             core._buffer = document.createElement('canvas');
3595                             core._buffer.width = this._context.canvas.width;
3596                             core._buffer.height = this._context.canvas.height;
3597                         }
3598                         var context = core._buffer.getContext('2d');
3599                         if (this._doubledImage) {
3600                             context.clearRect(0, 0, sw * 2, sh * 2);
3601                             context.drawImage(this._context.canvas,
3602                                     sx * 2, sy * 2, sw * 2, sh * 2, 0, 0, sw * 2, sh * 2);
3603                             context = this._context;
3604                             context.clearRect(dx * 2, dy * 2, sw * 2, sh * 2);
3605                             context.drawImage(core._buffer,
3606                                     0, 0, sw * 2, sh * 2, dx * 2, dy * 2, sw * 2, sh * 2);
3607                         } else {
3608                             context.clearRect(0, 0, sw, sh);
3609                             context.drawImage(this._context.canvas,
3610                                     sx, sy, sw, sh, 0, 0, sw, sh);
3611                             context = this._context;
3612                             context.clearRect(dx, dy, sw, sh);
3613                             context.drawImage(core._buffer,
3614                                     0, 0, sw, sh, dx, dy, sw, sh);
3615                         }
3616 
3617                         if (dx === 0) {
3618                             this.redraw(sw, 0, core.width - sw, core.height);
3619                         } else {
3620                             this.redraw(0, 0, core.width - sw, core.height);
3621                         }
3622                         if (dy === 0) {
3623                             this.redraw(0, sh, core.width, core.height - sh);
3624                         } else {
3625                             this.redraw(0, 0, core.width, core.height - sh);
3626                         }
3627                     } else {
3628                         this.redraw(0, 0, core.width, core.height);
3629                     }
3630                 } else {
3631                     this.redraw(0, 0, core.width, core.height);
3632                 }
3633             }
3634             this._previousOffsetX = this._offsetX;
3635             this._previousOffsetY = this._offsetY;
3636         }
3637     },
3638     cvsRender: function(ctx) {
3639         if (this.width !== 0 && this.height !== 0) {
3640             var core = enchant.Core.instance;
3641             this.updateBuffer();
3642             ctx.save();
3643             ctx.setTransform(1, 0, 0, 1, 0, 0);
3644             var cvs = this._context.canvas;
3645                 ctx.drawImage(cvs, 0, 0, core.width, core.height);
3646             ctx.restore();
3647         }
3648     },
3649     domRender: function(element) {
3650         if (this._image) {
3651             this.updateBuffer();
3652             this._style['background-image'] = this._surface._css;
3653             // bad performance
3654             this._style[enchant.ENV.VENDOR_PREFIX + 'Transform'] = 'matrix(1, 0, 0, 1, 0, 0)';
3655         }
3656     }
3657 });
3658 
3659 
3660 /**
3661  * @scope enchant.Group.prototype
3662  */
3663 enchant.Group = enchant.Class.create(enchant.Node, {
3664     /**
3665      * @name enchant.Group
3666      * @class
3667      * A class that can hold multiple {@link enchant.Node}.
3668      *
3669      * @example
3670      * var stage = new Group();
3671      * stage.addChild(player);
3672      * stage.addChild(enemy);
3673      * stage.addChild(map);
3674      * stage.addEventListener('enterframe', function() {
3675      *     // Moves the entire frame in according to the player's coordinates.
3676      *     if (this.x > 64 - player.x) {
3677      *         this.x = 64 - player.x;
3678      *     }
3679      * });
3680      * @constructs
3681      * @extends enchant.Node
3682      */
3683     initialize: function() {
3684         /**
3685          * Child Nodes.
3686          * @type enchant.Node[]
3687          */
3688         this.childNodes = [];
3689 
3690         enchant.Node.call(this);
3691 
3692         this._rotation = 0;
3693         this._scaleX = 1;
3694         this._scaleY = 1;
3695 
3696         this._originX = null;
3697         this._originY = null;
3698 
3699         this.__dirty = false;
3700 
3701         [enchant.Event.ADDED_TO_SCENE, enchant.Event.REMOVED_FROM_SCENE]
3702             .forEach(function(event) {
3703                 this.addEventListener(event, function(e) {
3704                     this.childNodes.forEach(function(child) {
3705                         child.scene = this.scene;
3706                         child.dispatchEvent(e);
3707                     }, this);
3708                 });
3709             }, this);
3710     },
3711     /**
3712      * Adds a Node to the Group.
3713      * @param {enchant.Node} node Node to be added.
3714      */
3715     addChild: function(node) {
3716         if (node.parentNode) {
3717             node.parentNode.removeChild(node);
3718         }
3719         this.childNodes.push(node);
3720         node.parentNode = this;
3721         var childAdded = new enchant.Event('childadded');
3722         childAdded.node = node;
3723         childAdded.next = null;
3724         this.dispatchEvent(childAdded);
3725         node.dispatchEvent(new enchant.Event('added'));
3726         if (this.scene) {
3727             node.scene = this.scene;
3728             var addedToScene = new enchant.Event('addedtoscene');
3729             node.dispatchEvent(addedToScene);
3730         }
3731     },
3732     /**
3733      * Incorporates Node into Group.
3734      * @param {enchant.Node} node Node to be incorporated.
3735      * @param {enchant.Node} reference Node in position before insertion.
3736      */
3737     insertBefore: function(node, reference) {
3738         if (node.parentNode) {
3739             node.parentNode.removeChild(node);
3740         }
3741         var i = this.childNodes.indexOf(reference);
3742         if (i !== -1) {
3743             this.childNodes.splice(i, 0, node);
3744             node.parentNode = this;
3745             var childAdded = new enchant.Event('childadded');
3746             childAdded.node = node;
3747             childAdded.next = reference;
3748             this.dispatchEvent(childAdded);
3749             node.dispatchEvent(new enchant.Event('added'));
3750             if (this.scene) {
3751                 node.scene = this.scene;
3752                 var addedToScene = new enchant.Event('addedtoscene');
3753                 node.dispatchEvent(addedToScene);
3754             }
3755         } else {
3756             this.addChild(node);
3757         }
3758     },
3759     /**
3760      * Remove a Node from the Group.
3761      * @param {enchant.Node} node Node to be deleted.
3762      */
3763     removeChild: function(node) {
3764         var i;
3765         if ((i = this.childNodes.indexOf(node)) !== -1) {
3766             this.childNodes.splice(i, 1);
3767             node.parentNode = null;
3768             var childRemoved = new enchant.Event('childremoved');
3769             childRemoved.node = node;
3770             this.dispatchEvent(childRemoved);
3771             node.dispatchEvent(new enchant.Event('removed'));
3772             if (this.scene) {
3773                 node.scene = null;
3774                 var removedFromScene = new enchant.Event('removedfromscene');
3775                 node.dispatchEvent(removedFromScene);
3776             }
3777         }
3778     },
3779     /**
3780      * The Node which is the first child.
3781      * @type enchant.Node
3782      */
3783     firstChild: {
3784         get: function() {
3785             return this.childNodes[0];
3786         }
3787     },
3788     /**
3789      * The Node which is the last child.
3790      * @type enchant.Node
3791      */
3792     lastChild: {
3793         get: function() {
3794             return this.childNodes[this.childNodes.length - 1];
3795         }
3796     },
3797     /**
3798     * Group rotation angle (degree).
3799     * @type Number
3800     */
3801     rotation: {
3802         get: function() {
3803             return this._rotation;
3804         },
3805         set: function(rotation) {
3806             if(this._rotation !== rotation) {
3807                 this._rotation = rotation;
3808                 this._dirty = true;
3809             }
3810         }
3811     },
3812     /**
3813     * Scaling factor on the x axis of the Group.
3814     * @type Number
3815     * @see enchant.Group#originX
3816     * @see enchant.Group#originY
3817     */
3818     scaleX: {
3819         get: function() {
3820             return this._scaleX;
3821         },
3822         set: function(scale) {
3823             if(this._scaleX !== scale) {
3824                 this._scaleX = scale;
3825                 this._dirty = true;
3826             }
3827         }
3828     },
3829     /**
3830     * Scaling factor on the y axis of the Group.
3831     * @type Number
3832     * @see enchant.Group#originX
3833     * @see enchant.Group#originY
3834     */
3835     scaleY: {
3836         get: function() {
3837             return this._scaleY;
3838         },
3839         set: function(scale) {
3840             if(this._scaleY !== scale) {
3841                 this._scaleY = scale;
3842                 this._dirty = true;
3843             }
3844         }
3845     },
3846     /**
3847     * origin point of rotation, scaling
3848     * @type Number
3849     */
3850     originX: {
3851         get: function() {
3852             return this._originX;
3853         },
3854         set: function(originX) {
3855             if(this._originX !== originX) {
3856                 this._originX = originX;
3857                 this._dirty = true;
3858             }
3859         }
3860     },
3861     /**
3862     * origin point of rotation, scaling
3863     * @type Number
3864     */
3865     originY: {
3866         get: function() {
3867             return this._originY;
3868         },
3869         set: function(originY) {
3870             if(this._originY !== originY) {
3871                 this._originY = originY;
3872                 this._dirty = true;
3873             }
3874         }
3875     },
3876     /**#nocode+*/
3877     _dirty: {
3878         get: function() {
3879             return this.__dirty;
3880         },
3881         set: function(dirty) {
3882             dirty = !!dirty;
3883             this.__dirty = dirty;
3884             if (dirty) {
3885                 for (var i = 0, l = this.childNodes.length; i < l; i++) {
3886                     this.childNodes[i]._dirty = true;
3887                 }
3888             }
3889         }
3890     }
3891     /**#nocode-*/
3892 });
3893 
3894 enchant.Matrix = enchant.Class.create({
3895     initialize: function() {
3896         this.reset();
3897     },
3898     reset: function() {
3899         this.stack = [];
3900         this.stack.push([ 1, 0, 0, 1, 0, 0 ]);
3901     },
3902     makeTransformMatrix: function(node, dest) {
3903         var x = node._x;
3904         var y = node._y;
3905         var width = node.width || 0;
3906         var height = node.height || 0;
3907         var rotation = node._rotation || 0;
3908         var scaleX = (typeof node._scaleX === 'number') ? node._scaleX : 1;
3909         var scaleY = (typeof node._scaleY === 'number') ? node._scaleY : 1;
3910         var theta = rotation * Math.PI / 180;
3911         var tmpcos = Math.cos(theta);
3912         var tmpsin = Math.sin(theta);
3913         var w = (typeof node._originX === 'number') ? node._originX : width / 2;
3914         var h = (typeof node._originY === 'number') ? node._originY : height / 2;
3915         var a = scaleX * tmpcos;
3916         var b = scaleX * tmpsin;
3917         var c = scaleY * tmpsin;
3918         var d = scaleY * tmpcos;
3919         dest[0] = a;
3920         dest[1] = b;
3921         dest[2] = -c;
3922         dest[3] = d;
3923         dest[4] = (-a * w + c * h + x + w);
3924         dest[5] = (-b * w - d * h + y + h);
3925     },
3926     multiply: function(m1, m2, dest) {
3927         var a11 = m1[0], a21 = m1[2], adx = m1[4],
3928             a12 = m1[1], a22 = m1[3], ady = m1[5];
3929         var b11 = m2[0], b21 = m2[2], bdx = m2[4],
3930             b12 = m2[1], b22 = m2[3], bdy = m2[5];
3931 
3932         dest[0] = a11 * b11 + a21 * b12;
3933         dest[1] = a12 * b11 + a22 * b12;
3934         dest[2] = a11 * b21 + a21 * b22;
3935         dest[3] = a12 * b21 + a22 * b22;
3936         dest[4] = a11 * bdx + a21 * bdy + adx;
3937         dest[5] = a12 * bdx + a22 * bdy + ady;
3938     },
3939     multiplyVec: function(mat, vec, dest) {
3940         var x = vec[0], y = vec[1];
3941         var m11 = mat[0], m21 = mat[2], mdx = mat[4],
3942             m12 = mat[1], m22 = mat[3], mdy = mat[5];
3943         dest[0] = m11 * x + m21 * y + mdx;
3944         dest[1] = m12 * x + m22 * y + mdy;
3945     }
3946 });
3947 enchant.Matrix.instance = new enchant.Matrix();
3948 
3949 enchant.DetectColorManager = enchant.Class.create({
3950     initialize: function(reso, max) {
3951         this.reference = [];
3952         this.colorResolution = reso || 16;
3953         this.max = max || 1;
3954         this.capacity = Math.pow(this.colorResolution, 3);
3955         for (var i = 1, l = this.capacity; i < l; i++) {
3956             this.reference[i] = null;
3957         }
3958     },
3959     attachDetectColor: function(sprite) {
3960         var i = this.reference.indexOf(null);
3961         if (i === -1) {
3962             i = 1;
3963         }
3964         this.reference[i] = sprite;
3965         return this._getColor(i);
3966     },
3967     detachDetectColor: function(sprite) {
3968         var i = this.reference.indexOf(sprite);
3969         if (i !== -1) {
3970             this.reference[i] = null;
3971         }
3972     },
3973     _getColor: function(n) {
3974         var C = this.colorResolution;
3975         var d = C / this.max;
3976         return [
3977             parseInt((n / C / C) % C, 10) / d,
3978             parseInt((n / C) % C, 10) / d,
3979             parseInt(n % C, 10) / d,
3980             1.0
3981         ];
3982     },
3983     _decodeDetectColor: function(color, i) {
3984         i = i || 0;
3985         var C = this.colorResolution;
3986         return ~~(color[i] * C * C * C / 256) +
3987             ~~(color[i + 1] * C * C / 256) +
3988             ~~(color[i + 2] * C / 256);
3989     },
3990     getSpriteByColor: function(color) {
3991         return this.reference[this._decodeDetectColor(color)];
3992     },
3993     getSpriteByColors: function(rgba) {
3994         var i, l, id, result,
3995             score = 0,
3996             found = {};
3997 
3998         for (i = 0, l = rgba.length; i < l; i+= 4) {
3999             id = this._decodeDetectColor(rgba, i);
4000             found[id] = (found[id] || 0) + 1;
4001         }
4002         for (id in found) {
4003             if (found[id] > score) {
4004                 score = found[id];
4005                 result = id;
4006             }
4007         }
4008 
4009         return this.reference[result];
4010     }
4011 });
4012 
4013 enchant.DomManager = enchant.Class.create({
4014     initialize: function(node, elementDefinition) {
4015         var core = enchant.Core.instance;
4016         this.layer = null;
4017         this.targetNode = node;
4018         if (typeof elementDefinition === 'string') {
4019             this.element = document.createElement(elementDefinition);
4020         } else if (elementDefinition instanceof HTMLElement) {
4021             this.element = elementDefinition;
4022         }
4023         this.style = this.element.style;
4024         this.style.position = 'absolute';
4025         this.style[enchant.ENV.VENDOR_PREFIX + 'TransformOrigin'] = '0px 0px';
4026         if (core._debug) {
4027             this.style.border = '1px solid blue';
4028             this.style.margin = '-1px';
4029         }
4030 
4031         var manager = this;
4032         this._setDomTarget = function() {
4033             manager.layer._touchEventTarget = manager.targetNode;
4034         };
4035         this._attachEvent();
4036     },
4037     getDomElement: function() {
4038         return this.element;
4039     },
4040     getDomElementAsNext: function() {
4041         return this.element;
4042     },
4043     getNextManager: function(manager) {
4044         var i = this.targetNode.parentNode.childNodes.indexOf(manager.targetNode);
4045         if (i !== this.targetNode.parentNode.childNodes.length - 1) {
4046             return this.targetNode.parentNode.childNodes[i + 1]._domManager;
4047         } else {
4048             return null;
4049         }
4050     },
4051     addManager: function(childManager, nextManager) {
4052         var nextElement;
4053         if (nextManager) {
4054             nextElement = nextManager.getDomElementAsNext();
4055         }
4056         var element = childManager.getDomElement();
4057         if (element instanceof Array) {
4058             element.forEach(function(child) {
4059                 if (nextElement) {
4060                     this.element.insertBefore(child, nextElement);
4061                 } else {
4062                     this.element.appendChild(child);
4063                 }
4064             }, this);
4065         } else {
4066             if (nextElement) {
4067                 this.element.insertBefore(element, nextElement);
4068             } else {
4069                 this.element.appendChild(element);
4070             }
4071         }
4072         this.setLayer(this.layer);
4073     },
4074     removeManager: function(childManager) {
4075         if (childManager instanceof enchant.DomlessManager) {
4076             childManager._domRef.forEach(function(element) {
4077                 this.element.removeChild(element);
4078             }, this);
4079         } else {
4080             this.element.removeChild(childManager.element);
4081         }
4082         this.setLayer(this.layer);
4083     },
4084     setLayer: function(layer) {
4085         this.layer = layer;
4086         var node = this.targetNode;
4087         var manager;
4088         if (node.childNodes) {
4089             for (var i = 0, l = node.childNodes.length; i < l; i++) {
4090                 manager = node.childNodes[i]._domManager;
4091                 if (manager) {
4092                     manager.setLayer(layer);
4093                 }
4094             }
4095         }
4096     },
4097     render: function(inheritMat) {
4098         var node = this.targetNode;
4099         var matrix = enchant.Matrix.instance;
4100         var stack = matrix.stack;
4101         var dest = [];
4102         matrix.makeTransformMatrix(node, dest);
4103         matrix.multiply(stack[stack.length - 1], dest, dest);
4104         matrix.multiply(inheritMat, dest, inheritMat);
4105         node._matrix = inheritMat;
4106         var ox = (typeof node._originX === 'number') ? node._originX : node.width / 2 || 0;
4107         var oy = (typeof node._originY === 'number') ? node._originY : node.height / 2 || 0;
4108         var vec = [ ox, oy ];
4109         matrix.multiplyVec(dest, vec, vec);
4110 
4111         node._offsetX = vec[0] - ox;
4112         node._offsetY = vec[1] - oy;
4113         if(node.parentNode && !(node.parentNode instanceof enchant.Group)) {
4114             node._offsetX += node.parentNode._offsetX;
4115             node._offsetY += node.parentNode._offsetY;
4116         }
4117         if (node._dirty) {
4118             this.style[enchant.ENV.VENDOR_PREFIX + 'Transform'] = 'matrix(' +
4119                 dest[0].toFixed(10) + ',' +
4120                 dest[1].toFixed(10) + ',' +
4121                 dest[2].toFixed(10) + ',' +
4122                 dest[3].toFixed(10) + ',' +
4123                 dest[4].toFixed(10) + ',' +
4124                 dest[5].toFixed(10) +
4125             ')';
4126         }
4127         this.domRender();
4128     },
4129     domRender: function() {
4130         var node = this.targetNode;
4131         if(!node._style) {
4132             node._style = {};
4133         }
4134         if(!node.__styleStatus) {
4135             node.__styleStatus = {};
4136         }
4137         if (node.width !== null) {
4138             node._style.width = node.width + 'px';
4139         }
4140         if (node.height !== null) {
4141             node._style.height = node.height + 'px';
4142         }
4143         node._style.opacity = node._opacity;
4144         node._style['background-color'] = node._backgroundColor;
4145         if (typeof node._visible !== 'undefined') {
4146             node._style.display = node._visible ? 'block' : 'none';
4147         }
4148         if (typeof node.domRender === 'function') {
4149             node.domRender(this.element);
4150         }
4151         var value;
4152         for (var prop in node._style) {
4153             value = node._style[prop];
4154             if(node.__styleStatus[prop] !== value && value != null) {
4155                 this.style.setProperty(prop, '' + value);
4156                 node.__styleStatus[prop] = value;
4157             }
4158         }
4159     },
4160     _attachEvent: function() {
4161         if (enchant.ENV.TOUCH_ENABLED) {
4162             this.element.addEventListener('touchstart', this._setDomTarget, true);
4163         }
4164         this.element.addEventListener('mousedown', this._setDomTarget, true);
4165     },
4166     _detachEvent: function() {
4167         if (enchant.ENV.TOUCH_ENABLED) {
4168             this.element.removeEventListener('touchstart', this._setDomTarget, true);
4169         }
4170         this.element.removeEventListener('mousedown', this._setDomTarget, true);
4171     },
4172     remove: function() {
4173         this._detachEvent();
4174         this.element = this.style = this.targetNode = null;
4175     }
4176 });
4177 
4178 enchant.DomlessManager = enchant.Class.create({
4179     initialize: function(node) {
4180         this._domRef = [];
4181         this.targetNode = node;
4182     },
4183     _register: function(element, nextElement) {
4184         var i = this._domRef.indexOf(nextElement);
4185         if (element instanceof Array) {
4186             if (i === -1) {
4187                 Array.prototype.push.apply(this._domRef, element);
4188             } else {
4189                 Array.prototype.splice.apply(this._domRef, [i, 0].concat(element));
4190             }
4191         } else {
4192             if (i === -1) {
4193                 this._domRef.push(element);
4194             } else {
4195                 this._domRef.splice(i, 0, element);
4196             }
4197         }
4198     },
4199     getNextManager: function(manager) {
4200         var i = this.targetNode.parentNode.childNodes.indexOf(manager.targetNode);
4201         if (i !== this.targetNode.parentNode.childNodes.length - 1) {
4202             return this.targetNode.parentNode.childNodes[i + 1]._domManager;
4203         } else {
4204             return null;
4205         }
4206     },
4207     getDomElement: function() {
4208         var ret = [];
4209         this.targetNode.childNodes.forEach(function(child) {
4210             ret = ret.concat(child._domManager.getDomElement());
4211         });
4212         return ret;
4213     },
4214     getDomElementAsNext: function() {
4215         if (this._domRef.length) {
4216             return this._domRef[0];
4217         } else {
4218             var nextManager = this.getNextManager(this);
4219             if (nextManager) {
4220                 return nextManager.element;
4221             } else {
4222                 return null;
4223             }
4224         }
4225     },
4226     addManager: function(childManager, nextManager) {
4227         var parentNode = this.targetNode.parentNode;
4228         if (parentNode) {
4229             if (nextManager === null) {
4230                 nextManager = this.getNextManager(this);
4231             }
4232             if (parentNode instanceof enchant.Scene) {
4233                 parentNode._layers.Dom._domManager.addManager(childManager, nextManager);
4234             } else {
4235                 parentNode._domManager.addManager(childManager, nextManager);
4236             }
4237         }
4238         var nextElement = nextManager ? nextManager.getDomElementAsNext() : null;
4239         this._register(childManager.getDomElement(), nextElement);
4240         this.setLayer(this.layer);
4241     },
4242     removeManager: function(childManager) {
4243         var dom;
4244         var i = this._domRef.indexOf(childManager.element);
4245         if (i !== -1) {
4246             dom = this._domRef[i];
4247             dom.parentNode.removeChild(dom);
4248             this._domRef.splice(i, 1);
4249         }
4250         this.setLayer(this.layer);
4251     },
4252     setLayer: function(layer) {
4253         this.layer = layer;
4254         var node = this.targetNode;
4255         var manager;
4256         if (node.childNodes) {
4257             for (var i = 0, l = node.childNodes.length; i < l; i++) {
4258                 manager = node.childNodes[i]._domManager;
4259                 if (manager) {
4260                     manager.setLayer(layer);
4261                 }
4262             }
4263         }
4264     },
4265     render: function(inheritMat) {
4266         var matrix = enchant.Matrix.instance;
4267         var stack = matrix.stack;
4268         var node = this.targetNode;
4269         var dest = [];
4270         matrix.makeTransformMatrix(node, dest);
4271         matrix.multiply(stack[stack.length - 1], dest, dest);
4272         matrix.multiply(inheritMat, dest, inheritMat);
4273         node._matrix = inheritMat;
4274         var ox = (typeof node._originX === 'number') ? node._originX : node.width / 2 || 0;
4275         var oy = (typeof node._originY === 'number') ? node._originY : node.height / 2 || 0;
4276         var vec = [ ox, oy ];
4277         matrix.multiplyVec(dest, vec, vec);
4278         node._offsetX = vec[0] - ox;
4279         node._offsetY = vec[1] - oy;
4280         stack.push(dest);
4281     },
4282     remove: function() {
4283         this._domRef = [];
4284         this.targetNode = null;
4285     }
4286 });
4287 
4288 enchant.DomLayer = enchant.Class.create(enchant.Group, {
4289     initialize: function() {
4290         var core = enchant.Core.instance;
4291         enchant.Group.call(this);
4292 
4293         this._touchEventTarget = null;
4294 
4295         this._element = document.createElement('div');
4296         this._element.style.position = 'absolute';
4297 
4298         this._domManager = new enchant.DomManager(this, this._element);
4299         this._domManager.layer = this;
4300 
4301         this.width = core.width;
4302         this.height = core.height;
4303 
4304         var touch = [
4305             enchant.Event.TOUCH_START,
4306             enchant.Event.TOUCH_MOVE,
4307             enchant.Event.TOUCH_END
4308         ];
4309 
4310         touch.forEach(function(type) {
4311             this.addEventListener(type, function(e) {
4312                 if (this._scene) {
4313                     this._scene.dispatchEvent(e);
4314                 }
4315             });
4316         }, this);
4317 
4318         var __onchildadded = function(e) {
4319             var child = e.node;
4320             var next = e.next;
4321             var self = e.target;
4322             var nextManager = next ? next._domManager : null;
4323             enchant.DomLayer._attachDomManager(child, __onchildadded, __onchildremoved);
4324             self._domManager.addManager(child._domManager, nextManager);
4325             var render = new enchant.Event(enchant.Event.RENDER);
4326             child._dirty = true;
4327             self._domManager.layer._rendering(child, render);
4328         };
4329 
4330         var __onchildremoved = function(e) {
4331             var child = e.node;
4332             var self = e.target;
4333             self._domManager.removeManager(child._domManager);
4334             enchant.DomLayer._detachDomManager(child, __onchildadded, __onchildremoved);
4335         };
4336 
4337         this.addEventListener('childremoved', __onchildremoved);
4338         this.addEventListener('childadded', __onchildadded);
4339 
4340     },
4341     width:<