standard |
/** * enchant.js v0.6.1 * http://enchantjs.com * * Copyright Ubiquitous Entertainment Inc. * Released under the MIT license. */
(function(window, undefined){
/** * ECMA-262 5th edition Functions */ if (typeof Object.defineProperty !== 'function') { Object.defineProperty = function(obj, prop, desc) { if ('value' in desc) { obj[prop] = desc.value; } if ('get' in desc) { obj.__defineGetter__(prop, desc.get); } if ('set' in desc) { obj.__defineSetter__(prop, desc.set); } return obj; }; } if (typeof Object.defineProperties !== 'function') { Object.defineProperties = function(obj, descs) { for (var prop in descs) { if (descs.hasOwnProperty(prop)) { Object.defineProperty(obj, prop, descs[prop]); } } return obj; }; } if (typeof Object.create !== 'function') { Object.create = function(prototype, descs) { function F() { }
F.prototype = prototype; var obj = new F(); if (descs != null) { Object.defineProperties(obj, descs); } return obj; }; } if (typeof Object.getPrototypeOf !== 'function') { Object.getPrototypeOf = function(obj) { return obj.__proto__; }; }
if (typeof Function.prototype.bind !== 'function') { Function.prototype.bind = function(thisObject) { var func = this; var args = Array.prototype.slice.call(arguments, 1); var Nop = function() { }; var bound = function() { var a = args.concat(Array.prototype.slice.call(arguments)); return func.apply( this instanceof Nop ? this : thisObject || window, a); }; Nop.prototype = func.prototype; bound.prototype = new Nop(); return bound; }; }
window.getTime = (function() {
if (window.performance && window.performance.now) { return function() { return window.performance.now(); }; } else if (window.performance && window.performance.webkitNow) { return function() { return window.performance.webkitNow(); }; } else { return Date.now; } }());
/** * define requestAnimationFrame */ window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || (function() { var lastTime = window.getTime(); var frame = 1000 / 60; return function(func) { var currentTime = window.getTime(); var _id = setTimeout(function() { func(window.getTime()); }, Math.max(0, lastTime + frame - currentTime)); lastTime = currentTime; return _id; }; }());
/** * Export the library classes globally. * * When no arguments are given, all classes defined in enchant.js as well as all classes defined in * plugins will be exported. When more than one argument is given, by default only classes defined * in enchant.js will be exported. When you wish to export plugin classes you must explicitly deliver * the plugin identifiers as arguments. * * @example * enchant(); // All classes will be exported. * enchant(''); // Only classes in enchant.js will be exported. * enchant('ui'); // enchant.js classes and ui.enchant.js classes will be exported. * * @param {...String} [modules] Export module. Multiple designations possible. * @global * @type {Object} * @name enchant */ var enchant = function(modules) { if (modules != null) { if (!(modules instanceof Array)) { modules = Array.prototype.slice.call(arguments); } modules = modules.filter(function(module) { return [module].join(); }); } (function include(module, prefix) { var submodules = [], i, len; for (var prop in module) { if (module.hasOwnProperty(prop)) { if (typeof module[prop] === 'function') { window[prop] = module[prop]; } else if (typeof module[prop] === 'object' && Object.getPrototypeOf(module[prop]) === Object.prototype) { if (modules == null) { submodules.push(prop); } else { i = modules.indexOf(prefix + prop); if (i !== -1) { submodules.push(prop); modules.splice(i, 1); } } } } }
for (i = 0, len = submodules.length; i < len; i++) { include(module[submodules[i]], prefix + submodules[i] + '.'); } }(enchant, ''));
window.Game = window.Core;
if (modules != null && modules.length) { throw new Error('Cannot load module: ' + modules.join(', ')); } };
/** * export enchant */ window.enchant = enchant;
window.addEventListener("message", function(msg, origin) { try { var data = JSON.parse(msg.data); if (data.type === "event") { enchant.Core.instance.dispatchEvent(new enchant.Event(data.value)); } else if (data.type === "debug") { switch (data.value) { case "start": enchant.Core.instance.start(); break; case "pause": enchant.Core.instance.pause(); break; case "resume": enchant.Core.instance.resume(); break; case "tick": enchant.Core.instance._tick(); break; default: break; } } } catch (e) { // ignore } }, false);
/** * @name enchant.Class * @class * A Class representing a class which supports inheritance. * * @param {Function} [superclass] The class from which the * new class will inherit the class definition. * @param {*} definition Class definition. * @constructor */ enchant.Class = function(superclass, definition) { return enchant.Class.create(superclass, definition); };
/** * Create a class. * * When defining classes that inherit from other classes, the previous class is used as a base with * the superclass's constructor as default. When overriding the default constructor, it is necessary * to explicitly call the previous constructor to ensure a correct class initialization. * * @example * var Ball = Class.create({ // Creates independent class. * initialize: function(radius) { ... }, // Method definition. * fall: function() { ... } * }); * * var Ball = Class.create(Sprite); // Creates a class inheriting from "Sprite" * var Ball = Class.create(Sprite, { // Creates a class inheriting "Sprite" * initialize: function(radius) { // Overwrites constructor * Sprite.call(this, radius*2, radius*2); // Applies previous constructor. * this.image = core.assets['ball.gif']; * } * }); * * @param {Function} [superclass] The class from which the * new class will inherit the class definition. * @param {*} [definition] Class definition. * @static */ enchant.Class.create = function(superclass, definition) { if (superclass == null && definition){ throw new Error("superclass is undefined (enchant.Class.create)"); }else if(superclass == null){ throw new Error("definition is undefined (enchant.Class.create)"); }
if (arguments.length === 0) { return enchant.Class.create(Object, definition); } else if (arguments.length === 1 && typeof arguments[0] !== 'function') { return enchant.Class.create(Object, arguments[0]); }
for (var prop in definition) { if (definition.hasOwnProperty(prop)) { if (typeof definition[prop] === 'object' && definition[prop] !== null && Object.getPrototypeOf(definition[prop]) === Object.prototype) { if (!('enumerable' in definition[prop])) { definition[prop].enumerable = true; } } else { definition[prop] = { value: definition[prop], enumerable: true, writable: true }; } } } var Constructor = function() { if (this instanceof Constructor) { Constructor.prototype.initialize.apply(this, arguments); } else { return new Constructor(); } }; Constructor.prototype = Object.create(superclass.prototype, definition); Constructor.prototype.constructor = Constructor; if (Constructor.prototype.initialize == null) { Constructor.prototype.initialize = function() { superclass.apply(this, arguments); }; }
var tree = this.getInheritanceTree(superclass); for (var i = tree.length - 1; i >= 0; i--) { if (typeof tree[i]._inherited === 'function') { tree[i]._inherited(Constructor); break; } }
return Constructor; };
/** * Get the inheritance tree of this class. * @param {ConstructorFunction} * @return {...ConstructorFunction} */ enchant.Class.getInheritanceTree = function(Constructor) { var ret = []; var C = Constructor; var proto = C.prototype; while (C !== Object) { ret.push(C); proto = Object.getPrototypeOf(proto); C = proto.constructor; } return ret; };
/** * @namespace * Environment variable. * @type {Object} */ enchant.ENV = { /** * Version of enchant.js * @type {String} */ VERSION: "0.6.1", /** * The CSS vendor prefix of the current browser. * @type {String} */ VENDOR_PREFIX: (function() { var ua = navigator.userAgent; if (ua.indexOf('Opera') !== -1) { return 'O'; } else if (ua.indexOf('MSIE') !== -1) { return 'ms'; } else if (ua.indexOf('WebKit') !== -1) { return 'webkit'; } else if (navigator.product === 'Gecko') { return 'Moz'; } else { return ''; } }()), /** * Determines if the current browser supports touch. * @type {Boolean} True, if touch is enabled. */ TOUCH_ENABLED: (function() { var div = document.createElement('div'); div.setAttribute('ontouchstart', 'return'); return typeof div.ontouchstart === 'function'; }()), /** * Determines if the current browser is an iPhone with a retina display. * @return {Boolean} True, if this display is a retina display */ RETINA_DISPLAY: (function() { if (navigator.userAgent.indexOf('iPhone') !== -1 && window.devicePixelRatio === 2) { var viewport = document.querySelector('meta[name="viewport"]'); if (viewport == null) { viewport = document.createElement('meta'); document.head.appendChild(viewport); } viewport.setAttribute('content', 'width=640'); return true; } else { return false; } }()), /** * Determines if for current browser Flash should be used to play * sound instead of the native audio class. * @type {Boolean} True, if flash should be used. */ USE_FLASH_SOUND: (function() { var ua = navigator.userAgent; var vendor = navigator.vendor || ""; // non-local access, not on mobile mobile device, not on safari return (location.href.indexOf('http') === 0 && ua.indexOf('Mobile') === -1 && vendor.indexOf('Apple') !== -1); }()), /** * If click/touch event occure for these tags the setPreventDefault() method will not be called. */ USE_DEFAULT_EVENT_TAGS: ['input', 'textarea', 'select', 'area'], CANVAS_DRAWING_METHODS: [ 'putImageData', 'drawImage', 'drawFocusRing', 'fill', 'stroke', 'clearRect', 'fillRect', 'strokeRect', 'fillText', 'strokeText' ], /** * Keybind Table. * You can use 'left', 'up', 'right', 'down', 'a', 'b' for preset event. * @example * enchant.ENV.KEY_BIND_TABLE = { * 37: 'left', * 38: 'up', * 39: 'right', * 40: 'down', * 32: 'a', //-> use 'space' key as 'a button' * } */ KEY_BIND_TABLE: { 37: 'left', 38: 'up', 39: 'right', 40: 'down' }, PREVENT_DEFAULT_KEY_CODES: [37, 38, 39, 40, 32], /** * @type {Boolean} */ SOUND_ENABLED_ON_MOBILE_SAFARI: false, /** * Determines if WebAudioAPI is enabled. (true: use WebAudioAPI instead of Audio element if possible) */ USE_WEBAUDIO: (function(){ return location.protocol !== 'file:'; }()), /** * Determines if animation feature is enabled. (true: Timeline instance will be generated in new Node) */ USE_ANIMATION: true };
/** * @scope enchant.Event.prototype */ enchant.Event = enchant.Class.create({ /** * @name enchant.Event * @class * A class for an independent implementation of events * similar to DOM Events. * However, it does not include phase concept. * @param {String} type Event type. * @constructs */ initialize: function(type) { /** * The type of the event. * @type {String} */ this.type = type; /** * The target of the event. * @type {*} */ this.target = null; /** * The x coordinate of the events occurrence. * @type {Number} */ this.x = 0; /** * The y coordinate of the events occurrence. * @type {Number} */ this.y = 0; /** * The event occurrences local coordinate systems x coordinates. * @type {Number} */ this.localX = 0; /** * The event occurrences local coordinate systems y coordinates. * @type {Number} */ this.localY = 0; }, _initPosition: function(pageX, pageY) { var core = enchant.Core.instance; this.x = this.localX = (pageX - core._pageX) / core.scale; this.y = this.localY = (pageY - core._pageY) / core.scale; } });
/** * An event dispatched upon completion of core loading. * * It is necessary to wait for loading to finish and to do initial processing when preloading images. * Issued object: {@link enchant.Core} * * @example * var core = new Core(320, 320); * core.preload('player.gif'); * core.onload = function() { * ... // Describes initial core processing * }; * core.start(); * * @type {String} */ enchant.Event.LOAD = 'load';
/** * Events which are occurring during core loading. * Dispatched each time preloaded image is loaded. Issued object: {@link enchant.Core} * @type {String} */ enchant.Event.PROGRESS = 'progress';
/** * An event which is occurring when a new frame is beeing processed. * Issued object: {@link enchant.Core}, {@link enchant.Node} * @type {String} */ enchant.Event.ENTER_FRAME = 'enterframe';
/** * An event which is occurring when the frame processing is about to end. * Issued object: {@link enchant.Core} * @type {String} */ enchant.Event.EXIT_FRAME = 'exitframe';
/** * Events occurring during Scene beginning. * Issued object: {@link enchant.Scene} * @type {String} */ enchant.Event.ENTER = 'enter';
/** * Events occurring during Scene end. * Issued object: {@link enchant.Scene} * @type {String} */ enchant.Event.EXIT = 'exit';
/** * An event which is occurring when a Child is getting added to a Node. * Issued object: {@link enchant.Group}, {@link enchant.Scene} * @type {String} */ enchant.Event.CHILD_ADDED = 'childadded';
/** * An event which is occurring when the Node is added to a Group. * Issued object: {@link enchant.Node} * @type {String} */ enchant.Event.ADDED = 'added';
/** * An event which is occurring when the Node is added to a Scene. * Issued object: {@link enchant.Node} * @type {String} */ enchant.Event.ADDED_TO_SCENE = 'addedtoscene';
/** * An event which is occurring when a Child is removed from a Node. * Issued object: {@link enchant.Group}, {@link enchant.Scene} * @type {String} * @type {String} */ enchant.Event.CHILD_REMOVED = 'childremoved';
/** * An event which is occurring when the Node is deleted from a Group. * Issued object: {@link enchant.Node} * @type {String} */ enchant.Event.REMOVED = 'removed';
/** * An event which is occurring when the Node is deleted from a Scene. * Issued object: {@link enchant.Node} * @type {String} */ enchant.Event.REMOVED_FROM_SCENE = 'removedfromscene';
/** * An event occurring when a touch related to the Node has begun. * A click is also treated as touch. Issued object: {@link enchant.Node} * @type {String} */ enchant.Event.TOUCH_START = 'touchstart';
/** * An event occurring when a touch related to the Node has been moved. * A click is also treated as touch. Issued object: {@link enchant.Node} * @type {String} */ enchant.Event.TOUCH_MOVE = 'touchmove';
/** * An event which is occurring when a touch related to the Node has ended. * A Click is also treated as touch. Issued object: enchant.Node * @type {String} */ enchant.Event.TOUCH_END = 'touchend';
/** * An event which is occurring when an Entity is rendered. * Issued object: {@link enchant.Entity} * @type {String} */ enchant.Event.RENDER = 'render';
/** * An event which is occurring when a button is pressed. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.INPUT_START = 'inputstart';
/** * An event which is occurring when a button input changes. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.INPUT_CHANGE = 'inputchange';
/** * An event which is occurring when a button input ends. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.INPUT_END = 'inputend';
/** * An event which is occurring when the left button is pressed. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.LEFT_BUTTON_DOWN = 'leftbuttondown';
/** * An event which is occurring when the left button is released. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.LEFT_BUTTON_UP = 'leftbuttonup';
/** * An event which is occurring when the right button is pressed. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.RIGHT_BUTTON_DOWN = 'rightbuttondown';
/** * An event which is occurring when the right button is released. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.RIGHT_BUTTON_UP = 'rightbuttonup';
/** * An event which is occurring when the up button is pressed. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.UP_BUTTON_DOWN = 'upbuttondown';
/** * An event which is occurring when the up button is released. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.UP_BUTTON_UP = 'upbuttonup';
/** * An event which is occurring when the down button is pressed. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.DOWN_BUTTON_DOWN = 'downbuttondown';
/** * An event which is occurring when the down button is released. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.DOWN_BUTTON_UP = 'downbuttonup';
/** * An event which is occurring when the a button is pressed. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.A_BUTTON_DOWN = 'abuttondown';
/** * An event which is occurring when the a button is released. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.A_BUTTON_UP = 'abuttonup';
/** * An event which is occurring when the b button is pressed. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.B_BUTTON_DOWN = 'bbuttondown';
/** * An event which is occurring when the b button is released. * Issued object: {@link enchant.Core}, {@link enchant.Scene} * @type {String} */ enchant.Event.B_BUTTON_UP = 'bbuttonup';
/** */ enchant.Event.ADDED_TO_TIMELINE = "addedtotimeline";
/** * @type {String} */ enchant.Event.REMOVED_FROM_TIMELINE = "removedfromtimeline";
/** * @type {String} */ enchant.Event.ACTION_START = "actionstart";
/** * @type {String} */ enchant.Event.ACTION_END = "actionend";
/** * @type {String} */ enchant.Event.ACTION_TICK = "actiontick";
/** * @type {String} */ enchant.Event.ACTION_ADDED = "actionadded";
/** * @type {String} */ enchant.Event.ACTION_REMOVED = "actionremoved";
/** * @scope enchant.EventTarget.prototype */ enchant.EventTarget = enchant.Class.create({ /** * @name enchant.EventTarget * @class * A class for an independent implementation of events * similar to DOM Events. * However, it does not include the phase concept. * @extends {enchant.Event} * @constructs */ initialize: function() { this._listeners = {}; }, /** * Add a new event listener which will be executed when the event * is being dispatched. * @param {String} type Type of the events. * @param {function(e:enchant.Event)} listener Event listener to be added. */ addEventListener: function(type, listener) { var listeners = this._listeners[type]; if (listeners == null) { this._listeners[type] = [listener]; } else if (listeners.indexOf(listener) === -1) { listeners.unshift(listener);
} }, /** * Synonym for addEventListener * @see {enchant.EventTarget#addEventListener} * @param {String} type Type of the events. * @param {function(e:enchant.Event)} listener Event listener to be added. */ on: function() { this.addEventListener.apply(this, arguments); }, /** * Delete an event listener. * @param {String} type Type of the events. * @param {function(e:enchant.Event)} listener Event listener to be deleted. */ removeEventListener: function(type, listener) { var listeners = this._listeners[type]; if (listeners != null) { var i = listeners.indexOf(listener); if (i !== -1) { listeners.splice(i, 1); } } }, /** * Clear all defined event listener for a given type. * If no type is given, all listener will be removed. * @param [String] type Type of the events. */ clearEventListener: function(type) { if (type != null) { delete this._listeners[type]; } else { this._listeners = {}; } }, /** * Issue an event. * @param {enchant.Event} e Event to be issued. */ dispatchEvent: function(e) { e.target = this; e.localX = e.x - this._offsetX; e.localY = e.y - this._offsetY; if (this['on' + e.type] != null){ this['on' + e.type](e); } var listeners = this._listeners[e.type]; if (listeners != null) { listeners = listeners.slice(); for (var i = 0, len = listeners.length; i < len; i++) { listeners[i].call(this, e); } } } });
/** * @scope enchant.Core.prototype */ (function() { var core; /** * @scope enchant.Core.prototype */ enchant.Core = enchant.Class.create(enchant.EventTarget, { /** * @name enchant.Core * @class * A class which is controlling the cores main loop and scenes. * * There can be only one instance at a time, when the constructor is executed * with an instance present, the existing instance will be overwritten. The existing instance * can be accessed from {@link enchant.Core.instance}. * * @param {Number} width The width of the core screen. * @param {Number} height The height of the core screen. * @constructs * @extends enchant.EventTarget */ initialize: function(width, height) { if (window.document.body === null) { // @TODO postpone initialization after window.onload throw new Error("document.body is null. Please excute 'new Core()' in window.onload."); }
enchant.EventTarget.call(this); var initial = true; if (core) { initial = false; core.stop(); } core = enchant.Core.instance = this;
/** * The width of the core screen. * @type {Number} */ this.width = width || 320; /** * The height of the core screen. * @type {Number} */ this.height = height || 320; /** * The scaling of the core rendering. * @type {Number} */ this.scale = 1;
var stage = document.getElementById('enchant-stage'); if (!stage) { stage = document.createElement('div'); stage.id = 'enchant-stage'; // stage.style.width = window.innerWidth + 'px'; // stage.style.height = window.innerHeight + 'px'; stage.style.position = 'absolute';
if (document.body.firstChild) { document.body.insertBefore(stage, document.body.firstChild); } else { document.body.appendChild(stage); } this.scale = Math.min( window.innerWidth / this.width, window.innerHeight / this.height ); this._pageX = 0; this._pageY = 0; } else { var style = window.getComputedStyle(stage); width = parseInt(style.width, 10); height = parseInt(style.height, 10); if (width && height) { this.scale = Math.min( width / this.width, height / this.height ); } else { stage.style.width = this.width + 'px'; stage.style.height = this.height + 'px'; } while (stage.firstChild) { stage.removeChild(stage.firstChild); } stage.style.position = 'relative';
var bounding = stage.getBoundingClientRect(); this._pageX = Math.round(window.scrollX || window.pageXOffset + bounding.left); this._pageY = Math.round(window.scrollY || window.pageYOffset + bounding.top); } if (!this.scale) { this.scale = 1; } stage.style.fontSize = '12px'; stage.style.webkitTextSizeAdjust = 'none'; this._element = stage;
/** * The frame rate of the core. * @type {Number} */ this.fps = 30; /** * The amount of frames since the core was started. * @type {Number} */ this.frame = 0; /** * Indicates if the core can be executed. * @type {Boolean} */ this.ready = false; /** * Indicates if the core is currently executed. * @type {Boolean} */ this.running = false; /** * Object which stores loaded objects with the path as key. * @type {Object.<String, Surface>} */ this.assets = {}; var assets = this._assets = []; (function detectAssets(module) { if (module.assets instanceof Array) { [].push.apply(assets, module.assets); } for (var prop in module) { if (module.hasOwnProperty(prop)) { if (typeof module[prop] === 'object' && Object.getPrototypeOf(module[prop]) === Object.prototype) { detectAssets(module[prop]); } } } }(enchant));
this._scenes = []; /** * The Scene which is currently displayed. This Scene is on top of Scene stack. * @type {enchant.Scene} */ this.currentScene = null; /** * The root Scene. The Scene at bottom of Scene stack. * @type {enchant.Scene} */ this.rootScene = new enchant.Scene(); this.pushScene(this.rootScene); /** * The Scene which is getting displayed during loading. * @type {enchant.Scene} */ this.loadingScene = new enchant.Scene(); this.loadingScene.backgroundColor = '#000'; var barWidth = this.width * 0.4 | 0; var barHeight = this.width * 0.05 | 0; var border = barWidth * 0.03 | 0; var bar = new enchant.Sprite(barWidth, barHeight);
bar.x = (this.width - barWidth) / 2; bar.y = (this.height - barHeight) / 2; var image = new enchant.Surface(barWidth, barHeight); image.context.fillStyle = '#fff'; image.context.fillRect(0, 0, barWidth, barHeight); image.context.fillStyle = '#000'; image.context.fillRect(border, border, barWidth - border * 2, barHeight - border * 2); bar.image = image; var progress = 0, _progress = 0; this.addEventListener('progress', function(e) { progress = e.loaded / e.total; }); bar.addEventListener('enterframe', function() { _progress *= 0.9; _progress += progress * 0.1; image.context.fillStyle = '#fff'; image.context.fillRect(border, 0, (barWidth - border * 2) * _progress, barHeight); }); this.loadingScene.addChild(bar);
this._mousedownID = 0; this._surfaceID = 0; this._soundID = 0;
/** * @type {Boolean} * @private */ this._activated = false;
this._offsetX = 0; this._offsetY = 0;
/** * Object that saves the current input state for the core. * @type {Object.<String, Boolean>} */ this.input = {}; this._keybind = enchant.ENV.KEY_BIND_TABLE || {};
var c = 0; ['left', 'right', 'up', 'down', 'a', 'b'].forEach(function(type) { this.addEventListener(type + 'buttondown', function(e) { var inputEvent; if (!this.input[type]) { this.input[type] = true; inputEvent = new enchant.Event((c++) ? 'inputchange' : 'inputstart'); this.dispatchEvent(inputEvent); } this.currentScene.dispatchEvent(e); if (inputEvent) { this.currentScene.dispatchEvent(inputEvent); } }); this.addEventListener(type + 'buttonup', function(e) { var inputEvent; if (this.input[type]) { this.input[type] = false; inputEvent = new enchant.Event((--c) ? 'inputchange' : 'inputend'); this.dispatchEvent(inputEvent); } this.currentScene.dispatchEvent(e); if (inputEvent) { this.currentScene.dispatchEvent(inputEvent); } }); }, this);
if (initial) { stage = enchant.Core.instance._element; var evt; document.addEventListener('keydown', function(e) { core.dispatchEvent(new enchant.Event('keydown')); if (enchant.ENV.PREVENT_DEFAULT_KEY_CODES.indexOf(e.keyCode) !== -1) { e.preventDefault(); e.stopPropagation(); }
if (!core.running) { return; } var button = core._keybind[e.keyCode]; if (button) { evt = new enchant.Event(button + 'buttondown'); core.dispatchEvent(evt); } }, true); document.addEventListener('keyup', function(e) { if (!core.running) { return; } var button = core._keybind[e.keyCode]; if (button) { evt = new enchant.Event(button + 'buttonup'); core.dispatchEvent(evt); } }, true);
if (enchant.ENV.TOUCH_ENABLED) { stage.addEventListener('touchstart', function(e) { var tagName = (e.target.tagName).toLowerCase(); if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) { e.preventDefault(); if (!core.running) { e.stopPropagation(); } } }, true); stage.addEventListener('touchmove', function(e) { var tagName = (e.target.tagName).toLowerCase(); if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) { e.preventDefault(); if (!core.running) { e.stopPropagation(); } } }, true); stage.addEventListener('touchend', function(e) { var tagName = (e.target.tagName).toLowerCase(); if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) { e.preventDefault(); if (!core.running) { e.stopPropagation(); } } }, true); } stage.addEventListener('mousedown', function(e) { var tagName = (e.target.tagName).toLowerCase(); if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) { e.preventDefault(); core._mousedownID++; if (!core.running) { e.stopPropagation(); } } }, true); stage.addEventListener('mousemove', function(e) { var tagName = (e.target.tagName).toLowerCase(); if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) { e.preventDefault(); if (!core.running) { e.stopPropagation(); } } }, true); stage.addEventListener('mouseup', function(e) { var tagName = (e.target.tagName).toLowerCase(); if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) { e.preventDefault(); if (!core.running) { e.stopPropagation(); } } }, true); core._touchEventTarget = {}; if (enchant.ENV.TOUCH_ENABLED) { stage.addEventListener('touchstart', function(e) { var core = enchant.Core.instance; var evt = new enchant.Event(enchant.Event.TOUCH_START); var touches = e.changedTouches; var touch, target; for (var i = 0, l = touches.length; i < l; i++) { touch = touches[i]; evt._initPosition(touch.pageX, touch.pageY); target = core.currentScene._determineEventTarget(evt); core._touchEventTarget[touch.identifier] = target; target.dispatchEvent(evt); } }, false); stage.addEventListener('touchmove', function(e) { var core = enchant.Core.instance; var evt = new enchant.Event(enchant.Event.TOUCH_MOVE); var touches = e.changedTouches; var touch, target; for (var i = 0, l = touches.length; i < l; i++) { touch = touches[i]; target = core._touchEventTarget[touch.identifier]; if (target) { evt._initPosition(touch.pageX, touch.pageY); target.dispatchEvent(evt); } } }, false); stage.addEventListener('touchend', function(e) { var core = enchant.Core.instance; var evt = new enchant.Event(enchant.Event.TOUCH_END); var touches = e.changedTouches; var touch, target; for (var i = 0, l = touches.length; i < l; i++) { touch = touches[i]; target = core._touchEventTarget[touch.identifier]; if (target) { evt._initPosition(touch.pageX, touch.pageY); target.dispatchEvent(evt); delete core._touchEventTarget[touch.identifier]; } } }, false); } stage.addEventListener('mousedown', function(e) { var core = enchant.Core.instance; var evt = new enchant.Event(enchant.Event.TOUCH_START); evt._initPosition(e.pageX, e.pageY); var target = core.currentScene._determineEventTarget(evt); core._touchEventTarget[core._mousedownID] = target; target.dispatchEvent(evt); }, false); stage.addEventListener('mousemove', function(e) { var core = enchant.Core.instance; var evt = new enchant.Event(enchant.Event.TOUCH_MOVE); evt._initPosition(e.pageX, e.pageY); var target = core._touchEventTarget[core._mousedownID]; if (target) { target.dispatchEvent(evt); } }, false); stage.addEventListener('mouseup', function(e) { var core = enchant.Core.instance; var evt = new enchant.Event(enchant.Event.TOUCH_END); evt._initPosition(e.pageX, e.pageY); core._touchEventTarget[core._mousedownID].dispatchEvent(evt); delete core._touchEventTarget[core._mousedownID]; }, false); } }, /** * Performs a file preload. * * Sets files which are to be preloaded. When {@link enchant.Core#start} is called the * actual loading takes place. When all files are loaded, a {@link enchant.Event.LOAD} event * is dispatched from the Core object. Depending on the type of the file different objects will be * created and stored in {@link enchant.Core#assets} Variable. * When an image file is loaded, an {@link enchant.Surface} is created. If a sound file is loaded, an * {@link enchant.Sound} object is created. Otherwise it will be accessible as a string. * * In addition, because this Surface object used made with {@link enchant.Surface.load}, * direct object manipulation is not possible. Refer to the items of {@link enchant.Surface.load} * * @example * core.preload('player.gif'); * core.onload = function() { * var sprite = new Sprite(32, 32); * sprite.image = core.assets['player.gif']; // Access via path * ... * }; * core.start(); * * @param {...String} assets Path of images to be preloaded. Multiple settings possible. */ preload: function(assets) { if (!(assets instanceof Array)) { assets = Array.prototype.slice.call(arguments); } [].push.apply(this._assets, assets); }, /** * Loads a file. * * @param {String} asset File path of the resource to be loaded. * @param {Function} [callback] Function called up when file loading is finished. */ load: function(src, callback) { if (callback == null) { callback = function() { }; }
var ext = enchant.Core.findExt(src);
if (enchant.Core._loadFuncs[ext]) { enchant.Core._loadFuncs[ext].call(this, src, callback, ext); } else { var req = new XMLHttpRequest(); req.open('GET', src, true); req.onreadystatechange = function(e) { if (req.readyState === 4) { if (req.status !== 200 && req.status !== 0) { throw new Error(req.status + ': ' + 'Cannot load an asset: ' + src); }
var type = req.getResponseHeader('Content-Type') || ''; if (type.match(/^image/)) { core.assets[src] = enchant.Surface.load(src); core.assets[src].addEventListener('load', callback); } else if (type.match(/^audio/)) { core.assets[src] = enchant.Sound.load(src, type); core.assets[src].addEventListener('load', callback); } else { core.assets[src] = req.responseText; callback(); } } }; req.send(null); } }, /** * Start the core. * * Obeying the frame rate set in {@link enchant.Core#fps}, the frame in * {@link enchant.Core#currentScene} will be updated. If images to preload are present, * loading will begin and the loading screen will be displayed. */ start: function() { var onloadTimeSetter = function() { this.currentTime = this.getTime(); this._nextTime = 0; this.removeEventListener('load', onloadTimeSetter); this.running = true; this.ready = true; this._requestNextFrame(); }; this.addEventListener('load', onloadTimeSetter);
if (!this._activated && this._assets.length) { this._activated = true; if (enchant.Sound.enabledInMobileSafari && !core._touched && enchant.ENV.VENDOR_PREFIX === 'webkit' && enchant.ENV.TOUCH_ENABLED) { var scene = new enchant.Scene(); scene.backgroundColor = '#000'; var size = Math.round(core.width / 10); var sprite = new enchant.Sprite(core.width, size); sprite.y = (core.height - size) / 2; sprite.image = new enchant.Surface(core.width, size); sprite.image.context.fillStyle = '#fff'; sprite.image.context.font = (size - 1) + 'px bold Helvetica,Arial,sans-serif'; var width = sprite.image.context.measureText('Touch to Start').width; sprite.image.context.fillText('Touch to Start', (core.width - width) / 2, size - 1); scene.addChild(sprite); document.addEventListener('touchstart', function() { core._touched = true; core.removeScene(scene); core.start(); }, true); core.pushScene(scene); return; }
var o = {}; var assets = this._assets.filter(function(asset) { return asset in o ? false : o[asset] = true; }); var loaded = 0, len = assets.length, loadFunc = function() { var e = new enchant.Event('progress'); e.loaded = ++loaded; e.total = len; core.dispatchEvent(e); if (loaded === len) { core.removeScene(core.loadingScene); core.dispatchEvent(new enchant.Event('load')); } };
for (var i = 0; i < len; i++) { this.load(assets[i], loadFunc); } this.pushScene(this.loadingScene); } else { this.dispatchEvent(new enchant.Event('load')); } }, /** * Begin core debug mode. * * Core debug mode can be set to on even if enchant.Core.instance._debug * flag is already set to true. */ debug: function() { this._debug = true; this.start(); }, actualFps: { get: function() { return this._actualFps || this.fps; } }, /** * @private */ _requestNextFrame: function() { if (!this.ready) { return; } var core = this; window.requestAnimationFrame(core._checkTick); }, /** * @private */ _checkTick: function(now) { var core = enchant.Core.instance; if (core._nextTime < now) { // if enough time has passed, execute _tick core._tick(now); } else { // if enough time has not passed yet, request next frame window.requestAnimationFrame(core._checkTick); } }, _tick: function(now) { var e = new enchant.Event('enterframe'); e.elapsed = now - this.currentTime;
// frame fragment time, will be used in _checkTick this._nextTime = now + 1000 / this.fps; this._actualFps = e.elapsed > 0 ? (1000 / e.elapsed) : 0;
var nodes = this.currentScene.childNodes.slice(); var push = Array.prototype.push; while (nodes.length) { var node = nodes.pop(); node.age++; node.dispatchEvent(e); if (node.childNodes) { push.apply(nodes, node.childNodes); } }
this.currentScene.age++; this.currentScene.dispatchEvent(e); this.dispatchEvent(e);
this.dispatchEvent(new enchant.Event('exitframe')); this.frame++; this._requestNextFrame(); }, getTime: function() { return window.getTime(); }, /** * Stops the core. * * The frame will not be updated, and player input will not be accepted anymore. * Core can be restarted using {@link enchant.Core#start}. */ stop: function() { this.ready = false; this.running = false; }, /** * Stops the core. * * The frame will not be updated, and player input will not be accepted anymore. * Core can be started again using {@link enchant.Core#start}. */ pause: function() { this.ready = false; }, /** * Resumes the core. */ resume: function() { if (this.ready) { return; } this.currentTime = this.getTime(); this.ready = true; this.running = true; this._requestNextFrame(); },
/** * Switch to a new Scene. * * Scenes are controlled using a stack, and the display order also obeys that stack order. * When {@link enchant.Core#pushScene} is executed, the Scene can be brought to the top of stack. * Frames will be updated in the Scene which is on the top of the stack. * * @param {enchant.Scene} scene The new scene to be switched to. * @return {enchant.Scene} The new Scene. */ pushScene: function(scene) { this._element.appendChild(scene._element); if (this.currentScene) { this.currentScene.dispatchEvent(new enchant.Event('exit')); } this.currentScene = scene; this.currentScene.dispatchEvent(new enchant.Event('enter')); return this._scenes.push(scene); }, /** * Ends the current Scene, return to the previous Scene. * * Scenes are controlled using a stack, and the display order also obeys that stack order. * When {@link enchant.Core#popScene} is executed, the Scene at the top of the stack * will be removed and returned. * * @return {enchant.Scene} Ended Scene. */ popScene: function() { if (this.currentScene === this.rootScene) { return this.currentScene; } this._element.removeChild(this.currentScene._element); this.currentScene.dispatchEvent(new enchant.Event('exit')); this.currentScene = this._scenes[this._scenes.length - 2]; this.currentScene.dispatchEvent(new enchant.Event('enter')); return this._scenes.pop(); }, /** * Overwrites the current Scene with a new Scene. * * {@link enchant.Core#popScene}, {@link enchant.Core#pushScene} are executed after * each other to replace to current scene with the new scene. * * @param {enchant.Scene} scene The new scene which will replace the previous scene. * @return {enchant.Scene} The new Scene. */ replaceScene: function(scene) { this.popScene(); return this.pushScene(scene); }, /** * Removes a Scene. * * Removes a Scene from the Scene stack. * * @param {enchant.Scene} scene Scene to be removed. * @return {enchant.Scene} The deleted Scene. */ removeScene: function(scene) { if (this.currentScene === scene) { return this.popScene(); } else { var i = this._scenes.indexOf(scene); if (i !== -1) { this._scenes.splice(i, 1); this._element.removeChild(scene._element); return scene; } else { return null; } } }, /** * Set a key binding. * * Maps an input key to an enchant.js left, right, up, down, a, b button. * * @param {Number} key Key code for the button which will be bound. * @param {String} button The enchant.js button (left, right, up, down, a, b). */ keybind: function(key, button) { this._keybind[key] = button; }, /** * Get the elapsed core time (not actual) from when core.start was called. * @return {Number} The elapsed time (seconds) */ getElapsedTime: function() { return this.frame / this.fps; } });
enchant.Core._loadFuncs = {}; enchant.Core._loadFuncs['jpg'] = enchant.Core._loadFuncs['jpeg'] = enchant.Core._loadFuncs['gif'] = enchant.Core._loadFuncs['png'] = enchant.Core._loadFuncs['bmp'] = function(src, callback) { this.assets[src] = enchant.Surface.load(src); this.assets[src].addEventListener('load', callback); }; enchant.Core._loadFuncs['mp3'] = enchant.Core._loadFuncs['aac'] = enchant.Core._loadFuncs['m4a'] = enchant.Core._loadFuncs['wav'] = enchant.Core._loadFuncs['ogg'] = function(src, callback, ext) { this.assets[src] = enchant.Sound.load(src, 'audio/' + ext, callback); };
/** * Get the file extension from a path * @param path * @return {*} */ enchant.Core.findExt = function(path) { var matched = path.match(/\.\w+$/); if (matched && matched.length > 0) { return matched[0].slice(1).toLowerCase(); }
// for data URI if (path.indexOf('data:') === 0) { return path.split(/[\/;]/)[1].toLowerCase(); } return null; };
/** * The Current Core instance. * @type {enchant.Core} * @static */ enchant.Core.instance = null; }());
/** * enchant.Core is moved to enchant.Core from v0.6 * @type {*} */ enchant.Game = enchant.Core; /** * @scope enchant.Node.prototype */ enchant.Node = enchant.Class.create(enchant.EventTarget, { /** * @name enchant.Node * @class * Base class for objects in the display tree which is rooted at a Scene. * Not to be used directly. * @constructs * @extends enchant.EventTarget */ initialize: function() { enchant.EventTarget.call(this);
this._dirty = false;
this._matrix = [ 1, 0, 0, 1, 0, 0 ];
this._x = 0; this._y = 0; this._offsetX = 0; this._offsetY = 0;
/** * The age (frames) of this node which will be increased before this node receives {@link enchant.Event.ENTER_FRAME} event. * @type {Number} */ this.age = 0;
/** * Parent Node of this Node. * @type {enchant.Group} */ this.parentNode = null; /** * Scene to which Node belongs. * @type {enchant.Scene} */ this.scene = null;
this.addEventListener('touchstart', function(e) { if (this.parentNode) { this.parentNode.dispatchEvent(e); } }); this.addEventListener('touchmove', function(e) { if (this.parentNode) { this.parentNode.dispatchEvent(e); } }); this.addEventListener('touchend', function(e) { if (this.parentNode) { this.parentNode.dispatchEvent(e); } });
/** */ if(enchant.ENV.USE_ANIMATION){ var tl = this.tl = new enchant.Timeline(this); } }, /** * Move the Node to the given target location. * @param {Number} x Target x coordinates. * @param {Number} y Target y coordinates. */ moveTo: function(x, y) { this._x = x; this._y = y; this._dirty = true; }, /** * Move the Node relative to its current position. * @param {Number} x x axis movement distance. * @param {Number} y y axis movement distance. */ moveBy: function(x, y) { this._x += x; this._y += y; this._dirty = true; }, /** * x coordinates of the Node. * @type {Number} */ x: { get: function() { return this._x; }, set: function(x) { this._x = x; this._dirty = true; } }, /** * y coordinates of the Node. * @type {Number} */ y: { get: function() { return this._y; }, set: function(y) { this._y = y; this._dirty = true; } }, _updateCoordinate: function() { var node = this; var tree = [ node ]; var parent = node.parentNode; var scene = this.scene; while (parent && node._dirty) { tree.unshift(parent); node = node.parentNode; parent = node.parentNode; } var matrix = enchant.Matrix.instance; var stack = matrix.stack; var mat = []; var newmat, ox, oy; stack.push(tree[0]._matrix); for (var i = 1, l = tree.length; i < l; i++) { node = tree[i]; newmat = []; matrix.makeTransformMatrix(node, mat); matrix.multiply(stack[stack.length - 1], mat, newmat); node._matrix = newmat; stack.push(newmat); ox = (typeof node._originX === 'number') ? node._originX : node._width / 2 || 0; oy = (typeof node._originY === 'number') ? node._originY : node._height / 2 || 0; var vec = [ ox, oy ]; matrix.multiplyVec(newmat, vec, vec); node._offsetX = vec[0] - ox; node._offsetY = vec[1] - oy; node._dirty = false; } matrix.reset(); }, remove: function() { if (this._listener) { this.clearEventListener(); } if (this.parentNode) { this.parentNode.removeChild(this); } } });
var _intersectBetweenClassAndInstance = function(Class, instance) { /* return Class.collection.filter(function(classInstance) { return enchant.Entity.prototype._intersectone.call(instance, classInstance); }); */ var ret = []; var c; for (var i = 0, l = Class.collection.length; i < l; i++) { c = Class.collection[i]; if (instance._intersectone(c)) { ret.push(c); } } return ret; };
var _intersectBetweenClassAndClass = function(Class1, Class2) { var ret = []; /* Class1.collection.forEach(function(instance1) { Class2.collection.forEach(function(instance2) { if (enchant.Entity.prototype._intersectone.call(instance1, instance2)) { ret.push([ instance1, instance2 ]); } }); }); */ var c1, c2; for (var i = 0, l = Class1.collection.length; i < l; i++) { c1 = Class1.collection[i]; for (var j = 0, ll = Class2.collection.length; j < ll; j++) { c2 = Class2.collection[j]; if (c1._intersectone(c2)) { ret.push([ c1, c2 ]); } } } return ret; };
var _staticintersect = function(other) { if (other instanceof enchant.Entity) { return _intersectBetweenClassAndInstance(this, other); } else if (typeof other === 'function' && other.collection) { return _intersectBetweenClassAndClass(this, other); } return false; };
/** * @scope enchant.Entity.prototype */ enchant.Entity = enchant.Class.create(enchant.Node, { /** * @name enchant.Entity * @class * A class with objects displayed as DOM elements. Not to be used directly. * @constructs * @extends enchant.Node */ initialize: function() { var core = enchant.Core.instance; enchant.Node.call(this);
this._rotation = 0; this._scaleX = 1; this._scaleY = 1;
this._touchEnabled = true; this._clipping = false;
this._originX = null; this._originY = null;
this._width = 0; this._height = 0; this._backgroundColor = null; this._opacity = 1; this._visible = true; this._buttonMode = null;
this._style = {}; this.__styleStatus = {};
/** */ this.compositeOperation = null;
/** * Defines this Entity as a button. * When touched or clicked the corresponding button event is dispatched. * Valid buttonModes are: left, right, up, down, a, b. * @type {String} */ this.buttonMode = null; /** * Indicates if this Entity is being clicked. * Only works when {@link enchant.Entity.buttonMode} is set. * @type {Boolean} */ this.buttonPressed = false; this.addEventListener('touchstart', function() { if (!this.buttonMode) { return; } this.buttonPressed = true; var e = new enchant.Event(this.buttonMode + 'buttondown'); this.dispatchEvent(e); core.dispatchEvent(e); }); this.addEventListener('touchend', function() { if (!this.buttonMode) { return; } this.buttonPressed = false; var e = new enchant.Event(this.buttonMode + 'buttonup'); this.dispatchEvent(e); core.dispatchEvent(e); });
this.enableCollection(); }, /** * The width of the Entity. * @type {Number} */ width: { get: function() { return this._width; }, set: function(width) { this._width = width; this._dirty = true; } }, /** * The height of the Entity. * @type {Number} */ height: { get: function() { return this._height; }, set: function(height) { this._height = height; this._dirty = true; } }, /** * The Entity background color. * Must be provided in the same format as the CSS 'color' property. * @type {String} */ backgroundColor: { get: function() { return this._backgroundColor; }, set: function(color) { this._backgroundColor = color; } }, /** * The transparency of this entity. * Defines the transparency level from 0 to 1 * (0 is completely transparent, 1 is completely opaque). * @type {Number} */ opacity: { get: function() { return this._opacity; }, set: function(opacity) { this._opacity = parseFloat(opacity); } }, /** * Indicates whether or not to display this Entity. * @type {Boolean} */ visible: { get: function() { return this._visible; }, set: function(visible) { this._visible = visible; } }, /** * Indicates whether or not this Entity can be touched. * @type {Boolean} */ touchEnabled: { get: function() { return this._touchEnabled; }, set: function(enabled) { this._touchEnabled = enabled; if (this._touchEnabled = enabled) { this._style.pointerEvents = 'all'; } else { this._style.pointerEvents = 'none'; } } }, /** * Performs a collision detection based on whether or not the bounding rectangles are intersecting. * @param {*} other An object like Entity, with the properties x, y, width, height, which are used for the * collision detection. * @return {Boolean} True, if a collision was detected. */ intersect: function(other) { if (other instanceof enchant.Entity) { return this._intersectone(other); } else if (typeof other === 'function' && other.collection) { return _intersectBetweenClassAndInstance(other, this); } return false; }, _intersectone: function(other) { if (this._dirty) { this._updateCoordinate(); } if (other._dirty) { other._updateCoordinate(); } return this._offsetX < other._offsetX + other.width && other._offsetX < this._offsetX + this.width && this._offsetY < other._offsetY + other.height && other._offsetY < this._offsetY + this.height; }, /** * Performs a collision detection based on distance from the Entity's central point. * @param {*} other An object like Entity, with properties x, y, width, height, which are used for the * collision detection. * @param {Number} [distance] The greatest distance to be considered for a collision. * The default distance is the average of both objects width and height. * @return {Boolean} True, if a collision was detected. */ within: function(other, distance) { if (this._dirty) { this._updateCoordinate(); } if (other._dirty) { other._updateCoordinate(); } if (distance == null) { distance = (this.width + this.height + other.width + other.height) / 4; } var _; return (_ = this._offsetX - other._offsetX + (this.width - other.width) / 2) * _ + (_ = this._offsetY - other._offsetY + (this.height - other.height) / 2) * _ < distance * distance; }, /** * Enlarges or shrinks this Sprite. * @param {Number} x Scaling factor on the x axis. * @param {Number} [y] Scaling factor on the y axis. */ scale: function(x, y) { this._scaleX *= x; this._scaleY *= (y != null) ? y : x; this._dirty = true; }, /** * Rotate this Sprite. * @param {Number} deg Rotation angle (degree). */ rotate: function(deg) { this._rotation += deg; this._dirty = true; }, /** * Scaling factor on the x axis of this Sprite. * @type {Number} */ scaleX: { get: function() { return this._scaleX; }, set: function(scaleX) { this._scaleX = scaleX; this._dirty = true; } }, /** * Scaling factor on the y axis of this Sprite. * @type {Number} */ scaleY: { get: function() { return this._scaleY; }, set: function(scaleY) { this._scaleY = scaleY; this._dirty = true; } }, /** * Sprite rotation angle (degree). * @type {Number} */ rotation: { get: function() { return this._rotation; }, set: function(rotation) { this._rotation = rotation; this._dirty = true; } }, /** * The point of origin used for rotation and scaling. * @type {Number} */ originX: { get: function() { return this._originX; }, set: function(originX) { this._originX = originX; this._dirty = true; } }, /** * The point of origin used for rotation and scaling. * @type {Number} */ originY: { get: function() { return this._originY; }, set: function(originY) { this._originY = originY; this._dirty = true; } }, /** */ enableCollection: function() { this.addEventListener('addedtoscene', this._addSelfToCollection); this.addEventListener('removedfromscene', this._removeSelfFromCollection); if (this.scene) { this._addSelfToCollection(); } }, /** */ disableCollection: function() { this.removeEventListener('addedtoscene', this._addSelfToCollection); this.removeEventListener('removedfromscene', this._removeSelfFromCollection); if (this.scene) { this._removeSelfFromCollection(); } }, _addSelfToCollection: function() { var Constructor = this.getConstructor(); Constructor._collectionTarget.forEach(function(C) { C.collection.push(this); }, this); }, _removeSelfFromCollection: function() { var Constructor = this.getConstructor(); Constructor._collectionTarget.forEach(function(C) { var i = C.collection.indexOf(this); if (i !== -1) { C.collection.splice(i, 1); } }, this); }, getConstructor: function() { return Object.getPrototypeOf(this).constructor; } });
var _collectizeConstructor = function(Constructor) { if (Constructor._collective) { return; } var rel = enchant.Class.getInheritanceTree(Constructor); var i = rel.indexOf(enchant.Entity); if (i !== -1) { Constructor._collectionTarget = rel.splice(0, i + 1); } else { Constructor._collectionTarget = []; } Constructor.intersect = _staticintersect; Constructor.collection = []; Constructor._collective = true; };
_collectizeConstructor(enchant.Entity);
enchant.Entity._inherited = function(subclass) { _collectizeConstructor(subclass); };
/** * @scope enchant.Sprite.prototype */ enchant.Sprite = enchant.Class.create(enchant.Entity, { /** * @name enchant.Sprite * @class * Class which can display images. * * @param {Number} [width] Sprite width. * @param {Number} [height] Sprite height. * @example * var bear = new Sprite(32, 32); * bear.image = core.assets['chara1.gif']; * * @constructs * @extends enchant.Entity */ initialize: function(width, height) { enchant.Entity.call(this);
this.width = width; this.height = height; this._image = null; this._frameLeft = 0; this._frameTop = 0; this._frame = 0; this._frameSequence = []; /** */ this.addEventListener('enterframe', function() { if (this._frameSequence.length !== 0) { var nextFrame = this._frameSequence.shift(); if (nextFrame === null) { this._frameSequence = []; } else { this._setFrame(nextFrame); this._frameSequence.push(nextFrame); } } }); }, /** * Image displayed in the Sprite. * @type {enchant.Surface} */ image: { get: function() { return this._image; }, set: function(image) { if (image === this._image) { return; } this._image = image; this._setFrame(this._frame); } }, /** * Indizes of the frames to be displayed. * Frames with same width and height as Sprite will be arrayed from upper left corner of the * {@link enchant.Sprite#image} image. When a sequence of numbers is provided, the displayed frame * will switch automatically. At the end of the array the sequence will restart. By setting * a value within the sequence to null, the frame switching is stopped. * @example * var sprite = new Sprite(32, 32); * sprite.frame = [0, 1, 0, 2] * //-> 0, 1, 0, 2, 0, 1, 0, 2,.. * sprite.frame = [0, 1, 0, 2, null] * //-> 0, 1, 0, 2, (2, 2,.. :stop) * * @type {Number|Array} */ frame: { get: function() { return this._frame; }, set: function(frame) { if(this._frame === frame) { return; } if (frame instanceof Array) { var frameSequence = frame; var nextFrame = frameSequence.shift(); this._setFrame(nextFrame); frameSequence.push(nextFrame); this._frameSequence = frameSequence; } else { this._setFrame(frame); this._frameSequence = []; this._frame = frame; } } }, /** * 0 <= frame * @param frame * @private */ _setFrame: function(frame) { var image = this._image; var row, col; if (image != null) { this._frame = frame; row = image.width / this._width | 0; this._frameLeft = (frame % row | 0) * this._width; this._frameTop = (frame / row | 0) * this._height % image.height; } }, /** * width of Sprite * @type {Number} */ width: { get: function() { return this._width; }, set: function(width) { this._width = width; this._setFrame(); this._dirty = true; } }, /** * height of Sprite * @type {Number} */ height: { get: function() { return this._height; }, set: function(height) { this._height = height; this._setFrame(); this._dirty = true; } }, cvsRender: function(ctx) { if (this._image == null || this._width === 0 || this._height === 0) { return; } var image = this._image; var element = image._element; var sx = this._frameLeft; var sy = this._frameTop; var sw = Math.min(this.width, image.width - sx); var sh = Math.min(this.height, image.height - sy); var dw = Math.min(image.width, this.width); var dh = Math.min(image.height, this.height); var x, y, w, h; for (y = 0; y < this.height; y += dh) { h = (this.height < y + dh) ? this.height - y : dh; for (x = 0; x < this.width; x += dw) { w = (this.width < x + dw) ? this.width - x : dw; ctx.drawImage(element, sx, sy, sw * w / dw, sh * h / dh, x, y, w, h); } } }, domRender: function(element) { if (this._image) { if (this._image._css) { this._style['background-image'] = this._image._css; this._style['background-position'] = -this._frameLeft + 'px ' + -this._frameTop + 'px'; } else if (this._image._element) { } } } });
/** * @scope enchant.Label.prototype */ enchant.Label = enchant.Class.create(enchant.Entity, { /** * @name enchant.Label * @class * A class for Label object. * @constructs * @extends enchant.Entity */ initialize: function(text) { enchant.Entity.call(this);
this.width = 300; this.font = '14px serif'; this.text = text || ''; this.textAlign = 'left'; }, /** * Text to be displayed. * @type {String} */ text: { get: function() { return this._text; }, set: function(text) { if(this._text === text) { return; } this._text = text; text = text.replace(/<(br|BR) ?\/?>/g, '<br/>'); this._splitText = text.split('<br/>'); this.updateBoundArea(); for (var i = 0, l = this._splitText.length; i < l; i++) { text = this._splitText[i]; var metrics = this.getMetrics(text); this._splitText[i] = {}; this._splitText[i].text = text; this._splitText[i].height = metrics.height; } } }, /** * Specifies horizontal alignment of text. * Can be set according to the format of the CSS 'text-align' property. * @type {String} */ textAlign: { get: function() { return this._style['text-align']; }, set: function(textAlign) { this._style['text-align'] = textAlign; this.updateBoundArea(); } }, /** * Font settings. * Can be set according to the format of the CSS 'font' property. * @type {String} */ font: { get: function() { return this._style.font; }, set: function(font) { this._style.font = font; this.updateBoundArea(); } }, /** * Text color settings. * Can be set according to the format of the CSS 'color' property. * @type {String} */ color: { get: function() { return this._style.color; }, set: function(color) { this._style.color = color; } }, cvsRender: function(ctx) { var x, y = 0; var text, buf, c; if (this._splitText) { ctx.textBaseline = 'top'; ctx.font = this.font; ctx.fillStyle = this.color || '#000000'; for (var i = 0, l = this._splitText.length; i < l; i++) { text = this._splitText[i]; buf = ''; for (var j = 0, ll = text.text.length; j < ll; j++) { c = text.text[j]; if (ctx.measureText(buf).width > this.width) { ctx.fillText(buf, 0, y); y += text.height - 1; buf = ''; } buf += c; } if (this.textAlign === 'right') { x = this.width - ctx.measureText(buf).width; } else if (this.textAlign === 'center') { x = (this.width - ctx.measureText(buf).width) / 2; } else { x = 0; } ctx.fillText(buf, x, y); y += text.height - 1; } } }, domRender: function(element) { if (element.innerHTML !== this._text) { element.innerHTML = this._text; } }, detectRender: function(ctx) { ctx.fillRect(this._boundOffset, 0, this._boundWidth, this._boundHeight); }, updateBoundArea: function() { var metrics = this.getMetrics(); this._boundWidth = metrics.width; this._boundHeight = metrics.height; if (this.textAlign === 'right') { this._boundOffset = this.width - this._boundWidth; } else if (this.textAlign === 'center') { this._boundOffset = (this.width - this._boundWidth) / 2; } else { this._boundOffset = 0; } } });
enchant.Label.prototype.getMetrics = function(text) { var ret = {}; var div, width, height; if (document.body) { div = document.createElement('div'); for (var prop in this._style) { if(prop !== 'width' && prop !== 'height') { div.style[prop] = this._style[prop]; } } div.innerHTML = text || this._text; document.body.appendChild(div); ret.height = parseInt(getComputedStyle(div).height, 10) + 1; div.style.position = 'absolute'; ret.width = parseInt(getComputedStyle(div).width, 10) + 1; document.body.removeChild(div); } else { ret.width = this.width; ret.height = this.height; } return ret; };
/** * @scope enchant.Map.prototype */ enchant.Map = enchant.Class.create(enchant.Entity, { /** * @name enchant.Map * @class * A class to create and display maps from a tile set. * * @param {Number} tileWidth Tile width. * @param {Number} tileHeight Tile height. * @constructs * @extends enchant.Entity */ initialize: function(tileWidth, tileHeight) { var core = enchant.Core.instance;
enchant.Entity.call(this);
var surface = new enchant.Surface(core.width, core.height); this._surface = surface; var canvas = surface._element; canvas.style.position = 'absolute'; if (enchant.ENV.RETINA_DISPLAY && core.scale === 2) { canvas.width = core.width * 2; canvas.height = core.height * 2; this._style.webkitTransformOrigin = '0 0'; this._style.webkitTransform = 'scale(0.5)'; } else { canvas.width = core.width; canvas.height = core.height; } this._context = canvas.getContext('2d');
this._tileWidth = tileWidth || 0; this._tileHeight = tileHeight || 0; this._image = null; this._data = [ [ [] ] ]; this._dirty = false; this._tight = false;
this.touchEnabled = false;
/** * Two dimensional array to store if collision detection should be performed for a tile. * @type {Array.<Array.<Number>>} */ this.collisionData = null;
this._listeners['render'] = null; this.addEventListener('render', function() { if (this._dirty || this._previousOffsetX == null) { this.redraw(0, 0, core.width, core.height); } else if (this._offsetX !== this._previousOffsetX || this._offsetY !== this._previousOffsetY) { if (this._tight) { var x = -this._offsetX; var y = -this._offsetY; var px = -this._previousOffsetX; var py = -this._previousOffsetY; var w1 = x - px + core.width; var w2 = px - x + core.width; var h1 = y - py + core.height; var h2 = py - y + core.height; if (w1 > this._tileWidth && w2 > this._tileWidth && h1 > this._tileHeight && h2 > this._tileHeight) { var sx, sy, dx, dy, sw, sh; if (w1 < w2) { sx = 0; dx = px - x; sw = w1; } else { sx = x - px; dx = 0; sw = w2; } if (h1 < h2) { sy = 0; dy = py - y; sh = h1; } else { sy = y - py; dy = 0; sh = h2; }
if (core._buffer == null) { core._buffer = document.createElement('canvas'); core._buffer.width = this._context.canvas.width; core._buffer.height = this._context.canvas.height; } var context = core._buffer.getContext('2d'); if (this._doubledImage) { context.clearRect(0, 0, sw * 2, sh * 2); context.drawImage(this._context.canvas, sx * 2, sy * 2, sw * 2, sh * 2, 0, 0, sw * 2, sh * 2); context = this._context; context.clearRect(dx * 2, dy * 2, sw * 2, sh * 2); context.drawImage(core._buffer, 0, 0, sw * 2, sh * 2, dx * 2, dy * 2, sw * 2, sh * 2); } else { context.clearRect(0, 0, sw, sh); context.drawImage(this._context.canvas, sx, sy, sw, sh, 0, 0, sw, sh); context = this._context; context.clearRect(dx, dy, sw, sh); context.drawImage(core._buffer, 0, 0, sw, sh, dx, dy, sw, sh); }
if (dx === 0) { this.redraw(sw, 0, core.width - sw, core.height); } else { this.redraw(0, 0, core.width - sw, core.height); } if (dy === 0) { this.redraw(0, sh, core.width, core.height - sh); } else { this.redraw(0, 0, core.width, core.height - sh); } } else { this.redraw(0, 0, core.width, core.height); } } else { this.redraw(0, 0, core.width, core.height); } } this._previousOffsetX = this._offsetX; this._previousOffsetY = this._offsetY; }); }, /** * Set map data. * Sets the tile data, whereas the data (two-dimensional array with indizes starting from 0) * is mapped on the image starting from the upper left corner. * When more than one map data array is set, they are displayed in reverse order. * @param {...Array<Array.<Number>>} data Two-dimensional array of tile indizes. Multiple designations possible. */ loadData: function(data) { this._data = Array.prototype.slice.apply(arguments); this._dirty = true;
this._tight = false; for (var i = 0, len = this._data.length; i < len; i++) { var c = 0; data = this._data[i]; for (var y = 0, l = data.length; y < l; y++) { for (var x = 0, ll = data[y].length; x < ll; x++) { if (data[y][x] >= 0) { c++; } } } if (c / (data.length * data[0].length) > 0.2) { this._tight = true; break; } } }, /** * Checks what tile is present at the given position. * @param {Number} x x coordinates of the point on the map. * @param {Number} y y coordinates of the point on the map. * @return {*} The tile data for the given position. */ checkTile: function(x, y) { if (x < 0 || this.width <= x || y < 0 || this.height <= y) { return false; } var width = this._image.width; var height = this._image.height; var tileWidth = this._tileWidth || width; var tileHeight = this._tileHeight || height; x = x / tileWidth | 0; y = y / tileHeight | 0; // return this._data[y][x]; var data = this._data[0]; return data[y][x]; }, /** * Judges whether or not obstacles are on top of Map. * @param {Number} x x coordinates of detection spot on map. * @param {Number} y y coordinates of detection spot on map. * @return {Boolean} True, if there are obstacles. */ hitTest: function(x, y) { if (x < 0 || this.width <= x || y < 0 || this.height <= y) { return false; } var width = this._image.width; var height = this._image.height; var tileWidth = this._tileWidth || width; var tileHeight = this._tileHeight || height; x = x / tileWidth | 0; y = y / tileHeight | 0; if (this.collisionData != null) { return this.collisionData[y] && !!this.collisionData[y][x]; } else { for (var i = 0, len = this._data.length; i < len; i++) { var data = this._data[i]; var n; if (data[y] != null && (n = data[y][x]) != null && 0 <= n && n < (width / tileWidth | 0) * (height / tileHeight | 0)) { return true; } } return false; } }, /** * Image with which the tile set is displayed on the map. * @type {enchant.Surface} */ image: { get: function() { return this._image; }, set: function(image) { var core = enchant.Core.instance;
this._image = image; if (enchant.ENV.RETINA_DISPLAY && core.scale === 2) { var img = new enchant.Surface(image.width * 2, image.height * 2); var tileWidth = this._tileWidth || image.width; var tileHeight = this._tileHeight || image.height; var row = image.width / tileWidth | 0; var col = image.height / tileHeight | 0; for (var y = 0; y < col; y++) { for (var x = 0; x < row; x++) { img.draw(image, x * tileWidth, y * tileHeight, tileWidth, tileHeight, x * tileWidth * 2, y * tileHeight * 2, tileWidth * 2, tileHeight * 2); } } this._doubledImage = img; } this._dirty = true; } }, /** * Map tile width. * @type {Number} */ tileWidth: { get: function() { return this._tileWidth; }, set: function(tileWidth) { this._tileWidth = tileWidth; this._dirty = true; } }, /** * Map tile height. * @type {Number} */ tileHeight: { get: function() { return this._tileHeight; }, set: function(tileHeight) { this._tileHeight = tileHeight; this._dirty = true; } }, /** * @private */ width: { get: function() { return this._tileWidth * this._data[0][0].length; } }, /** * @private */ height: { get: function() { return this._tileHeight * this._data[0].length; } }, /** * @private */ redraw: function(x, y, width, height) { if (this._image == null) { return; }
var image, tileWidth, tileHeight, dx, dy; if (this._doubledImage) { image = this._doubledImage; tileWidth = this._tileWidth * 2; tileHeight = this._tileHeight * 2; dx = -this._offsetX * 2; dy = -this._offsetY * 2; x *= 2; y *= 2; width *= 2; height *= 2; } else { image = this._image; tileWidth = this._tileWidth; tileHeight = this._tileHeight; dx = -this._offsetX; dy = -this._offsetY; } var row = image.width / tileWidth | 0; var col = image.height / tileHeight | 0; var left = Math.max((x + dx) / tileWidth | 0, 0); var top = Math.max((y + dy) / tileHeight | 0, 0); var right = Math.ceil((x + dx + width) / tileWidth); var bottom = Math.ceil((y + dy + height) / tileHeight);
var source = image._element; var context = this._context; var canvas = context.canvas; context.clearRect(x, y, width, height); for (var i = 0, len = this._data.length; i < len; i++) { var data = this._data[i]; var r = Math.min(right, data[0].length); var b = Math.min(bottom, data.length); for (y = top; y < b; y++) { for (x = left; x < r; x++) { var n = data[y][x]; if (0 <= n && n < row * col) { var sx = (n % row) * tileWidth; var sy = (n / row | 0) * tileHeight; context.drawImage(source, sx, sy, tileWidth, tileHeight, x * tileWidth - dx, y * tileHeight - dy, tileWidth, tileHeight); } } } } }, cvsRender: function(ctx) { var core = enchant.Core.instance; if (this.width !== 0 && this.height !== 0) { ctx.save(); ctx.setTransform(1, 0, 0, 1, 0, 0); var cvs = this._context.canvas; ctx.drawImage(cvs, 0, 0, core.width, core.height); ctx.restore(); } }, domRender: function(element) { if (this._image) { this._style['background-image'] = this._surface._css; // bad performance this._style[enchant.ENV.VENDOR_PREFIX + 'Transform'] = 'matrix(1, 0, 0, 1, 0, 0)'; } } });
/** * @scope enchant.Group.prototype */ enchant.Group = enchant.Class.create(enchant.Node, { /** * @name enchant.Group * @class * A class that can hold multiple {@link enchant.Node}. * * @example * var stage = new Group(); * stage.addChild(player); * stage.addChild(enemy); * stage.addChild(map); * stage.addEventListener('enterframe', function() { * // Moves the entire frame in according to the player's coordinates. * if (this.x > 64 - player.x) { * this.x = 64 - player.x; * } * }); * * @constructs * @extends enchant.Node */ initialize: function() { /** * Child Nodes. * @type {Array.<enchant.Node>} */ this.childNodes = [];
enchant.Node.call(this);
this._rotation = 0; this._scaleX = 1; this._scaleY = 1;
this._originX = null; this._originY = null;
this.__dirty = false;
[enchant.Event.ADDED_TO_SCENE, enchant.Event.REMOVED_FROM_SCENE] .forEach(function(event) { this.addEventListener(event, function(e) { this.childNodes.forEach(function(child) { child.scene = this.scene; child.dispatchEvent(e); }, this); }); }, this); }, /** * Adds a Node to the Group. * @param {enchant.Node} node Node to be added. */ addChild: function(node) { this.childNodes.push(node); node.parentNode = this; var childAdded = new enchant.Event('childadded'); childAdded.node = node; childAdded.next = null; this.dispatchEvent(childAdded); node.dispatchEvent(new enchant.Event('added')); if (this.scene) { node.scene = this.scene; var addedToScene = new enchant.Event('addedtoscene'); node.dispatchEvent(addedToScene); } }, /** * Incorporates Node into Group. * @param {enchant.Node} node Node to be incorporated. * @param {enchant.Node} reference Node in position before insertion. */ insertBefore: function(node, reference) { var i = this.childNodes.indexOf(reference); if (i !== -1) { this.childNodes.splice(i, 0, node); node.parentNode = this; var childAdded = new enchant.Event('childadded'); childAdded.node = node; childAdded.next = reference; this.dispatchEvent(childAdded); node.dispatchEvent(new enchant.Event('added')); if (this.scene) { node.scene = this.scene; var addedToScene = new enchant.Event('addedtoscene'); node.dispatchEvent(addedToScene); } } else { this.addChild(node); } }, /** * Remove a Node from the Group. * @param {enchant.Node} node Node to be deleted. */ removeChild: function(node) { var i; if ((i = this.childNodes.indexOf(node)) !== -1) { this.childNodes.splice(i, 1); node.parentNode = null; var childRemoved = new enchant.Event('childremoved'); childRemoved.node = node; this.dispatchEvent(childRemoved); node.dispatchEvent(new enchant.Event('removed')); if (this.scene) { node.scene = null; var removedFromScene = new enchant.Event('removedfromscene'); node.dispatchEvent(removedFromScene); } } }, /** * The Node which is the first child. * @type {enchant.Node} */ firstChild: { get: function() { return this.childNodes[0]; } }, /** * The Node which is the last child. * @type {enchant.Node} */ lastChild: { get: function() { return this.childNodes[this.childNodes.length - 1]; } }, /** * Group rotation angle (degree). * @type {Number} */ rotation: { get: function() { return this._rotation; }, set: function(rotation) { this._rotation = rotation; this._dirty = true; } }, /** * Scaling factor on the x axis of the Group. * @type {Number} * @see enchant.CanvasGroup.originX * @see enchant.CanvasGroup.originY */ scaleX: { get: function() { return this._scaleX; }, set: function(scale) { this._scaleX = scale; this._dirty = true; } }, /** * Scaling factor on the y axis of the Group. * @type {Number} * @see enchant.CanvasGroup.originX * @see enchant.CanvasGroup.originY */ scaleY: { get: function() { return this._scaleY; }, set: function(scale) { this._scaleY = scale; this._dirty = true; } }, /** * origin point of rotation, scaling * @type {Number} */ originX: { get: function() { return this._originX; }, set: function(originX) { this._originX = originX; this._dirty = true; } }, /** * origin point of rotation, scaling * @type {Number} */ originY: { get: function() { return this._originY; }, set: function(originY) { this._originY = originY; this._dirty = true; } }, _dirty: { get: function() { return this.__dirty; }, set: function(dirty) { dirty = !!dirty; this.__dirty = dirty; if (dirty) { for (var i = 0, l = this.childNodes.length; i < l; i++) { this.childNodes[i]._dirty = true; } } } } });
enchant.Matrix = enchant.Class.create({ initialize: function() { if (enchant.Matrix.instance) { return enchant.Matrix.instance; } this.reset(); }, reset: function() { this.stack = []; this.stack.push([ 1, 0, 0, 1, 0, 0 ]); }, makeTransformMatrix: function(node, dest) { var x = node._x; var y = node._y; var width = node.width || 0; var height = node.height || 0; var rotation = node._rotation || 0; var scaleX = (typeof node._scaleX === 'number') ? node._scaleX : 1; var scaleY = (typeof node._scaleY === 'number') ? node._scaleY : 1; var theta = rotation * Math.PI / 180; var tmpcos = Math.cos(theta); var tmpsin = Math.sin(theta); var w = (typeof node._originX === 'number') ? node._originX : width / 2; var h = (typeof node._originY === 'number') ? node._originY : height / 2; var a = scaleX * tmpcos; var b = scaleX * tmpsin; var c = scaleY * tmpsin; var d = scaleY * tmpcos; dest[0] = a; dest[1] = b; dest[2] = -c; dest[3] = d; dest[4] = (-a * w + c * h + x + w); dest[5] = (-b * w - d * h + y + h); }, multiply: function(m1, m2, dest) { var a11 = m1[0], a21 = m1[2], adx = m1[4], a12 = m1[1], a22 = m1[3], ady = m1[5]; var b11 = m2[0], b21 = m2[2], bdx = m2[4], b12 = m2[1], b22 = m2[3], bdy = m2[5];
dest[0] = a11 * b11 + a21 * b12; dest[1] = a12 * b11 + a22 * b12; dest[2] = a11 * b21 + a21 * b22; dest[3] = a12 * b21 + a22 * b22; dest[4] = a11 * bdx + a21 * bdy + adx; dest[5] = a12 * bdx + a22 * bdy + ady; }, multiplyVec: function(mat, vec, dest) { var x = vec[0], y = vec[1]; var m11 = mat[0], m21 = mat[2], mdx = mat[4], m12 = mat[1], m22 = mat[3], mdy = mat[5]; dest[0] = m11 * x + m21 * y + mdx; dest[1] = m12 * x + m22 * y + mdy; } }); enchant.Matrix.instance = new enchant.Matrix();
enchant.DetectColorManager = enchant.Class.create({ initialize: function(reso, max) { this.reference = []; this.colorResolution = reso || 16; this.max = max || 1; this.capacity = Math.pow(this.colorResolution, 3); for (var i = 1, l = this.capacity; i < l; i++) { this.reference[i] = null; } }, attachDetectColor: function(sprite) { var i = this.reference.indexOf(null); if (i === -1) { i = 1; } this.reference[i] = sprite; return this._getColor(i); }, detachDetectColor: function(sprite) { var i = this.reference.indexOf(sprite); if (i !== -1) { this.reference[i] = null; } }, _getColor: function(n) { var C = this.colorResolution; var d = C / this.max; return [ parseInt((n / C / C) % C, 10) / d, parseInt((n / C) % C, 10) / d, parseInt(n % C, 10) / d, 1.0 ]; }, _decodeDetectColor: function(color) { var C = this.colorResolution; return ~~(color[0] * C * C * C / 256) + ~~(color[1] * C * C / 256) + ~~(color[2] * C / 256); }, getSpriteByColor: function(color) { return this.reference[this._decodeDetectColor(color)]; } });
enchant.DomManager = enchant.Class.create({ initialize: function(node, elementDefinition) { var core = enchant.Core.instance; this.layer = null; this.targetNode = node; if (typeof elementDefinition === 'string') { this.element = document.createElement(elementDefinition); } else if (elementDefinition instanceof HTMLElement) { this.element = elementDefinition; } this.style = this.element.style; this.style.position = 'absolute'; this.style[enchant.ENV.VENDOR_PREFIX + 'TransformOrigin'] = '0px 0px'; if (core._debug) { this.style.border = '1px solid blue'; this.style.margin = '-1px'; }
var manager = this; this._setDomTarget = function() { manager.layer._touchEventTarget = manager.targetNode; }; this._attachEvent(); }, getDomElement: function() { return this.element; }, getDomElementAsNext: function() { return this.element; }, getNextManager: function(manager) { var i = this.targetNode.parentNode.childNodes.indexOf(manager.targetNode); if (i !== this.targetNode.parentNode.childNodes.length - 1) { return this.targetNode.parentNode.childNodes[i + 1]._domManager; } else { return null; } }, addManager: function(childManager, nextManager) { var nextElement; if (nextManager) { nextElement = nextManager.getDomElementAsNext(); } var element = childManager.getDomElement(); if (element instanceof Array) { element.forEach(function(child) { this.element.insertBefore(child, nextElement); }, this); } else { this.element.insertBefore(element, nextElement); } this.setLayer(this.layer); }, removeManager: function(childManager) { if (childManager instanceof enchant.DomlessManager) { childManager._domRef.forEach(function(element) { this.element.removeChild(element); }, this); } else { this.element.removeChild(childManager.element); } this.setLayer(this.layer); }, setLayer: function(layer) { this.layer = layer; var node = this.targetNode; var manager; if (node.childNodes) { for (var i = 0, l = node.childNodes.length; i < l; i++) { manager = node.childNodes[i]._domManager; if (manager) { manager.setLayer(layer); } } } }, render: function(inheritMat) { var node = this.targetNode; var matrix = enchant.Matrix.instance; var stack = matrix.stack; var dest = []; matrix.makeTransformMatrix(node, dest); matrix.multiply(stack[stack.length - 1], dest, dest); matrix.multiply(inheritMat, dest, inheritMat); node._matrix = inheritMat; var ox = (typeof node._originX === 'number') ? node._originX : node.width / 2 || 0; var oy = (typeof node._originY === 'number') ? node._originY : node.height / 2 || 0; var vec = [ ox, oy ]; matrix.multiplyVec(dest, vec, vec);
node._offsetX = vec[0] - ox; node._offsetY = vec[1] - oy; if(node.parentNode && !(node.parentNode instanceof enchant.Group)) { node._offsetX += node.parentNode._offsetX; node._offsetY += node.parentNode._offsetY; } this.style[enchant.ENV.VENDOR_PREFIX + 'Transform'] = 'matrix(' + dest[0].toFixed(10) + ',' + dest[1].toFixed(10) + ',' + dest[2].toFixed(10) + ',' + dest[3].toFixed(10) + ',' + dest[4].toFixed(10) + ',' + dest[5].toFixed(10) + ')'; this.domRender(); }, domRender: function() { var node = this.targetNode; if(!node._style) { node._style = {}; } if(!node.__styleStatus) { node.__styleStatus = {}; } node._style.width = node.width + 'px'; node._style.height = node.height + 'px'; node._style.opacity = node._opacity; node._style['background-color'] = node._backgroundColor; if (typeof node._visible !== 'undefined') { node._style.display = node._visible ? 'block' : 'none'; } if (typeof node.domRender === 'function') { node.domRender(this.element); } for (var prop in node._style) { if(node.__styleStatus[prop] !== node._style[prop]) { this.style.setProperty(prop, node._style[prop]); node.__styleStatus[prop] = node._style[prop]; } } }, _attachEvent: function() { if (enchant.ENV.TOUCH_ENABLED) { this.element.addEventListener('touchstart', this._setDomTarget, true); } this.element.addEventListener('mousedown', this._setDomTarget, true); }, _detachEvent: function() { if (enchant.ENV.TOUCH_ENABLED) { this.element.removeEventListener('touchstart', this._setDomTarget, true); } this.element.removeEventListener('mousedown', this._setDomTarget, true); }, remove: function() { this._detachEvent(); this.element = this.style = this.targetNode = null; } });
enchant.DomlessManager = enchant.Class.create({ initialize: function(node) { this._domRef = []; this.targetNode = node; }, _register: function(element, nextElement) { var i = this._domRef.indexOf(nextElement); var childNodes; if (element instanceof Array) { if (i === -1) { Array.prototype.push.apply(this._domRef, element); } else { Array.prototype.splice.apply(this._domRef, [i, 0].concat(element)); } } else { if (i === -1) { this._domRef.push(element); } else { this._domRef.splice(i, 0, element); } } }, getNextManager: function(manager) { var i = this.targetNode.parentNode.childNodes.indexOf(manager.targetNode); if (i !== this.targetNode.parentNode.childNodes.length - 1) { return this.targetNode.parentNode.childNodes[i + 1]._domManager; } else { return null; } }, getDomElement: function() { var ret = []; this.targetNode.childNodes.forEach(function(child) { ret = ret.concat(child._domManager.getDomElement()); }); return ret; }, getDomElementAsNext: function() { if (this._domRef.length) { return this._domRef[0]; } else { var nextManager = this.getNextManager(this); if (nextManager) { return nextManager.element; } else { return null; } } }, addManager: function(childManager, nextManager) { var parentNode = this.targetNode.parentNode; if (parentNode) { if (nextManager === null) { nextManager = this.getNextManager(this); } if (parentNode instanceof enchant.Scene) { parentNode._layers.Dom._domManager.addManager(childManager, nextManager); } else { parentNode._domManager.addManager(childManager, nextManager); } } var nextElement = nextManager ? nextManager.getDomElementAsNext() : null; this._register(childManager.getDomElement(), nextElement); this.setLayer(this.layer); }, removeManager: function(childManager) { var dom; var i = this._domRef.indexOf(childManager.element); if (i !== -1) { dom = this._domRef[i]; dom.parentNode.removeChild(dom); this._domRef.splice(i, 1); } this.setLayer(this.layer); }, setLayer: function(layer) { this.layer = layer; var node = this.targetNode; var manager; if (node.childNodes) { for (var i = 0, l = node.childNodes.length; i < l; i++) { manager = node.childNodes[i]._domManager; if (manager) { manager.setLayer(layer); } } } }, render: function(inheritMat) { var matrix = enchant.Matrix.instance; var stack = matrix.stack; var node = this.targetNode; var dest = []; matrix.makeTransformMatrix(node, dest); matrix.multiply(stack[stack.length - 1], dest, dest); matrix.multiply(inheritMat, dest, inheritMat); node._matrix = inheritMat; var ox = (typeof node._originX === 'number') ? node._originX : node.width / 2 || 0; var oy = (typeof node._originY === 'number') ? node._originY : node.height / 2 || 0; var vec = [ ox, oy ]; matrix.multiplyVec(dest, vec, vec); node._offsetX = vec[0] - ox; node._offsetY = vec[1] - oy; stack.push(dest); }, remove: function() { this._domRef = []; this.targetNode = null; } });
enchant.DomLayer = enchant.Class.create(enchant.Group, { initialize: function() { var core = enchant.Core.instance; enchant.Group.call(this);
this.width = this._width = core.width; this.height = this._height = core.height;
this._touchEventTarget = null;
this._element = document.createElement('div'); this._element.style.width = this.width + 'px'; this._element.style.height = this.height + 'px'; this._element.style.position = 'absolute';
this._domManager = new enchant.DomManager(this, this._element); this._domManager.layer = this;
var touch = [ enchant.Event.TOUCH_START, enchant.Event.TOUCH_MOVE, enchant.Event.TOUCH_END ];
touch.forEach(function(type) { this.addEventListener(type, function(e) { if (this._scene) { this._scene.dispatchEvent(e); } }); }, this);
var __onchildadded = function(e) { var child = e.node; var next = e.next; var self = e.target; var nextManager = next ? next._domManager : null; enchant.DomLayer._attachDomManager(child, __onchildadded, __onchildremoved); self._domManager.addManager(child._domManager, nextManager); var render = new enchant.Event(enchant.Event.RENDER); child._dirty = true; self._domManager.layer._rendering(child, render); };
var __onchildremoved = function(e) { var child = e.node; var self = e.target; self._domManager.removeManager(child._domManager); enchant.DomLayer._detachDomManager(child, __onchildadded, __onchildremoved); };
this.addEventListener('childremoved', __onchildremoved); this.addEventListener('childadded', __onchildadded);
}, _startRendering: function() { this.addEventListener('exitframe', this._onexitframe); this._onexitframe(); }, _stopRendering: function() { this.removeEventListener('exitframe', this._onexitframe); this._onexitframe(); }, _onexitframe: function() { this._rendering(this, new enchant.Event(enchant.Event.RENDER)); }, _rendering: function(node, e, inheritMat) { var child; if (!inheritMat) { inheritMat = [ 1, 0, 0, 1, 0, 0 ]; } node.dispatchEvent(e); node._domManager.render(inheritMat); if (node.childNodes) { for (var i = 0, l = node.childNodes.length; i < l; i++) { child = node.childNodes[i]; this._rendering(child, e, inheritMat.slice()); } } if (node._domManager instanceof enchant.DomlessManager) { enchant.Matrix.instance.stack.pop(); } node._dirty = false; }, _determineEventTarget: function() { if (this._touchEventTarget) { if (this._touchEventTarget !== this) { return this._touchEventTarget; } } return null; } });
enchant.DomLayer._attachDomManager = function(node, onchildadded, onchildremoved) { var child; if (!node._domManager) { node.addEventListener('childadded', onchildadded); node.addEventListener('childremoved', onchildremoved); if (node instanceof enchant.Group) { node._domManager = new enchant.DomlessManager(node); } else { if (node._element) { node._domManager = new enchant.DomManager(node, node._element); } else { node._domManager = new enchant.DomManager(node, 'div'); } } } if (node.childNodes) { for (var i = 0, l = node.childNodes.length; i < l; i++) { child = node.childNodes[i]; enchant.DomLayer._attachDomManager(child, onchildadded, onchildremoved); node._domManager.addManager(child._domManager, null); } } };
enchant.DomLayer._detachDomManager = function(node, onchildadded, onchildremoved) { var child; node.removeEventListener('childadded', onchildadded); node.removeEventListener('childremoved', onchildremoved); if (node.childNodes) { for (var i = 0, l = node.childNodes.length; i < l; i++) { child = node.childNodes[i]; node._domManager.removeManager(child._domManager, null); enchant.DomLayer._detachDomManager(child, onchildadded, onchildremoved); } } node._domManager.remove(); delete node._domManager; };
/** * @scope enchant.CanvasLayer.prototype */ enchant.CanvasLayer = enchant.Class.create(enchant.Group, { /** * @name enchant.CanvasLayer * @class * A class which is using HTML Canvas for the rendering. * The rendering of children will be replaced by the Canvas rendering. * @constructs */ initialize: function() { var core = enchant.Core.instance;
enchant.Group.call(this);
this._cvsCache = { matrix: [1, 0, 0, 1, 0, 0], detectColor: '#000000' }; this._cvsCache.layer = this;
this.width = core.width; this.height = core.height;
this._element = document.createElement('canvas'); this._element.width = core.width; this._element.height = core.height; this._element.style.position = 'absolute';
this._detect = document.createElement('canvas'); this._detect.width = core.width; this._detect.height = core.height; this._detect.style.position = 'absolute'; this._lastDetected = 0;
this.context = this._element.getContext('2d'); this._dctx = this._detect.getContext('2d');
this._colorManager = new enchant.DetectColorManager(16, 256);
var touch = [ enchant.Event.TOUCH_START, enchant.Event.TOUCH_MOVE, enchant.Event.TOUCH_END ];
touch.forEach(function(type) { this.addEventListener(type, function(e) { if (this._scene) { this._scene.dispatchEvent(e); } }); }, this);
var __onchildadded = function(e) { var child = e.node; var self = e.target; var layer; if (self instanceof enchant.CanvasLayer) { layer = self._scene._layers.Canvas; } else { layer = self.scene._layers.Canvas; } enchant.CanvasLayer._attachCache(child, layer, __onchildadded, __onchildremoved); var render = new enchant.Event(enchant.Event.RENDER); if (self._dirty) { self._updateCoordinate(); } child._dirty = true; enchant.Matrix.instance.stack.push(self._matrix); layer._rendering(child, render); enchant.Matrix.instance.stack.pop(self._matrix); };
var __onchildremoved = function(e) { var child = e.node; var self = e.target; var layer; if (self instanceof enchant.CanvasLayer) { layer = self._scene._layers.Canvas; } else { layer = self.scene._layers.Canvas; } enchant.CanvasLayer._detachCache(child, layer, __onchildadded, __onchildremoved); };
this.addEventListener('childremoved', __onchildremoved); this.addEventListener('childadded', __onchildadded);
}, /** * @private */ _startRendering: function() { this.addEventListener('exitframe', this._onexitframe); this._onexitframe(new enchant.Event(enchant.Event.RENDER)); }, /** * @private */ _stopRendering: function() { this.removeEventListener('render', this._onexitframe); this._onexitframe(new enchant.Event(enchant.Event.RENDER)); }, _onexitframe: function() { var core = enchant.Core.instance; var ctx = this.context; ctx.clearRect(0, 0, core.width, core.height); var render = new enchant.Event(enchant.Event.RENDER); this._rendering(this, render); }, _rendering: function(node, e) { var core = enchant.Core.instance; var matrix = enchant.Matrix.instance; var stack = matrix.stack; var width = node.width; var height = node.height; var ctx = this.context; var child; ctx.save(); node.dispatchEvent(e); // composite if (node.compositeOperation) { ctx.globalCompositeOperation = node.compositeOperation; } else { ctx.globalCompositeOperation = 'source-over'; } ctx.globalAlpha = (typeof node._opacity === 'number') ? node._opacity : 1.0; // transform this._transform(node, ctx); // render if (typeof node._visible === 'undefined' || node._visible) { if (node._backgroundColor) { ctx.fillStyle = node._backgroundColor; ctx.fillRect(0, 0, width, height); }
if (node.cvsRender) { node.cvsRender(ctx); }
if (core._debug) { if (node instanceof enchant.Label || node instanceof enchant.Sprite) { ctx.strokeStyle = '#ff0000'; } else { ctx.strokeStyle = '#0000ff'; } ctx.strokeRect(0, 0, width, height); } if (node._clipping) { ctx.rect(0, 0, width, height); ctx.clip(); } } if (node.childNodes) { for (var i = 0, l = node.childNodes.length; i < l; i++) { child = node.childNodes[i]; this._rendering(child, e); } } ctx.restore(); enchant.Matrix.instance.stack.pop(); }, _detectrendering: function(node) { var width = node.width; var height = node.height; var ctx = this._dctx; var child; ctx.save(); this._transform(node, ctx); ctx.fillStyle = node._cvsCache.detectColor; if (node._touchEnabled) { if (node.detectRender) { node.detectRender(ctx); } else { ctx.fillRect(0, 0, width, height); } } if (node._clipping) { ctx.rect(0, 0, width, height); ctx.clip(); } if (node.childNodes) { for (var i = 0, l = node.childNodes.length; i < l; i++) { child = node.childNodes[i]; this._detectrendering(child); } } ctx.restore(); enchant.Matrix.instance.stack.pop(); }, _transform: function(node, ctx) { var matrix = enchant.Matrix.instance; var stack = matrix.stack; var newmat; if (node._dirty) { matrix.makeTransformMatrix(node, node._cvsCache.matrix); newmat = []; matrix.multiply(stack[stack.length - 1], node._cvsCache.matrix, newmat); node._matrix = newmat; } else { newmat = node._matrix; } stack.push(newmat); ctx.setTransform.apply(ctx, newmat); var ox = (typeof node._originX === 'number') ? node._originX : node._width / 2 || 0; var oy = (typeof node._originY === 'number') ? node._originY : node._height / 2 || 0; var vec = [ ox, oy ]; matrix.multiplyVec(newmat, vec, vec); node._offsetX = vec[0] - ox; node._offsetY = vec[1] - oy; node._dirty = false;
}, _determineEventTarget: function(e) { return this._getEntityByPosition(e.x, e.y); }, _getEntityByPosition: function(x, y) { var core = enchant.Core.instance; var ctx = this._dctx; if (this._lastDetected < core.frame) { ctx.clearRect(0, 0, this.width, this.height); this._detectrendering(this); this._lastDetected = core.frame; } var color = ctx.getImageData(x, y, 1, 1).data; return this._colorManager.getSpriteByColor(color); } });
enchant.CanvasLayer._attachCache = function(node, layer, onchildadded, onchildremoved) { var child; if (!node._cvsCache) { node._cvsCache = {}; node._cvsCache.matrix = [ 1, 0, 0, 1, 0, 0 ]; node._cvsCache.detectColor = 'rgba(' + layer._colorManager.attachDetectColor(node) + ')'; node.addEventListener('childadded', onchildadded); node.addEventListener('childremoved', onchildremoved); } if (node.childNodes) { for (var i = 0, l = node.childNodes.length; i < l; i++) { child = node.childNodes[i]; enchant.CanvasLayer._attachCache(child, layer, onchildadded, onchildremoved); } } };
enchant.CanvasLayer._detachCache = function(node, layer, onchildadded, onchildremoved) { var child; if (node._cvsCache) { layer._colorManager.detachDetectColor(node); node.removeEventListener('childadded', onchildadded); node.removeEventListener('childremoved', onchildremoved); delete node._cvsCache; } if (node.childNodes) { for (var i = 0, l = node.childNodes.length; i < l; i++) { child = node.childNodes[i]; enchant.CanvasLayer._detachCache(child, layer, onchildadded, onchildremoved); } } };
/** * @scope enchant.Scene.prototype * @type {*} */ enchant.Scene = enchant.Class.create(enchant.Group, { /** * @name enchant.Scene * @class * A Class that becomes the root of the display object tree. * * @example * var scene = new Scene(); * scene.addChild(player); * scene.addChild(enemy); * core.pushScene(scene); * * @constructs * @extends enchant.Group */ initialize: function() { var core = enchant.Core.instance;
// Call initialize method of enchant.Group enchant.Group.call(this);
this.width = core.width; this.height = core.height;
// All nodes (entities, groups, scenes) have reference to the scene that it belongs to. this.scene = this;
this._backgroundColor = null;
// Create div tag which possesses its layers this._element = document.createElement('div'); this._element.style.width = this.width + 'px'; this._element.style.height = this.height + 'px'; this._element.style.position = 'absolute'; this._element.style.overflow = 'hidden'; this._element.style[enchant.ENV.VENDOR_PREFIX + 'TransformOrigin'] = '0 0'; this._element.style[enchant.ENV.VENDOR_PREFIX + 'Transform'] = 'scale(' + enchant.Core.instance.scale + ')';
this._layers = {}; this._layerPriority = [];
// Add layers this.addLayer('Canvas'); this.addLayer('Dom');
this.addEventListener(enchant.Event.CHILD_ADDED, this._onchildadded); this.addEventListener(enchant.Event.CHILD_REMOVED, this._onchildremoved); this.addEventListener(enchant.Event.ENTER, this._onenter); this.addEventListener(enchant.Event.EXIT, this._onexit);
var that = this; this._dispatchExitframe = function() { var layer; for (var prop in that._layers) { layer = that._layers[prop]; layer.dispatchEvent(new enchant.Event(enchant.Event.EXIT_FRAME)); } }; }, x: { get: function() { return this._x; }, set: function(x) { this._x = x; for (var type in this._layers) { this._layers[type].x = x; } } }, y: { get: function() { return this._y; }, set: function(y) { this._y = y; for (var type in this._layers) { this._layers[type].y = y; } } }, rotation: { get: function() { return this._rotation; }, set: function(rotation) { this._rotation = rotation; for (var type in this._layers) { this._layers[type].rotation = rotation; } } }, scaleX: { get: function() { return this._scaleX; }, set: function(scaleX) { this._scaleX = scaleX; for (var type in this._layers) { this._layers[type].scaleX = scaleX; } } }, scaleY: { get: function() { return this._scaleY; }, set: function(scaleY) { this._scaleY = scaleY; for (var type in this._layers) { this._layers[type].scaleY = scaleY; } } }, backgroundColor: { get: function() { return this._backgroundColor; }, set: function(color) { this._backgroundColor = this._element.style.backgroundColor = color; } }, addLayer: function(type, i) { var core = enchant.Core.instance; if (this._layers[type]) { return; } var layer = new enchant[type + 'Layer'](); if (core.currentScene === this) { layer._startRendering(); } this._layers[type] = layer; var element = layer._element; if (typeof i === 'number') { var nextSibling = this._element.childNodes.indexOf(i); this._element.insertBefore(element, nextSibling); this._layerPriority.splice(i, 0, type); } else { this._element.appendChild(element); this._layerPriority.push(type); } layer._scene = this; }, _determineEventTarget: function(e) { var layer, target; for (var i = this._layerPriority.length - 1; i >= 0; i--) { layer = this._layers[this._layerPriority[i]]; target = layer._determineEventTarget(e); if (target) { break; } } if (!target) { target = this; } return target; }, _onchildadded: function(e) { var child = e.node; var next = e.next; if (child._element) { this._layers.Dom.insertBefore(child, next); child._layer = this._layers.Dom; } else { this._layers.Canvas.insertBefore(child, next); child._layer = this._layers.Canvas; } child.parentNode = this; }, _onchildremoved: function(e) { var child = e.node; child._layer.removeChild(child); child._layer = null; }, _onenter: function() { for (var type in this._layers) { this._layers[type]._startRendering(); } enchant.Core.instance.addEventListener('exitframe', this._dispatchExitframe); }, _onexit: function() { for (var type in this._layers) { this._layers[type]._stopRendering(); } enchant.Core.instance.removeEventListener('exitframe', this._dispatchExitframe); } });
/** * @scope enchant.Surface.prototype */ enchant.Surface = enchant.Class.create(enchant.EventTarget, { /** * @name enchant.Surface * @class * Class that wraps canvas elements. * * Can be used to set the {@link enchant.Sprite} and {@link enchant.Map}'s image properties to be displayed. * If you wish to access Canvas API use the {@link enchant.Surface#context} property. * * @example * // Creates Sprite that displays a circle. * var ball = new Sprite(50, 50); * var surface = new Surface(50, 50); * surface.context.beginPath(); * surface.context.arc(25, 25, 25, 0, Math.PI*2, true); * surface.context.fill(); * ball.image = surface; * * @param {Number} width Surface width. * @param {Number} height Surface height. * @constructs */ initialize: function(width, height) { enchant.EventTarget.call(this);
var core = enchant.Core.instance;
/** * Surface width. * @type {Number} */ this.width = width; /** * Surface height. * @type {Number} */ this.height = height; /** * Surface drawing context. * @type {CanvasRenderingContext2D} */ this.context = null;
var id = 'enchant-surface' + core._surfaceID++; if (document.getCSSCanvasContext) { this.context = document.getCSSCanvasContext('2d', id, width, height); this._element = this.context.canvas; this._css = '-webkit-canvas(' + id + ')'; var context = this.context; } else if (document.mozSetImageElement) { this._element = document.createElement('canvas'); this._element.width = width; this._element.height = height; this._css = '-moz-element(#' + id + ')'; this.context = this._element.getContext('2d'); document.mozSetImageElement(id, this._element); } else { this._element = document.createElement('canvas'); this._element.width = width; this._element.height = height; this._element.style.position = 'absolute'; this.context = this._element.getContext('2d');
enchant.ENV.CANVAS_DRAWING_METHODS.forEach(function(name) { var method = this.context[name]; this.context[name] = function() { method.apply(this, arguments); this._dirty = true; }; }, this); } }, /** * Returns 1 pixel from the Surface. * @param {Number} x The pixel's x coordinates. * @param {Number} y The pixel's y coordinates. * @return {Array.<Number>} An array that holds pixel information in [r, g, b, a] format. */ getPixel: function(x, y) { return this.context.getImageData(x, y, 1, 1).data; }, /** * Sets one pixel within the surface. * @param {Number} x The pixel's x coordinates. * @param {Number} y The pixel's y coordinates. * @param {Number} r The pixel's red level. * @param {Number} g The pixel's green level. * @param {Number} b The pixel's blue level. * @param {Number} a The pixel's transparency. */ setPixel: function(x, y, r, g, b, a) { var pixel = this.context.createImageData(1, 1); pixel.data[0] = r; pixel.data[1] = g; pixel.data[2] = b; pixel.data[3] = a; this.context.putImageData(pixel, x, y); }, /** * Clears all Surface pixels and makes the pixels transparent. */ clear: function() { this.context.clearRect(0, 0, this.width, this.height); }, /** * Draws the content of the given Surface onto this surface. * * Wraps Canvas API drawImage and if multiple arguments are given, * these are getting applied to the Canvas drawImage method. * * @example * var src = core.assets['src.gif']; * var dst = new Surface(100, 100); * dst.draw(src); // Draws source at (0, 0) * dst.draw(src, 50, 50); // Draws source at (50, 50) * // Draws just 30 horizontal and vertical pixels of source at (50, 50) * dst.draw(src, 50, 50, 30, 30); * // Takes the image content in src starting at (10,10) with a (Width, Height) of (40,40), * // scales it and draws it in this surface at (50, 50) with a (Width, Height) of (30,30). * dst.draw(src, 10, 10, 40, 40, 50, 50, 30, 30); * * @param {enchant.Surface} image Surface used in drawing. */ draw: function(image) { image = image._element; if (arguments.length === 1) { this.context.drawImage(image, 0, 0); } else { var args = arguments; args[0] = image; this.context.drawImage.apply(this.context, args); } }, /** * Copies Surface. * @return {enchant.Surface} The copied Surface. */ clone: function() { var clone = new enchant.Surface(this.width, this.height); clone.draw(this); return clone; }, /** * Creates a data URI scheme from this Surface. * @return {String} The data URI scheme that identifies this Surface and * can be used to include this Surface into a dom tree. */ toDataURL: function() { var src = this._element.src; if (src) { if (src.slice(0, 5) === 'data:') { return src; } else { return this.clone().toDataURL(); } } else { return this._element.toDataURL(); } } });
/** * Loads an image and creates a Surface object out of it. * * It is not possible to access properties or methods of the {@link enchant.Surface#context}, or to call methods using the Canvas API - * like {@link enchant.Surface#draw}, {@link enchant.Surface#clear}, {@link enchant.Surface#getPixel}, {@link enchant.Surface#setPixel}.. - * of the wrapped image created with this method. * However, it is possible to use this surface to draw it to another surface using the {@link enchant.Surface#draw} method. * The resulting surface can then be manipulated. (when loading images in a cross-origin resource sharing environment, * pixel acquisition and other image manipulation might be limited). * * @param {String} src The file path of the image to be loaded. * @static */ enchant.Surface.load = function(src, callback) { var image = new Image(); var surface = Object.create(enchant.Surface.prototype, { context: { value: null }, _css: { value: 'url(' + src + ')' }, _element: { value: image } }); enchant.EventTarget.call(surface); image.src = src; image.onerror = function() { throw new Error('Cannot load an asset: ' + image.src); }; image.onload = function() { surface.width = image.width; surface.height = image.height; surface.dispatchEvent(new enchant.Event('load')); }; return surface; };
/** * @scope enchant.DOMSound.prototype * @type {*} */ enchant.DOMSound = enchant.Class.create(enchant.EventTarget, { /** * @name enchant.DOMSound * @class * Class to wrap audio elements. * * Safari, Chrome, Firefox, Opera, and IE all play MP3 files * (Firefox and Opera play via Flash). WAVE files can be played on * Safari, Chrome, Firefox, and Opera. When the browser is not compatible with * the used codec the file will not play. * * Instances are created not via constructor but via {@link enchant.DOMSound.load}. * @constructs */ initialize: function() { enchant.EventTarget.call(this); /** * Sound file duration (seconds). * @type {Number} */ this.duration = 0; throw new Error("Illegal Constructor"); }, /** * Begin playing. */ play: function() { if (this._element) { this._element.play(); } }, /** * Pause playback. */ pause: function() { if (this._element) { this._element.pause(); } }, /** * Stop playing. */ stop: function() { this.pause(); this.currentTime = 0; }, /** * Create a copy of this Sound object. * @return {enchant.DOMSound} Copied Sound. */ clone: function() { var clone; if (this._element instanceof Audio) { clone = Object.create(enchant.DOMSound.prototype, { _element: { value: this._element.cloneNode(false) }, duration: { value: this.duration } }); } else if (enchant.ENV.USE_FLASH_SOUND) { return this; } else { clone = Object.create(enchant.DOMSound.prototype); } enchant.EventTarget.call(clone); return clone; }, /** * Current playback position (seconds). * @type {Number} */ currentTime: { get: function() { return this._element ? this._element.currentTime : 0; }, set: function(time) { if (this._element) { this._element.currentTime = time; } } }, /** * Volume. 0 (muted) ๏ฝ 1 (full volume). * @type {Number} */ volume: { get: function() { return this._element ? this._element.volume : 1; }, set: function(volume) { if (this._element) { this._element.volume = volume; } } } });
/** * Loads an audio file and creates Sound object. * * @param {String} src Path of the audio file to be loaded. * @param {String} [type] MIME Type of the audio file. * @static */ enchant.DOMSound.load = function(src, type, callback) { if (type == null) { var ext = enchant.Core.findExt(src); if (ext) { type = 'audio/' + ext; } else { type = ''; } } type = type.replace('mp3', 'mpeg').replace('m4a', 'mp4');
var sound = Object.create(enchant.DOMSound.prototype); enchant.EventTarget.call(sound); var audio = new Audio(); if (!enchant.ENV.SOUND_ENABLED_ON_MOBILE_SAFARI && enchant.ENV.VENDOR_PREFIX === 'webkit' && enchant.ENV.TOUCH_ENABLED) { window.setTimeout(function() { sound.dispatchEvent(new enchant.Event('load')); }, 0); } else { if (!enchant.ENV.USE_FLASH_SOUND && audio.canPlayType(type)) { audio.src = src; audio.load(); audio.autoplay = false; audio.onerror = function() { throw new Error('Cannot load an asset: ' + audio.src); }; audio.addEventListener('canplaythrough', function() { sound.duration = audio.duration; sound.dispatchEvent(new enchant.Event('load')); }, false); sound._element = audio; } else if (type === 'audio/mpeg') { var embed = document.createElement('embed'); var id = 'enchant-audio' + enchant.Core.instance._soundID++; embed.width = embed.height = 1; embed.name = id; embed.src = 'sound.swf?id=' + id + '&src=' + src; embed.allowscriptaccess = 'always'; embed.style.position = 'absolute'; embed.style.left = '-1px'; sound.addEventListener('load', function() { Object.defineProperties(embed, { currentTime: { get: function() { return embed.getCurrentTime(); }, set: function(time) { embed.setCurrentTime(time); } }, volume: { get: function() { return embed.getVolume(); }, set: function(volume) { embed.setVolume(volume); } } }); sound._element = embed; sound.duration = embed.getDuration(); }); enchant.Core.instance._element.appendChild(embed); enchant.DOMSound[id] = sound; } else { window.setTimeout(function() { sound.dispatchEvent(new enchant.Event('load')); }, 0); } sound.addEventListener('load', function() { callback.call(enchant.Core.instance); }); } return sound; };
window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext || window.oAudioContext;
/** * @scope enchant.WebAudioSound.prototype * @type {*} */ enchant.WebAudioSound = enchant.Class.create(enchant.EventTarget, { /** * @name enchant.WebAudioSound * @class * Sound wrapper class for Web Audio API (supported on some webkit-based browsers) * * @constructs */ initialize: function() { if(!window.webkitAudioContext){ throw new Error("This browser does not support WebAudio API."); } var actx = enchant.WebAudioSound.audioContext; enchant.EventTarget.call(this); this.src = actx.createBufferSource(); this.buffer = null; this._volume = 1; this._currentTime = 0; this._state = 0; this.connectTarget = enchant.WebAudioSound.destination; }, play: function(dup) { var actx = enchant.WebAudioSound.audioContext; if (this._state === 2) { this.src.connect(this.connectTarget); } else { if (this._state === 1 && !dup) { this.src.disconnect(this.connectTarget); } this.src = actx.createBufferSource(); this.src.buffer = this.buffer; this.src.gain.value = this._volume; this.src.connect(this.connectTarget); this.src.noteOn(0); } this._state = 1; }, pause: function() { var actx = enchant.WebAudioSound.audioContext; this.src.disconnect(this.connectTarget); this._state = 2; }, stop: function() { this.src.noteOff(0); this._state = 0; }, clone: function() { var sound = new enchant.WebAudioSound(); sound.buffer = this.buffer; return sound; }, dulation: { get: function() { if (this.buffer) { return this.buffer.dulation; } else { return 0; } } }, volume: { get: function() { return this._volume; }, set: function(volume) { volume = Math.max(0, Math.min(1, volume)); this._volume = volume; if (this.src) { this.src.gain.value = volume; } } }, currentTime: { get: function() { window.console.log('currentTime is not allowed'); return this._currentTime; }, set: function(time) { window.console.log('currentTime is not allowed'); this._currentTime = time; } } });
enchant.WebAudioSound.load = function(src, type, callback) { var actx = enchant.WebAudioSound.audioContext; var xhr = new XMLHttpRequest(); var sound = new enchant.WebAudioSound(); var mimeType = 'audio/' + enchant.Core.findExt(src); // TODO check Audio.canPlayType(mimeType) xhr.responseType = 'arraybuffer'; xhr.open('GET', src, true); xhr.onload = function() { actx.decodeAudioData( xhr.response, function(buffer) { sound.buffer = buffer; callback.call(enchant.Core.instance); }, function(error) { // TODO change to enchant Error window.console.log(error); } ); }; xhr.send(null); return sound; };
if(window.AudioContext){ enchant.WebAudioSound.audioContext = new window.AudioContext(); enchant.WebAudioSound.destination = enchant.WebAudioSound.audioContext.destination; }
/* jshint newcap: false */
enchant.Sound = window.AudioContext && enchant.ENV.USE_WEBAUDIO ? enchant.WebAudioSound : enchant.DOMSound;
/** * ============================================================================================ * Easing Equations v2.0 * September 1, 2003 * (c) 2003 Robert Penner, all rights reserved. * This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html. * ============================================================================================ */
/** * Easing function library, from "Easing Equations" by Robert Penner. * @type {Object} * @namespace * {@link enchant.Tween} ใฏใฉในใง็จใใใคใผใธใณใฐ้ขๆฐใฎใฉใคใใฉใชๅๅ็ฉบ้. */ enchant.Easing = { /** * @param t * @param b * @param c * @param d * @return {Number} */ LINEAR: function(t, b, c, d) { return c * t / d + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ SWING: function(t, b, c, d) { return c * (0.5 - Math.cos(((t / d) * Math.PI)) / 2) + b; }, // quad /** * @param t * @param b * @param c * @param d * @return {Number} */ QUAD_EASEIN: function(t, b, c, d) { return c * (t /= d) * t + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ QUAD_EASEOUT: function(t, b, c, d) { return -c * (t /= d) * (t - 2) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ QUAD_EASEINOUT: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t + b; } return -c / 2 * ((--t) * (t - 2) - 1) + b; }, // cubic /** * @param t * @param b * @param c * @param d * @return {Number} */ CUBIC_EASEIN: function(t, b, c, d) { return c * (t /= d) * t * t + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ CUBIC_EASEOUT: function(t, b, c, d) { return c * ((t = t / d - 1) * t * t + 1) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ CUBIC_EASEINOUT: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t + b; } return c / 2 * ((t -= 2) * t * t + 2) + b; }, // quart /** * @param t * @param b * @param c * @param d * @return {Number} */ QUART_EASEIN: function(t, b, c, d) { return c * (t /= d) * t * t * t + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ QUART_EASEOUT: function(t, b, c, d) { return -c * ((t = t / d - 1) * t * t * t - 1) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ QUART_EASEINOUT: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t * t + b; } return -c / 2 * ((t -= 2) * t * t * t - 2) + b; }, // quint /** * @param t * @param b * @param c * @param d * @return {Number} */ QUINT_EASEIN: function(t, b, c, d) { return c * (t /= d) * t * t * t * t + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ QUINT_EASEOUT: function(t, b, c, d) { return c * ((t = t / d - 1) * t * t * t * t + 1) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ QUINT_EASEINOUT: function(t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t * t * t + b; } return c / 2 * ((t -= 2) * t * t * t * t + 2) + b; }, //sin /** * @param t * @param b * @param c * @param d * @return {Number} */ SIN_EASEIN: function(t, b, c, d) { return -c * Math.cos(t / d * (Math.PI / 2)) + c + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ SIN_EASEOUT: function(t, b, c, d) { return c * Math.sin(t / d * (Math.PI / 2)) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ SIN_EASEINOUT: function(t, b, c, d) { return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b; }, // circ /** * @param t * @param b * @param c * @param d * @return {Number} */ CIRC_EASEIN: function(t, b, c, d) { return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ CIRC_EASEOUT: function(t, b, c, d) { return c * Math.sqrt(1 - (t = t / d - 1) * t) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ CIRC_EASEINOUT: function(t, b, c, d) { if ((t /= d / 2) < 1) { return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b; } return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b; }, // elastic /** * @param t * @param b * @param c * @param d * @return {Number} */ ELASTIC_EASEIN: function(t, b, c, d, a, p) { if (t === 0) { return b; } if ((t /= d) === 1) { return b + c; }
if (!p) { p = d * 0.3; }
var s; if (!a || a < Math.abs(c)) { a = c; s = p / 4; } else { s = p / (2 * Math.PI) * Math.asin(c / a); } return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ ELASTIC_EASEOUT: function(t, b, c, d, a, p) { if (t === 0) { return b; } if ((t /= d) === 1) { return b + c; } if (!p) { p = d * 0.3; } var s; if (!a || a < Math.abs(c)) { a = c; s = p / 4; } else { s = p / (2 * Math.PI) * Math.asin(c / a); } return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b); }, /** * @param t * @param b * @param c * @param d * @return {Number} */ ELASTIC_EASEINOUT: function(t, b, c, d, a, p) { if (t === 0) { return b; } if ((t /= d / 2) === 2) { return b + c; } if (!p) { p = d * (0.3 * 1.5); } var s; if (!a || a < Math.abs(c)) { a = c; s = p / 4; } else { s = p / (2 * Math.PI) * Math.asin(c / a); } if (t < 1) { return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b; } return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b; }, // bounce /** * @param t * @param b * @param c * @param d * @return {Number} */ BOUNCE_EASEOUT: function(t, b, c, d) { if ((t /= d) < (1 / 2.75)) { return c * (7.5625 * t * t) + b; } else if (t < (2 / 2.75)) { return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b; } else if (t < (2.5 / 2.75)) { return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b; } else { return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b; } }, /** * @param t * @param b * @param c * @param d * @return {Number} */ BOUNCE_EASEIN: function(t, b, c, d) { return c - enchant.Easing.BOUNCE_EASEOUT(d - t, 0, c, d) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ BOUNCE_EASEINOUT: function(t, b, c, d) { if (t < d / 2) { return enchant.Easing.BOUNCE_EASEIN(t * 2, 0, c, d) * 0.5 + b; } else { return enchant.Easing.BOUNCE_EASEOUT(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b; }
}, // back /** * @param t * @param b * @param c * @param d * @return {Number} */ BACK_EASEIN: function(t, b, c, d, s) { if (s === undefined) { s = 1.70158; } return c * (t /= d) * t * ((s + 1) * t - s) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ BACK_EASEOUT: function(t, b, c, d, s) { if (s === undefined) { s = 1.70158; } return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ BACK_EASEINOUT: function(t, b, c, d, s) { if (s === undefined) { s = 1.70158; } if ((t /= d / 2) < 1) { return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b; } return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b; }, // expo /** * @param t * @param b * @param c * @param d * @return {Number} */ EXPO_EASEIN: function(t, b, c, d) { return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ EXPO_EASEOUT: function(t, b, c, d) { return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b; }, /** * @param t * @param b * @param c * @param d * @return {Number} */ EXPO_EASEINOUT: function(t, b, c, d) { if (t === 0) { return b; } if (t === d) { return b + c; } if ((t /= d / 2) < 1) { return c / 2 * Math.pow(2, 10 * (t - 1)) + b; } return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b; } };
/** * Easing Equations v2.0 */
/** * @scope enchant.ActionEventTarget.prototype * @type {*} */ enchant.ActionEventTarget = enchant.Class.create(enchant.EventTarget, { /** * @name enchant.ActionEventTarget * @class * EventTarget which can change the context of event listeners * @constructs * @extends enchant.EventTarget */ initialize: function() { enchant.EventTarget.apply(this, arguments); }, /** * Issue event. * @param {enchant.Event} e Event issued. */ dispatchEvent: function(e) { var target; if (this.node) { target = this.node; e.target = target; e.localX = e.x - target._offsetX; e.localY = e.y - target._offsetY; } else { this.node = null; }
if (this['on' + e.type] != null) { this['on' + e.type].call(target, e); } var listeners = this._listeners[e.type]; if (listeners != null) { listeners = listeners.slice(); for (var i = 0, len = listeners.length; i < len; i++) { listeners[i].call(target, e); } } } });
/** * @scope enchant.Timeline.prototype */ enchant.Timeline = enchant.Class.create(enchant.EventTarget, { /** * @name enchant.Timeline * @class * Time-line class. * Class for managing the action. * For one node to manipulate the timeline of one must correspond. * ย ย ย ย * Reading a tl.enchant.js, all classes (Group, Scene, Entity, Label, Sprite) of the Node class that inherits ย ย ย ย * Tlthe property, an instance of the Timeline class is generated. ย ย ย ย * Time-line class has a method to add a variety of actions to himself, ย ย ย ย * entities can be animated and various operations by using these briefly. ย ย ย ย * You can choose time based and frame based(default) animation. * * @param node target node * @param [unitialized] if this param is true, when add method called in the first time, * enchant.Event.ENTER_FRAME event listener will be added to node (for reducing unused event listeners) * @constructs */ initialize: function(node) { enchant.EventTarget.call(this); this.node = node; this.queue = []; this.paused = false; this.looped = false; this.isFrameBased = true; this._parallel = null; this._activated = false; this.addEventListener(enchant.Event.ENTER_FRAME, this.tick); }, /** * @private */ _deactivateTimeline: function() { if (this._activated) { this._activated = false; this.node.removeEventListener('enterframe', this._nodeEventListener); } }, /** * @private */ _activateTimeline: function() { if (!this._activated && !this.paused) { this.node.addEventListener("enterframe", this._nodeEventListener); this._activated = true; } }, /** */ setFrameBased: function() { this.isFrameBased = true; }, /** */ setTimeBased: function() { this.isFrameBased = false; }, /** */ next: function(remainingTime) { var e, action = this.queue.shift(); e = new enchant.Event("actionend"); e.timeline = this; action.dispatchEvent(e);
if (this.queue.length === 0) { this._activated = false; this.node.removeEventListener('enterframe', this._nodeEventListener); return; }
if (this.looped) { e = new enchant.Event("removedfromtimeline"); e.timeline = this; action.dispatchEvent(e); action.frame = 0;
this.add(action); } else { // remove after dispatching removedfromtimeline event e = new enchant.Event("removedfromtimeline"); e.timeline = this; action.dispatchEvent(e); } if (remainingTime > 0 || (this.queue[0] && this.queue[0].time === 0)) { var event = new enchant.Event("enterframe"); event.elapsed = remainingTime; this.dispatchEvent(event); } }, /** */ tick: function(enterFrameEvent) { if (this.paused) { return; } if (this.queue.length > 0) { var action = this.queue[0]; if (action.frame === 0) { var f; f = new enchant.Event("actionstart"); f.timeline = this; action.dispatchEvent(f); }
var e = new enchant.Event("actiontick"); e.timeline = this; if (this.isFrameBased) { e.elapsed = 1; } else { e.elapsed = enterFrameEvent.elapsed; } action.dispatchEvent(e); } }, add: function(action) { if (!this._activated) { var tl = this; this._nodeEventListener = function(e) { tl.dispatchEvent(e); }; this.node.addEventListener("enterframe", this._nodeEventListener);
this._activated = true; } if (this._parallel) { this._parallel.actions.push(action); this._parallel = null; } else { this.queue.push(action); } action.frame = 0;
var e = new enchant.Event("addedtotimeline"); e.timeline = this; action.dispatchEvent(e);
e = new enchant.Event("actionadded"); e.action = action; this.dispatchEvent(e);
return this; }, /** */ action: function(params) { return this.add(new enchant.Action(params)); }, /** */ tween: function(params) { return this.add(new enchant.Tween(params)); }, /** */ clear: function() { var e = new enchant.Event("removedfromtimeline"); e.timeline = this;
for (var i = 0, len = this.queue.length; i < len; i++) { this.queue[i].dispatchEvent(e); } this.queue = []; this._deactivateTimeline(); return this; }, /** */ skip: function(frames) { var event = new enchant.Event("enterframe"); if (this.isFrameBased) { event.elapsed = 1; } else { event.elapsed = frames; frames = 1; } while (frames--) { this.dispatchEvent(event); } return this; }, /** */ pause: function() { if (!this.paused) { this.paused = true; this._deactivateTimeline(); } return this; }, /** */ resume: function() { if (this.paused) { this.paused = false; this._activateTimeline(); } return this; }, /** */ loop: function() { this.looped = true; return this; }, /** */ unloop: function() { this.looped = false; return this; }, /** */ delay: function(time) { this.add(new enchant.Action({ time: time })); return this; }, /** */ wait: function(time) { // reserved return this; }, /** */ then: function(func) { var timeline = this; this.add(new enchant.Action({ onactiontick: function(evt) { func.call(timeline.node); }, // if time is 0, next action will be immediately executed time: 0 })); return this; }, /** */ exec: function(func) { this.then(func); }, /** */ cue: function(cue) { var ptr = 0; for (var frame in cue) { if (cue.hasOwnProperty(frame)) { this.delay(frame - ptr); this.then(cue[frame]); ptr = frame; } } }, /** */ repeat: function(func, time) { this.add(new enchant.Action({ onactiontick: function(evt) { func.call(this); }, time: time })); return this; }, /** */ and: function() { var last = this.queue.pop(); if (last instanceof enchant.ParallelAction) { this._parallel = last; this.queue.push(last); } else { var parallel = new enchant.ParallelAction(); parallel.actions.push(last); this.queue.push(parallel); this._parallel = parallel; } return this; }, /** * @ignore */ or: function() { return this; }, /** * @ignore */ doAll: function(children) { return this; }, /** * @ignore */ waitAll: function() { return this; }, /** */ waitUntil: function(func) { var timeline = this; this.add(new enchant.Action({ onactionstart: func, onactiontick: function(evt) { if (func.call(this)) { timeline.next(); } } })); return this; }, /** */ fadeTo: function(opacity, time, easing) { this.tween({ opacity: opacity, time: time, easing: easing }); return this; }, /** */ fadeIn: function(time, easing) { return this.fadeTo(1, time, easing); }, /** */ fadeOut: function(time, easing) { return this.fadeTo(0, time, easing); }, /** */ moveTo: function(x, y, time, easing) { return this.tween({ x: x, y: y, time: time, easing: easing }); }, /** */ moveX: function(x, time, easing) { return this.tween({ x: x, time: time, easing: easing }); }, /** */ moveY: function(y, time, easing) { return this.tween({ y: y, time: time, easing: easing }); }, /** */ moveBy: function(x, y, time, easing) { return this.tween({ x: function() { return this.x + x; }, y: function() { return this.y + y; }, time: time, easing: easing }); }, /** */ hide: function() { return this.then(function() { this.opacity = 0; }); }, /** */ show: function() { return this.then(function() { this.opacity = 1; }); }, /** */ removeFromScene: function() { return this.then(function() { this.scene.removeChild(this); }); }, /** */ scaleTo: function(scale, time, easing) { if (typeof easing === "number") { return this.tween({ scaleX: arguments[0], scaleY: arguments[1], time: arguments[2], easing: arguments[3] }); } return this.tween({ scaleX: scale, scaleY: scale, time: time, easing: easing }); }, /** */ scaleBy: function(scale, time, easing) { if (typeof easing === "number") { return this.tween({ scaleX: function() { return this.scaleX * arguments[0]; }, scaleY: function() { return this.scaleY * arguments[1]; }, time: arguments[2], easing: arguments[3] }); } return this.tween({ scaleX: function() { return this.scaleX * scale; }, scaleY: function() { return this.scaleY * scale; }, time: time, easing: easing }); }, /** */ rotateTo: function(deg, time, easing) { return this.tween({ rotation: deg, time: time, easing: easing }); }, /** */ rotateBy: function(deg, time, easing) { return this.tween({ rotation: function() { return this.rotation + deg; }, time: time, easing: easing }); } }); /** * @scope enchant.Action.prototype * @type {*} */
enchant.Action = enchant.Class.create(enchant.ActionEventTarget, { /** * @name enchant.Action * @class * Action class. ย ย ย ย ย * Actions are units that make up the time line, ย ย ย ย * It is a unit used to specify the action you want to perform. ย ย ย ย * Action has been added to the time line is performed in order. ย ย ย ย * ย ย ย ย ย * Actionstart, actiontick event is fired when the action is started and stopped, ย ย ย ย * When one frame has elapsed actiontick event is also issued. ย ย ย ย * Specify the action you want to perform as a listener for these events. ย ย ย * The transition to the next action automatically the number of frames that are specified in the time has elapsed. * * @constructs * @param param * @config {integer} [time] The number of frames that will last action. infinite length is specified null * @config {function} [onactionstart] Event listener for when the action is initiated * @config {function} [onactiontick] Event listener for when the action has passed one frame * @config {function} [onactionend] Event listener for when the action is finished * @constructs */ initialize: function(param) { enchant.ActionEventTarget.call(this); this.time = null; this.frame = 0; for (var key in param) { if (param.hasOwnProperty(key)) { if (param[key] != null) { this[key] = param[key]; } } } var action = this;
this.timeline = null; this.node = null;
this.addEventListener(enchant.Event.ADDED_TO_TIMELINE, function(evt) { action.timeline = evt.timeline; action.node = evt.timeline.node; action.frame = 0; });
this.addEventListener(enchant.Event.REMOVED_FROM_TIMELINE, function() { action.timeline = null; action.node = null; action.frame = 0; });
this.addEventListener(enchant.Event.ACTION_TICK, function(evt) { var remaining = action.time - (action.frame + evt.elapsed); if (action.time != null && remaining <= 0) { action.frame = action.time; evt.timeline.next(-remaining); } else { action.frame += evt.elapsed; } });
} }); /** * @scope enchant.ParallelAction.prototype */ enchant.ParallelAction = enchant.Class.create(enchant.Action, { /** * @name enchant.ParallelAction * @class * @constructs * @extends enchant.Action */ initialize: function(param) { enchant.Action.call(this, param); var timeline = this.timeline; var node = this.node; /** * Children Actions */ this.actions = []; /** * Removed actions */ this.endedActions = []; var that = this;
this.addEventListener(enchant.Event.ACTION_START, function(evt) { for (var i = 0, len = that.actions.length; i < len; i++) { that.actions[i].dispatchEvent(evt); } });
this.addEventListener(enchant.Event.ACTION_TICK, function(evt) { var i, len, timeline = { next: function(remaining) { var action = that.actions[i]; that.actions.splice(i--, 1); len = that.actions.length; that.endedActions.push(action);
var e = new enchant.Event("actionend"); e.timeline = this; action.dispatchEvent(e);
e = new enchant.Event("removedfromtimeline"); e.timeline = this; action.dispatchEvent(e); } };
var e = new enchant.Event("actiontick"); e.timeline = timeline; e.elapsed = evt.elapsed; for (i = 0, len = that.actions.length; i < len; i++) { that.actions[i].dispatchEvent(e); }
if (that.actions.length === 0) { evt.timeline.next(); } });
this.addEventListener(enchant.Event.ADDED_TO_TIMELINE, function(evt) { for (var i = 0, len = that.actions.length; i < len; i++) { that.actions[i].dispatchEvent(evt); } });
this.addEventListener(enchant.Event.REMOVED_FROM_TIMELINE, function() { this.actions = this.endedActions; this.endedActions = []; });
} });
/** * @scope enchant.Tween.prototype */ enchant.Tween = enchant.Class.create(enchant.Action, { /** * @name enchant.Tween * @class */ initialize: function(params) { var origin = {}; var target = {}; enchant.Action.call(this, params);
if (this.easing == null) { // linear this.easing = function(t, b, c, d) { return c * t / d + b; }; }
var tween = this; this.addEventListener(enchant.Event.ACTION_START, function() { // excepted property var excepted = ["frame", "time", "callback", "onactiontick", "onactionstart", "onactionend"]; for (var prop in params) { if (params.hasOwnProperty(prop)) { // if function is used instead of numerical value, evaluate it var target_val; if (typeof params[prop] === "function") { target_val = params[prop].call(tween.node); } else { target_val = params[prop]; }
if (excepted.indexOf(prop) === -1) { origin[prop] = tween.node[prop]; target[prop] = target_val; } } } });
this.addEventListener(enchant.Event.ACTION_TICK, function(evt) { // if time is 0, set property to target value immediately var ratio = tween.time === 0 ? 1 : tween.easing(Math.min(tween.time,tween.frame + evt.elapsed), 0, 1, tween.time) - tween.easing(tween.frame, 0, 1, tween.time);
for (var prop in target){ if (target.hasOwnProperty(prop)) { if (typeof this[prop] === "undefined"){ continue; } tween.node[prop] += (target[prop] - origin[prop]) * ratio; if (Math.abs(tween.node[prop]) < 10e-8){ tween.node[prop] = 0; } } } }); } }); /** * */ }(window));
|
pendingโฆ |
usual packing |
(function(e,t){typeof Object.defineProperty!="function"&&(Object.defineProperty=function(e,t,n){return"value"in n&&(e[t]=n.value),"get"in n&&e.__defineGetter__(t,n.get),"set"in n&&e.__defineSetter__(t,n.set),e}),typeof Object.defineProperties!="function"&&(Object.defineProperties=function(e,t){for(var n in t)t.hasOwnProperty(n)&&Object.defineProperty(e,n,t[n]);return e}),typeof Object.create!="function"&&(Object.create=function(e,t){function n(){}n.prototype=e;var r=new n;return t!=null&&Object.defineProperties(r,t),r}),typeof Object.getPrototypeOf!="function"&&(Object.getPrototypeOf=function(e){return e.__proto__}),typeof Function.prototype.bind!="function"&&(Function.prototype.bind=function(t){var n=this,r=Array.prototype.slice.call(arguments,1),i=function(){},s=function(){var s=r.concat(Array.prototype.slice.call(arguments));return n.apply(this instanceof i?this:t||e,s)};return i.prototype=n.prototype,s.prototype=new i,s});var n=function(t){t!=null&&(t instanceof Array||(t=Array.prototype.slice.call(arguments)),t=t.filter(function(e){return[e].join()})),function r(n,i){var s=[],o,u;for(var a in n)n.hasOwnProperty(a)&&(typeof n[a]=="function"?e[a]=n[a]:typeof n[a]=="object"&&Object.getPrototypeOf(n[a])===Object.prototype&&(t==null?s.push(a):(o=t.indexOf(i+a),o!==-1&&(s.push(a),t.splice(o,1)))));for(o=0,u=s.length;o<u;o++)r(n[s[o]],i+s[o]+".")}(n,""),e.Game=e.Core;if(t!=null&&t.length)throw new Error("Cannot load module: "+t.join(", "))};e.enchant=n,e.addEventListener("message",function(e,t){try{var r=JSON.parse(e.data);if(r.type==="event")n.Core.instance.dispatchEvent(new n.Event(r.value));else if(r.type==="debug")switch(r.value){case"start":n.Core.instance.start();break;case"pause":n.Core.instance.pause();break;case"resume":n.Core.instance.resume();break;case"tick":n.Core.instance._tick();break;default:}}catch(i){}},!1),n.Class=function(e,t){return n.Class.create(e,t)},n.Class.create=function(e,t){if(e==null)throw new Error("superclass is undefined");if(arguments.length===0)return n.Class.create(Object,t);if(arguments.length===1&&typeof arguments[0]!="function")return n.Class.create(Object,arguments[0]);for(var r in t)t.hasOwnProperty(r)&&(typeof t[r]=="object"&&t[r]!==null&&Object.getPrototypeOf(t[r])===Object.prototype?"enumerable"in t[r]||(t[r].enumerable=!0):t[r]={value:t[r],enumerable:!0,writable:!0});var i=function(){if(!(this instanceof i))return new i;i.prototype.initialize.apply(this,arguments)};i.prototype=Object.create(e.prototype,t),i.prototype.constructor=i,i.prototype.initialize==null&&(i.prototype.initialize=function(){e.apply(this,arguments)});var s=this.getInheritanceTree(e);for(var o=s.length-1;o>=0;o--)if(typeof s[o]._inherited=="function"){s[o]._inherited(i);break}return i},n.Class.getInheritanceTree=function(e){var t=[],n=e,r=n.prototype;while(n!==Object)t.push(n),r=Object.getPrototypeOf(r),n=r.constructor;return t},n.ENV={VENDOR_PREFIX:function(){var e=navigator.userAgent;return e.indexOf("Opera")!==-1?"O":e.indexOf("MSIE")!==-1?"ms":e.indexOf("WebKit")!==-1?"webkit":navigator.product==="Gecko"?"Moz":""}(),TOUCH_ENABLED:function(){var e=document.createElement("div");return e.setAttribute("ontouchstart","return"),typeof e.ontouchstart=="function"}(),RETINA_DISPLAY:function(){if(navigator.userAgent.indexOf("iPhone")!==-1&&e.devicePixelRatio===2){var t=document.querySelector('meta[name="viewport"]');return t==null&&(t=document.createElement("meta"),document.head.appendChild(t)),t.setAttribute("content","width=640"),!0}return!1}(),USE_FLASH_SOUND:function(){var e=navigator.userAgent,t=navigator.vendor||"";return location.href.indexOf("http")===0&&e.indexOf("Mobile")===-1&&t.indexOf("Apple")!==-1}(),USE_DEFAULT_EVENT_TAGS:["input","textarea","select","area"],CANVAS_DRAWING_METHODS:["putImageData","drawImage","drawFocusRing","fill","stroke","clearRect","fillRect","strokeRect","fillText","strokeText"],KEY_BIND_TABLE:{37:"left",38:"up",39:"right",40:"down"},PREVENT_DEFAULT_KEY_CODES:[37,38,39,40,32],SOUND_ENABLED_ON_MOBILE_SAFARI:!1,USE_WEBAUDIO:function(){return location.protocol!=="file:"}(),USE_ANIMATION:!0},n.Event=n.Class.create({initialize:function(e){this.type=e,this.target=null,this.x=0,this.y=0,this.localX=0,this.localY=0},_initPosition:function(e,t){var r=n.Core.instance;this.x=this.localX=(e-r._pageX)/r.scale,this.y=this.localY=(t-r._pageY)/r.scale}}),n.Event.LOAD="load",n.Event.PROGRESS="progress",n.Event.ENTER_FRAME="enterframe",n.Event.EXIT_FRAME="exitframe",n.Event.ENTER="enter",n.Event.EXIT="exit",n.Event.CHILD_ADDED="childadded",n.Event.ADDED="added",n.Event.ADDED_TO_SCENE="addedtoscene",n.Event.CHILD_REMOVED="childremoved",n.Event.REMOVED="removed",n.Event.REMOVED_FROM_SCENE="removedfromscene",n.Event.TOUCH_START="touchstart",n.Event.TOUCH_MOVE="touchmove",n.Event.TOUCH_END="touchend",n.Event.RENDER="render",n.Event.INPUT_START="inputstart",n.Event.INPUT_CHANGE="inputchange",n.Event.INPUT_END="inputend",n.Event.LEFT_BUTTON_DOWN="leftbuttondown",n.Event.LEFT_BUTTON_UP="leftbuttonup",n.Event.RIGHT_BUTTON_DOWN="rightbuttondown",n.Event.RIGHT_BUTTON_UP="rightbuttonup",n.Event.UP_BUTTON_DOWN="upbuttondown",n.Event.UP_BUTTON_UP="upbuttonup",n.Event.DOWN_BUTTON_DOWN="downbuttondown",n.Event.DOWN_BUTTON_UP="downbuttonup",n.Event.A_BUTTON_DOWN="abuttondown",n.Event.A_BUTTON_UP="abuttonup",n.Event.B_BUTTON_DOWN="bbuttondown",n.Event.B_BUTTON_UP="bbuttonup",n.Event.ADDED_TO_TIMELINE="addedtotimeline",n.Event.REMOVED_FROM_TIMELINE="removedfromtimeline",n.Event.ACTION_START="actionstart",n.Event.ACTION_END="actionend",n.Event.ACTION_TICK="actiontick",n.Event.ACTION_ADDED="actionadded",n.Event.ACTION_REMOVED="actionremoved",n.EventTarget=n.Class.create({initialize:function(){this._listeners={}},addEventListener:function(e,t){var n=this._listeners[e];n==null?this._listeners[e]=[t]:n.indexOf(t)===-1&&n.unshift(t)},on:function(){this.addEventListener.apply(this,arguments)},removeEventListener:function(e,t){var n=this._listeners[e];if(n!=null){var r=n.indexOf(t);r!==-1&&n.splice(r,1)}},clearEventListener:function(e){e!=null?delete this._listeners[e]:this._listeners={}},dispatchEvent:function(e){e.target=this,e.localX=e.x-this._offsetX,e.localY=e.y-this._offsetY,this["on"+e.type]!=null&&this["on"+e.type](e);var t=this._listeners[e.type];if(t!=null){t=t.slice();for(var n=0,r=t.length;n<r;n++)t[n].call(this,e)}}}),function(){var t;n.Core=n.Class.create(n.EventTarget,{initialize:function(r,i){if(e.document.body===null)throw new Error("document.body is null. Please excute 'new Core()' in window.onload.");n.EventTarget.call(this);var s=!0;t&&(s=!1,t.stop()),t=n.Core.instance=this,this.width=r||320,this.height=i||320,this.scale=1;var o=document.getElementById("enchant-stage");if(!o)o=document.createElement("div"),o.id="enchant-stage",o.style.position="absolute",document.body.firstChild?document.body.insertBefore(o,document.body.firstChild):document.body.appendChild(o),this.scale=Math.min(e.innerWidth/this.width,e.innerHeight/this.height),this._pageX=0,this._pageY=0;else{var u=e.getComputedStyle(o);r=parseInt(u.width,10),i=parseInt(u.height,10),r&&i?this.scale=Math.min(r/this.width,i/this.height):(o.style.width=this.width+"px",o.style.height=this.height+"px");while(o.firstChild)o.removeChild(o.firstChild);o.style.position="relative";var a=o.getBoundingClientRect();this._pageX=Math.round(e.scrollX+a.left),this._pageY=Math.round(e.scrollY+a.top)}this.scale||(this.scale=1),o.style.fontSize="12px",o.style.webkitTextSizeAdjust="none",this._element=o,this.fps=30,this.frame=0,this.ready=null,this.running=!1,this.assets={};var f=this._assets=[];(function b(e){e.assets instanceof Array&&[].push.apply(f,e.assets);for(var t in e)e.hasOwnProperty(t)&&typeof e[t]=="object"&&Object.getPrototypeOf(e[t])===Object.prototype&&b(e[t])})(n),this._scenes=[],this.currentScene=null,this.rootScene=new n.Scene,this.pushScene(this.rootScene),this.loadingScene=new n.Scene,this.loadingScene.backgroundColor="#000";var l=this.width*.4|0,c=this.width*.05|0,h=l*.03|0,p=new n.Sprite(l,c);p.x=(this.width-l)/2,p.y=(this.height-c)/2;var d=new n.Surface(l,c);d.context.fillStyle="#fff",d.context.fillRect(0,0,l,c),d.context.fillStyle="#000",d.context.fillRect(h,h,l-h*2,c-h*2),p.image=d;var v=0,m=0;this.addEventListener("progress",function(e){v=e.loaded/e.total}),p.addEventListener("enterframe",function(){m*=.9,m+=v*.1,d.context.fillStyle="#fff",d.context.fillRect(h,0,(l-h*2)*m,c)}),this.loadingScene.addChild(p),this._mousedownID=0,this._surfaceID=0,this._soundID=0,this._intervalID=null,this._offsetX=0,this._offsetY=0,this.input={},this._keybind=n.ENV.KEY_BIND_TABLE||{};var g=0;["left","right","up","down","a","b"].forEach(function(e){this.addEventListener(e+"buttondown",function(t){var r;this.input[e]||(this.input[e]=!0,r=new n.Event(g++?"inputchange":"inputstart"),this.dispatchEvent(r)),this.currentScene.dispatchEvent(t),r&&this.currentScene.dispatchEvent(r)}),this.addEventListener(e+"buttonup",function(t){var r;this.input[e]&&(this.input[e]=!1,r=new n.Event(--g?"inputchange":"inputend"),this.dispatchEvent(r)),this.currentScene.dispatchEvent(t),r&&this.currentScene.dispatchEvent(r)})},this);if(s){o=n.Core.instance._element;var y;document.addEventListener("keydown",function(e){t.dispatchEvent(new n.Event("keydown")),n.ENV.PREVENT_DEFAULT_KEY_CODES.indexOf(e.keyCode)!==-1&&(e.preventDefault(),e.stopPropagation());if(!t.running)return;var r=t._keybind[e.keyCode];r&&(y=new n.Event(r+"buttondown"),t.dispatchEvent(y))},!0),document.addEventListener("keyup",function(e){if(!t.running)return;var r=t._keybind[e.keyCode];r&&(y=new n.Event(r+"buttonup"),t.dispatchEvent(y))},!0),n.ENV.TOUCH_ENABLED&&(o.addEventListener("touchstart",function(e){var r=e.target.tagName.toLowerCase();n.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(r)===-1&&(e.preventDefault(),t.running||e.stopPropagation())},!0),o.addEventListener("touchmove",function(e){var r=e.target.tagName.toLowerCase();n.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(r)===-1&&(e.preventDefault(),t.running||e.stopPropagation())},!0),o.addEventListener("touchend",function(e){var r=e.target.tagName.toLowerCase();n.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(r)===-1&&(e.preventDefault(),t.running||e.stopPropagation())},!0)),o.addEventListener("mousedown",function(e){var r=e.target.tagName.toLowerCase();n.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(r)===-1&&(e.preventDefault(),t._mousedownID++,t.running||e.stopPropagation())},!0),o.addEventListener("mousemove",function(e){var r=e.target.tagName.toLowerCase();n.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(r)===-1&&(e.preventDefault(),t.running||e.stopPropagation())},!0),o.addEventListener("mouseup",function(e){var r=e.target.tagName.toLowerCase();n.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(r)===-1&&(e.preventDefault(),t.running||e.stopPropagation())},!0),t._touchEventTarget={},n.ENV.TOUCH_ENABLED&&(o.addEventListener("touchstart",function(e){var t=n.Core.instance,r=new n.Event(n.Event.TOUCH_START),i=e.changedTouches,s,o;for(var u=0,a=i.length;u<a;u++)s=i[u],r._initPosition(s.pageX,s.pageY),o=t.currentScene._determineEventTarget(r),t._touchEventTarget[s.identifier]=o,o.dispatchEvent(r)},!1),o.addEventListener("touchmove",function(e){var t=n.Core.instance,r=new n.Event(n.Event.TOUCH_MOVE),i=e.changedTouches,s,o;for(var u=0,a=i.length;u<a;u++)s=i[u],o=t._touchEventTarget[s.identifier],o&&(r._initPosition(s.pageX,s.pageY),o.dispatchEvent(r))},!1),o.addEventListener("touchend",function(e){var t=n.Core.instance,r=new n.Event(n.Event.TOUCH_END),i=e.changedTouches,s,o;for(var u=0,a=i.length;u<a;u++)s=i[u],o=t._touchEventTarget[s.identifier],o&&(r._initPosition(s.pageX,s.pageY),o.dispatchEvent(r),delete t._touchEventTarget[s.identifier])},!1)),o.addEventListener("mousedown",function(e){var t=n.Core.instance,r=new n.Event(n.Event.TOUCH_START);r._initPosition(e.pageX,e.pageY);var i=t.currentScene._determineEventTarget(r);t._touchEventTarget[t._mousedownID]=i,i.dispatchEvent(r)},!1),o.addEventListener("mousemove",function(e){var t=n.Core.instance,r=new n.Event(n.Event.TOUCH_MOVE);r._initPosition(e.pageX,e.pageY);var i=t._touchEventTarget[t._mousedownID];i&&i.dispatchEvent(r)},!1),o.addEventListener("mouseup",function(e){var t=n.Core.instance,r=new n.Event(n.Event.TOUCH_END);r._initPosition(e.pageX,e.pageY),t._touchEventTarget[t._mousedownID].dispatchEvent(r),delete t._touchEventTarget[t._mousedownID]},!1)}},preload:function(e){e instanceof Array||(e=Array.prototype.slice.call(arguments)),[].push.apply(this._assets,e)},load:function(e,r){r==null&&(r=function(){});var i=n.Core.findExt(e);if(n.Core._loadFuncs[i])n.Core._loadFuncs[i].call(this,e,r,i);else{var s=new XMLHttpRequest;s.open("GET",e,!0),s.onreadystatechange=function(i){if(s.readyState===4){if(s.status!==200&&s.status!==0)throw new Error(s.status+": "+"Cannot load an asset: "+e);var o=s.getResponseHeader("Content-Type")||"";o.match(/^image/)?(t.assets[e]=n.Surface.load(e),t.assets[e].addEventListener("load",r)):o.match(/^audio/)?(t.assets[e]=n.Sound.load(e,o),t.assets[e].addEventListener("load",r)):(t.assets[e]=s.responseText,r())}},s.send(null)}},start:function(){var r=function(){this.currentTime=this.getTime(),this.removeEventListener("load",r),this._intervalID=e.setInterval(function(){t._tick()},1e3/this.fps),this.running=!0};this.addEventListener("load",r);if(this._intervalID)e.clearInterval(this._intervalID);else if(this._assets.length){if(n.Sound.enabledInMobileSafari&&!t._touched&&n.ENV.VENDOR_PREFIX==="webkit"&&n.ENV.TOUCH_ENABLED){var i=new n.Scene;i.backgroundColor="#000";var s=Math.round(t.width/10),o=new n.Sprite(t.width,s);o.y=(t.height-s)/2,o.image=new n.Surface(t.width,s),o.image.context.fillStyle="#fff",o.image.context.font=s-1+"px bold Helvetica,Arial,sans-serif";var u=o.image.context.measureText("Touch to Start").width;o.image.context.fillText("Touch to Start",(t.width-u)/2,s-1),i.addChild(o),document.addEventListener("touchstart",function(){t._touched=!0,t.removeScene(i),t.start()},!0),t.pushScene(i);return}var a={},f=this._assets.filter(function(e){return e in a?!1:a[e]=!0}),l=0,c=f.length,h=function(){var e=new n.Event("progress");e.loaded=++l,e.total=c,t.dispatchEvent(e),l===c&&(t.removeScene(t.loadingScene),t.dispatchEvent(new n.Event("load")))};for(var p=0;p<c;p++)this.load(f[p],h);this.pushScene(this.loadingScene)}else this.dispatchEvent(new n.Event("load"))},debug:function(){this._debug=!0,this.rootScene.addEventListener("enterframe",function(e){this._actualFps=1/e}),this.start()},actualFps:{get:function(){return this._actualFps||this.fps}},_tick:function(){var e=this.getTime(),t=new n.Event("enterframe");t.elapsed=e-this.currentTime,this.currentTime=e;var r=this.currentScene.childNodes.slice(),i=Array.prototype.push;while(r.length){var s=r.pop();s.age++,s.dispatchEvent(t),s.childNodes&&i.apply(r,s.childNodes)}this.currentScene.age++,this.currentScene.dispatchEvent(t),this.dispatchEvent(t),this.dispatchEvent(new n.Event("exitframe")),this.frame++},getTime:function(){return e.performance&&e.performance.now?e.performance.now():e.performance&&e.performance.webkitNow?e.performance.webkitNow():Date.now()},stop:function(){this._intervalID&&(e.clearInterval(this._intervalID),this._intervalID=null),this.running=!1},pause:function(){this._intervalID&&(e.clearInterval(this._intervalID),this._intervalID=null)},resume:function(){if(this._intervalID)return;this.currentTime=this.getTime(),this._intervalID=e.setInterval(function(){t._tick()},1e3/this.fps),this.running=!0},pushScene:function(e){return this._element.appendChild(e._element),this.currentScene&&this.currentScene.dispatchEvent(new n.Event("exit")),this.currentScene=e,this.currentScene.dispatchEvent(new n.Event("enter")),this._scenes.push(e)},popScene:function(){return this.currentScene===this.rootScene?this.currentScene:(this._element.removeChild(this.currentScene._element),this.currentScene.dispatchEvent(new n.Event("exit")),this.currentScene=this._scenes[this._scenes.length-2],this.currentScene.dispatchEvent(new n.Event("enter")),this._scenes.pop())},replaceScene:function(e){return this.popScene(),this.pushScene(e)},removeScene:function(e){if(this.currentScene===e)return this.popScene();var t=this._scenes.indexOf(e);return t!==-1?(this._scenes.splice(t,1),this._element.removeChild(e._element),e):null},keybind:function(e,t){this._keybind[e]=t},getElapsedTime:function(){return this.frame/this.fps}}),n.Core._loadFuncs={},n.Core._loadFuncs.jpg=n.Core._loadFuncs.jpeg=n.Core._loadFuncs.gif=n.Core._loadFuncs.png=n.Core._loadFuncs.bmp=function(e,t){this.assets[e]=n.Surface.load(e),this.assets[e].addEventListener("load",t)},n.Core._loadFuncs.mp3=n.Core._loadFuncs.aac=n.Core._loadFuncs.m4a=n.Core._loadFuncs.wav=n.Core._loadFuncs.ogg=function(e,t,r){this.assets[e]=n.Sound.load(e,"audio/"+r),this.assets[e].addEventListener("load",t)},n.Core.findExt=function(e){var t=e.match(/\.\w+$/);return t&&t.length>0?t[0].slice(1).toLowerCase():e.indexOf("data:")===0?e.split(/[\/;]/)[1].toLowerCase():null},n.Core.instance=null}(),n.Game=n.Core,n.Node=n.Class.create(n.EventTarget,{initialize:function(){n.EventTarget.call(this),this._dirty=!1,this._matrix=[1,0,0,1,0,0],this._x=0,this._y=0,this._offsetX=0,this._offsetY=0,this.age=0,this.parentNode=null,this.scene=null,this.addEventListener("touchstart",function(e){this.parentNode&&this.parentNode.dispatchEvent(e)}),this.addEventListener("touchmove",function(e){this.parentNode&&this.parentNode.dispatchEvent(e)}),this.addEventListener("touchend",function(e){this.parentNode&&this.parentNode.dispatchEvent(e)});if(n.ENV.USE_ANIMATION)var e=this.tl=new n.Timeline(this)},moveTo:function(e,t){this._x=e,this._y=t,this._dirty=!0},moveBy:function(e,t){this._x+=e,this._y+=t,this._dirty=!0},x:{get:function(){return this._x},set:function(e){this._x=e,this._dirty=!0}},y:{get:function(){return this._y},set:function(e){this._y=e,this._dirty=!0}},_updateCoordinate:function(){var e=this,t=[e],r=e.parentNode,i=this.scene;while(r&&e._dirty)t.unshift(r),e=e.parentNode,r=e.parentNode;var s=n.Matrix.instance,o=s.stack,u=[],a,f,l;o.push(t[0]._matrix);for(var c=1,h=t.length;c<h;c++){e=t[c],a=[],s.makeTransformMatrix(e,u),s.multiply(o[o.length-1],u,a),e._matrix=a,o.push(a),f=typeof e._originX=="number"?e._originX:e._width/2||0,l=typeof e._originY=="number"?e._originY:e._height/2||0;var p=[f,l];s.multiplyVec(a,p,p),e._offsetX=p[0]-f,e._offsetY=p[1]-l,e._dirty=!1}s.reset()},remove:function(){this._listener&&this.clearEventListener(),this.parentNode&&this.parentNode.removeChild(this)}});var r=function(e,t){var n=[],r;for(var i=0,s=e.collection.length;i<s;i++)r=e.collection[i],t._intersectone(r)&&n.push(r);return n},i=function(e,t){var n=[],r,i;for(var s=0,o=e.collection.length;s<o;s++){r=e.collection[s];for(var u=0,a=t.collection.length;u<a;u++)i=t.collection[u],r._intersectone(i)&&n.push([r,i])}return n},s=function(e){return e instanceof n.Entity?r(this,e):typeof e=="function"&&e.collection?i(this,e):!1};n.Entity=n.Class.create(n.Node,{initialize:function(){var e=n.Core.instance;n.Node.call(this),this._rotation=0,this._scaleX=1,this._scaleY=1,this._touchEnabled=!0,this._clipping=!1,this._originX=null,this._originY=null,this._width=0,this._height=0,this._backgroundColor=null,this._opacity=1,this._visible=!0,this._buttonMode=null,this._style={},this.__styleStatus={},this.compositeOperation=null,this.buttonMode=null,this.buttonPressed=!1,this.addEventListener("touchstart",function(){if(!this.buttonMode)return;this.buttonPressed=!0;var t=new n.Event(this.buttonMode+"buttondown");this.dispatchEvent(t),e.dispatchEvent(t)}),this.addEventListener("touchend",function(){if(!this.buttonMode)return;this.buttonPressed=!1;var t=new n.Event(this.buttonMode+"buttonup");this.dispatchEvent(t),e.dispatchEvent(t)}),this.enableCollection()},width:{get:function(){return this._width},set:function(e){this._width=e,this._dirty=!0}},height:{get:function(){return this._height},set:function(e){this._height=e,this._dirty=!0}},backgroundColor:{get:function(){return this._backgroundColor},set:function(e){this._backgroundColor=e}},opacity:{get:function(){return this._opacity},set:function(e){this._opacity=e}},visible:{get:function(){return this._visible},set:function(e){this._visible=e}},touchEnabled:{get:function(){return this._touchEnabled},set:function(e){this._touchEnabled=e,(this._touchEnabled=e)?this._style.pointerEvents="all":this._style.pointerEvents="none"}},intersect:function(e){return e instanceof n.Entity?this._intersectone(e):typeof e=="function"&&e.collection?r(e,this):!1},_intersectone:function(e){return this._dirty&&this._updateCoordinate(),e._dirty&&e._updateCoordinate(),this._offsetX<e._offsetX+e.width&&e._offsetX<this._offsetX+this.width&&this._offsetY<e._offsetY+e.height&&e._offsetY<this._offsetY+this.height},within:function(e,t){this._dirty&&this._updateCoordinate(),e._dirty&&e._updateCoordinate(),t==null&&(t=(this.width+this.height+e.width+e.height)/4);var n;return(n=this._offsetX-e._offsetX+(this.width-e.width)/2)*n+(n=this._offsetY-e._offsetY+(this.height-e.height)/2)*n<t*t},scale:function(e,t){this._scaleX*=e,this._scaleY*=t!=null?t:e,this._dirty=!0},rotate:function(e){this._rotation+=e,this._dirty=!0},scaleX:{get:function(){return this._scaleX},set:function(e){this._scaleX=e,this._dirty=!0}},scaleY:{get:function(){return this._scaleY},set:function(e){this._scaleY=e,this._dirty=!0}},rotation:{get:function(){return this._rotation},set:function(e){this._rotation=e,this._dirty=!0}},originX:{get:function(){return this._originX},set:function(e){this._originX=e,this._dirty=!0}},originY:{get:function(){return this._originY},set:function(e){this._originY=e,this._dirty=!0}},enableCollection:function(){this.addEventListener("addedtoscene",this._addSelfToCollection),this.addEventListener("removedfromscene",this._removeSelfFromCollection),this.scene&&this._addSelfToCollection()},disableCollection:function(){this.removeEventListener("addedtoscene",this._addSelfToCollection),this.removeEventListener("removedfromscene",this._removeSelfFromCollection),this.scene&&this._removeSelfFromCollection()},_addSelfToCollection:function(){var e=this.getConstructor();e._collectionTarget.forEach(function(e){e.collection.push(this)},this)},_removeSelfFromCollection:function(){var e=this.getConstructor();e._collectionTarget.forEach(function(e){var t=e.collection.indexOf(this);t!==-1&&e.collection.splice(t,1)},this)},getConstructor:function(){return Object.getPrototypeOf(this).constructor}});var o=function(e){if(e._collective)return;var t=n.Class.getInheritanceTree(e),r=t.indexOf(n.Entity);r!==-1?e._collectionTarget=t.splice(0,r+1):e._collectionTarget=[],e.intersect=s,e.collection=[],e._collective=!0};o(n.Entity),n.Entity._inherited=function(e){o(e)},n.Sprite=n.Class.create(n.Entity,{initialize:function(e,t){n.Entity.call(this),this.width=e,this.height=t,this._image=null,this._frameLeft=0,this._frameTop=0,this._frame=0,this._frameSequence=[],this.addEventListener("enterframe",function(){if(this._frameSequence.length!==0){var e=this._frameSequence.shift();e===null?this._frameSequence=[]:(this._setFrame(e),this._frameSequence.push(e))}})},image:{get:function(){return this._image},set:function(e){if(e===this._image)return;this._image=e,this._setFrame(this._frame)}},frame:{get:function(){return this._frame},set:function(e){if(this._frame===e)return;if(e instanceof Array){var t=e,n=t.shift();this._setFrame(n),t.push(n),this._frameSequence=t}else this._setFrame(e),this._frameSequence=[],this._frame=e}},_setFrame:function(e){var t=this._image,n,r;t!=null&&(this._frame=e,n=t.width/this._width|0,this._frameLeft=(e%n|0)*this._width,this._frameTop=(e/n|0)*this._height%t.height)},width:{get:function(){return this._width},set:function(e){this._width=e,this._setFrame(),this._dirty=!0}},height:{get:function(){return this._height},set:function(e){this._height=e,this._setFrame(),this._dirty=!0}},cvsRender:function(e){if(this._image==null||this._width===0||this._height===0)return;var t=this._image,n=t._element,r=this._frameLeft,i=this._frameTop,s=Math.min(this.width,t.width-r),o=Math.min(this.height,t.height-i),u=Math.min(t.width,this.width),a=Math.min(t.height,this.height),f,l,c,h;for(l=0;l<this.height;l+=a){h=this.height<l+a?this.height-l:a;for(f=0;f<this.width;f+=u)c=this.width<f+u?this.width-f:u,e.drawImage(n,r,i,s*c/u,o*h/a,f,l,c,h)}},domRender:function(e){this._image&&(this._image._css?(this._style["background-image"]=this._image._css,this._style["background-position"]=-this._frameLeft+"px "+ -this._frameTop+"px"):this._image._element)}}),n.Label=n.Class.create(n.Entity,{initialize:function(e){n.Entity.call(this),this.width=300,this.font="14px serif",this.text=e||"",this.textAlign="left"},text:{get:function(){return this._text},set:function(e){if(this._text===e)return;this._text=e,e=e.replace(/<(br|BR) ?\/?>/g,"<br/>"),this._splitText=e.split("<br/>");var t=this.getMetrics();this._boundWidth=t.width,this._boundHeight=t.height;for(var n=0,r=this._splitText.length;n<r;n++)e=this._splitText[n],t=this.getMetrics(e),this._splitText[n]={},this._splitText[n].text=e,this._splitText[n].height=t.height}},textAlign:{get:function(){return this._style["text-align"]},set:function(e){this._style["text-align"]=e}},font:{get:function(){return this._style.font},set:function(e){this._style.font=e}},color:{get:function(){return this._style.color},set:function(e){this._style.color=e}},cvsRender:function(e){var t=0,n,r,i;if(this._splitText){e.textBaseline="top",e.font=this.font,e.fillStyle=this.color||"#000000";for(var s=0,o=this._splitText.length;s<o;s++){n=this._splitText[s],r="";for(var u=0,a=n.text.length;u<a;u++)i=n.text[u],e.measureText(r).width>this.width&&(e.fillText(r,0,t),t+=n.height-1,r=""),r+=i;e.fillText(r,0,t),t+=n.height-1}}},domRender:function(e){e.innerHTML!==this._text&&(e.innerHTML=this._text)},detectRender:function(e){e.fillRect(0,0,this._boundWidth,this._boundHeight)}}),n.Label.prototype.getMetrics=function(e){var t={},n,r,i;if(document.body){n=document.createElement("div");for(var s in this._style)s!=="width"&&s!=="height"&&(n.style[s]=this._style[s]);n.innerHTML=e||this._text,document.body.appendChild(n),t.height=parseInt(getComputedStyle(n).height,10)+1,n.style.position="absolute",t.width=parseInt(getComputedStyle(n).width,10)+1,document.body.removeChild(n)}else t.width=this.width,t.height=this.height;return t},n.Map=n.Class.create(n.Entity,{initialize:function(e,t){var r=n.Core.instance;n.Entity.call(this);var i=new n.Surface(r.width,r.height);this._surface=i;var s=i._element;s.style.position="absolute",n.ENV.RETINA_DISPLAY&&r.scale===2?(s.width=r.width*2,s.height=r.height*2,this._style.webkitTransformOrigin="0 0",this._style.webkitTransform="scale(0.5)"):(s.width=r.width,s.height=r.height),this._context=s.getContext("2d"),this._tileWidth=e||0,this._tileHeight=t||0,this._image=null,this._data=[[[]]],this._dirty=!1,this._tight=!1,this.touchEnabled=!1,this.collisionData=null,this._listeners.render=null,this.addEventListener("render",function(){if(this._dirty||this._previousOffsetX==null)this.redraw(0,0,r.width,r.height);else if(this._offsetX!==this._previousOffsetX||this._offsetY!==this._previousOffsetY)if(this._tight){var e=-this._offsetX,t=-this._offsetY,n=-this._previousOffsetX,i=-this._previousOffsetY,s=e-n+r.width,o=n-e+r.width,u=t-i+r.height,a=i-t+r.height;if(s>this._tileWidth&&o>this._tileWidth&&u>this._tileHeight&&a>this._tileHeight){var f,l,c,h,p,d;s<o?(f=0,c=n-e,p=s):(f=e-n,c=0,p=o),u<a?(l=0,h=i-t,d=u):(l=t-i,h=0,d=a),r._buffer==null&&(r._buffer=document.createElement("canvas"),r._buffer.width=this._context.canvas.width,r._buffer.height=this._context.canvas.height);var v=r._buffer.getContext("2d");this._doubledImage?(v.clearRect(0,0,p*2,d*2),v.drawImage(this._context.canvas,f*2,l*2,p*2,d*2,0,0,p*2,d*2),v=this._context,v.clearRect(c*2,h*2,p*2,d*2),v.drawImage(r._buffer,0,0,p*2,d*2,c*2,h*2,p*2,d*2)):(v.clearRect(0,0,p,d),v.drawImage(this._context.canvas,f,l,p,d,0,0,p,d),v=this._context,v.clearRect(c,h,p,d),v.drawImage(r._buffer,0,0,p,d,c,h,p,d)),c===0?this.redraw(p,0,r.width-p,r.height):this.redraw(0,0,r.width-p,r.height),h===0?this.redraw(0,d,r.width,r.height-d):this.redraw(0,0,r.width,r.height-d)}else this.redraw(0,0,r.width,r.height)}else this.redraw(0,0,r.width,r.height);this._previousOffsetX=this._offsetX,this._previousOffsetY=this._offsetY})},loadData:function(e){this._data=Array.prototype.slice.apply(arguments),
|