Guest User

Untitled

a guest
Apr 24th, 2016
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 196.59 KB | None | 0 0
  1. //=============================================================================
  2. // rpg_core.js v1.2.0
  3. //=============================================================================
  4.  
  5. //-----------------------------------------------------------------------------
  6. /**
  7. * This is not a class, but contains some methods that will be added to the
  8. * standard Javascript objects.
  9. *
  10. * @class JsExtensions
  11. */
  12. function JsExtensions() {
  13. throw new Error('This is not a class');
  14. }
  15.  
  16. /**
  17. * Returns a number whose value is limited to the given range.
  18. *
  19. * @method Number.prototype.clamp
  20. * @param {Number} min The lower boundary
  21. * @param {Number} max The upper boundary
  22. * @return {Number} A number in the range (min, max)
  23. */
  24. Number.prototype.clamp = function(min, max) {
  25. return Math.min(Math.max(this, min), max);
  26. };
  27.  
  28. /**
  29. * Returns a modulo value which is always positive.
  30. *
  31. * @method Number.prototype.mod
  32. * @param {Number} n The divisor
  33. * @return {Number} A modulo value
  34. */
  35. Number.prototype.mod = function(n) {
  36. return ((this % n) + n) % n;
  37. };
  38.  
  39. /**
  40. * Replaces %1, %2 and so on in the string to the arguments.
  41. *
  42. * @method String.prototype.format
  43. * @param {Any} ...args The objects to format
  44. * @return {String} A formatted string
  45. */
  46. String.prototype.format = function() {
  47. var args = arguments;
  48. return this.replace(/%([0-9]+)/g, function(s, n) {
  49. return args[Number(n) - 1];
  50. });
  51. };
  52.  
  53. /**
  54. * Makes a number string with leading zeros.
  55. *
  56. * @method String.prototype.padZero
  57. * @param {Number} length The length of the output string
  58. * @return {String} A string with leading zeros
  59. */
  60. String.prototype.padZero = function(length){
  61. var s = this;
  62. while (s.length < length) {
  63. s = '0' + s;
  64. }
  65. return s;
  66. };
  67.  
  68. /**
  69. * Makes a number string with leading zeros.
  70. *
  71. * @method Number.prototype.padZero
  72. * @param {Number} length The length of the output string
  73. * @return {String} A string with leading zeros
  74. */
  75. Number.prototype.padZero = function(length){
  76. return String(this).padZero(length);
  77. };
  78.  
  79. /**
  80. * Checks whether the two arrays are same.
  81. *
  82. * @method Array.prototype.equals
  83. * @param {Array} array The array to compare to
  84. * @return {Boolean} True if the two arrays are same
  85. */
  86. Array.prototype.equals = function(array) {
  87. if (!array || this.length !== array.length) {
  88. return false;
  89. }
  90. for (var i = 0; i < this.length; i++) {
  91. if (this[i] instanceof Array && array[i] instanceof Array) {
  92. if (!this[i].equals(array[i])) {
  93. return false;
  94. }
  95. } else if (this[i] !== array[i]) {
  96. return false;
  97. }
  98. }
  99. return true;
  100. };
  101.  
  102. /**
  103. * Makes a shallow copy of the array.
  104. *
  105. * @method Array.prototype.clone
  106. * @return {Array} A shallow copy of the array
  107. */
  108. Array.prototype.clone = function() {
  109. return this.slice(0);
  110. };
  111.  
  112. /**
  113. * Checks whether the array contains a given element.
  114. *
  115. * @method Array.prototype.contains
  116. * @param {Any} element The element to search for
  117. * @return {Boolean} True if the array contains a given element
  118. */
  119. Array.prototype.contains = function(element) {
  120. return this.indexOf(element) >= 0;
  121. };
  122.  
  123. /**
  124. * Checks whether the string contains a given string.
  125. *
  126. * @method String.prototype.contains
  127. * @param {String} string The string to search for
  128. * @return {Boolean} True if the string contains a given string
  129. */
  130. String.prototype.contains = function(string) {
  131. return this.indexOf(string) >= 0;
  132. };
  133.  
  134. /**
  135. * Generates a random integer in the range (0, max-1).
  136. *
  137. * @static
  138. * @method Math.randomInt
  139. * @param {Number} max The upper boundary (excluded)
  140. * @return {Number} A random integer
  141. */
  142. Math.randomInt = function(max) {
  143. return Math.floor(max * Math.random());
  144. };
  145.  
  146. //-----------------------------------------------------------------------------
  147. /**
  148. * The static class that defines utility methods.
  149. *
  150. * @class Utils
  151. */
  152. function Utils() {
  153. throw new Error('This is a static class');
  154. }
  155.  
  156. /**
  157. * The name of the RPG Maker. 'MV' in the current version.
  158. *
  159. * @static
  160. * @property RPGMAKER_NAME
  161. * @type String
  162. * @final
  163. */
  164. Utils.RPGMAKER_NAME = 'MV';
  165.  
  166. /**
  167. * The version of the RPG Maker.
  168. *
  169. * @static
  170. * @property RPGMAKER_VERSION
  171. * @type String
  172. * @final
  173. */
  174. Utils.RPGMAKER_VERSION = "1.2.0";
  175.  
  176. /**
  177. * Checks whether the option is in the query string.
  178. *
  179. * @static
  180. * @method isOptionValid
  181. * @param {String} name The option name
  182. * @return {Boolean} True if the option is in the query string
  183. */
  184. Utils.isOptionValid = function(name) {
  185. return location.search.slice(1).split('&').contains(name);
  186. };
  187.  
  188. /**
  189. * Checks whether the platform is NW.js.
  190. *
  191. * @static
  192. * @method isNwjs
  193. * @return {Boolean} True if the platform is NW.js
  194. */
  195. Utils.isNwjs = function() {
  196. return typeof require === 'function' && typeof process === 'object';
  197. };
  198.  
  199. /**
  200. * Checks whether the platform is a mobile device.
  201. *
  202. * @static
  203. * @method isMobileDevice
  204. * @return {Boolean} True if the platform is a mobile device
  205. */
  206. Utils.isMobileDevice = function() {
  207. var r = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
  208. return !!navigator.userAgent.match(r);
  209. };
  210.  
  211. /**
  212. * Checks whether the browser is Mobile Safari.
  213. *
  214. * @static
  215. * @method isMobileSafari
  216. * @return {Boolean} True if the browser is Mobile Safari
  217. */
  218. Utils.isMobileSafari = function() {
  219. var agent = navigator.userAgent;
  220. return !!(agent.match(/iPhone|iPad|iPod/) && agent.match(/AppleWebKit/) &&
  221. !agent.match('CriOS'));
  222. };
  223.  
  224. /**
  225. * Checks whether the browser is Android Chrome.
  226. *
  227. * @static
  228. * @method isAndroidChrome
  229. * @return {Boolean} True if the browser is Android Chrome
  230. */
  231. Utils.isAndroidChrome = function() {
  232. var agent = navigator.userAgent;
  233. return !!(agent.match(/Android/) && agent.match(/Chrome/));
  234. };
  235.  
  236. /**
  237. * Checks whether the browser can read files in the game folder.
  238. *
  239. * @static
  240. * @method canReadGameFiles
  241. * @return {Boolean} True if the browser can read files in the game folder
  242. */
  243. Utils.canReadGameFiles = function() {
  244. var scripts = document.getElementsByTagName('script');
  245. var lastScript = scripts[scripts.length - 1];
  246. var xhr = new XMLHttpRequest();
  247. try {
  248. xhr.open('GET', lastScript.src);
  249. xhr.overrideMimeType('text/javascript');
  250. xhr.send();
  251. return true;
  252. } catch (e) {
  253. return false;
  254. }
  255. };
  256.  
  257. /**
  258. * Makes a CSS color string from RGB values.
  259. *
  260. * @static
  261. * @method rgbToCssColor
  262. * @param {Number} r The red value in the range (0, 255)
  263. * @param {Number} g The green value in the range (0, 255)
  264. * @param {Number} b The blue value in the range (0, 255)
  265. * @return {String} CSS color string
  266. */
  267. Utils.rgbToCssColor = function(r, g, b) {
  268. r = Math.round(r);
  269. g = Math.round(g);
  270. b = Math.round(b);
  271. return 'rgb(' + r + ',' + g + ',' + b + ')';
  272. };
  273.  
  274. //-----------------------------------------------------------------------------
  275. /**
  276. * The point class.
  277. *
  278. * @class Point
  279. * @constructor
  280. * @param {Number} x The x coordinate
  281. * @param {Number} y The y coordinate
  282. */
  283. function Point() {
  284. this.initialize.apply(this, arguments);
  285. }
  286.  
  287. Point.prototype = Object.create(PIXI.Point.prototype);
  288. Point.prototype.constructor = Point;
  289.  
  290. Point.prototype.initialize = function(x, y) {
  291. PIXI.Point.call(this, x, y);
  292. };
  293.  
  294. /**
  295. * The x coordinate.
  296. *
  297. * @property x
  298. * @type Number
  299. */
  300.  
  301. /**
  302. * The y coordinate.
  303. *
  304. * @property y
  305. * @type Number
  306. */
  307.  
  308. //-----------------------------------------------------------------------------
  309. /**
  310. * The rectangle class.
  311. *
  312. * @class Rectangle
  313. * @constructor
  314. * @param {Number} x The x coordinate for the upper-left corner
  315. * @param {Number} y The y coordinate for the upper-left corner
  316. * @param {Number} width The width of the rectangle
  317. * @param {Number} height The height of the rectangle
  318. */
  319. function Rectangle() {
  320. this.initialize.apply(this, arguments);
  321. }
  322.  
  323. Rectangle.prototype = Object.create(PIXI.Rectangle.prototype);
  324. Rectangle.prototype.constructor = Rectangle;
  325.  
  326. Rectangle.prototype.initialize = function(x, y, width, height) {
  327. PIXI.Rectangle.call(this, x, y, width, height);
  328. };
  329.  
  330. /**
  331. * @static
  332. * @property emptyRectangle
  333. * @type Rectangle
  334. * @private
  335. */
  336. Rectangle.emptyRectangle = new Rectangle(0, 0, 0, 0);
  337.  
  338. /**
  339. * The x coordinate for the upper-left corner.
  340. *
  341. * @property x
  342. * @type Number
  343. */
  344.  
  345. /**
  346. * The y coordinate for the upper-left corner.
  347. *
  348. * @property y
  349. * @type Number
  350. */
  351.  
  352. /**
  353. * The width of the rectangle.
  354. *
  355. * @property width
  356. * @type Number
  357. */
  358.  
  359. /**
  360. * The height of the rectangle.
  361. *
  362. * @property height
  363. * @type Number
  364. */
  365.  
  366. //-----------------------------------------------------------------------------
  367. /**
  368. * The basic object that represents an image.
  369. *
  370. * @class Bitmap
  371. * @constructor
  372. * @param {Number} width The width of the bitmap
  373. * @param {Number} height The height of the bitmap
  374. */
  375. function Bitmap() {
  376. this.initialize.apply(this, arguments);
  377. }
  378.  
  379. Bitmap.prototype.initialize = function(width, height) {
  380. this._canvas = document.createElement('canvas');
  381. this._context = this._canvas.getContext('2d');
  382. this._canvas.width = Math.max(width || 0, 1);
  383. this._canvas.height = Math.max(height || 0, 1);
  384. this._baseTexture = new PIXI.BaseTexture(this._canvas);
  385. this._baseTexture.scaleMode = PIXI.scaleModes.NEAREST;
  386. this._image = null;
  387. this._url = '';
  388. this._paintOpacity = 255;
  389. this._smooth = false;
  390. this._loadListeners = [];
  391. this._isLoading = false;
  392. this._hasError = false;
  393.  
  394. /**
  395. * The face name of the font.
  396. *
  397. * @property fontFace
  398. * @type String
  399. */
  400. this.fontFace = 'GameFont';
  401.  
  402. /**
  403. * The size of the font in pixels.
  404. *
  405. * @property fontSize
  406. * @type Number
  407. */
  408. this.fontSize = 28;
  409.  
  410. /**
  411. * Whether the font is italic.
  412. *
  413. * @property fontItalic
  414. * @type Boolean
  415. */
  416. this.fontItalic = false;
  417.  
  418. /**
  419. * The color of the text in CSS format.
  420. *
  421. * @property textColor
  422. * @type String
  423. */
  424. this.textColor = '#ffffff';
  425.  
  426. /**
  427. * The color of the outline of the text in CSS format.
  428. *
  429. * @property outlineColor
  430. * @type String
  431. */
  432. this.outlineColor = 'rgba(0, 0, 0, 0.5)';
  433.  
  434. /**
  435. * The width of the outline of the text.
  436. *
  437. * @property outlineWidth
  438. * @type Number
  439. */
  440. this.outlineWidth = 4;
  441. };
  442.  
  443. /**
  444. * Loads a image file and returns a new bitmap object.
  445. *
  446. * @static
  447. * @method load
  448. * @param {String} url The image url of the texture
  449. * @return Bitmap
  450. */
  451. Bitmap.load = function(url) {
  452. var bitmap = new Bitmap();
  453. bitmap._image = new Image();
  454. bitmap._image.src = url;
  455. bitmap._image.onload = Bitmap.prototype._onLoad.bind(bitmap);
  456. bitmap._image.onerror = Bitmap.prototype._onError.bind(bitmap);
  457. bitmap._url = url;
  458. bitmap._isLoading = true;
  459. return bitmap;
  460. };
  461.  
  462. /**
  463. * Takes a snapshot of the game screen and returns a new bitmap object.
  464. *
  465. * @static
  466. * @method snap
  467. * @param {Stage} stage The stage object
  468. * @return Bitmap
  469. */
  470. Bitmap.snap = function(stage) {
  471. var width = Graphics.width;
  472. var height = Graphics.height;
  473. var bitmap = new Bitmap(width, height);
  474. var context = bitmap._context;
  475. var renderTexture = new PIXI.RenderTexture(width, height);
  476. if (stage) {
  477. renderTexture.render(stage);
  478. stage.worldTransform.identity();
  479. }
  480. if (Graphics.isWebGL()) {
  481. var gl = renderTexture.renderer.gl;
  482. var webGLPixels = new Uint8Array(4 * width * height);
  483. gl.bindFramebuffer(gl.FRAMEBUFFER, renderTexture.textureBuffer.frameBuffer);
  484. gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, webGLPixels);
  485. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  486. var canvasData = context.getImageData(0, 0, width, height);
  487. canvasData.data.set(webGLPixels);
  488. context.putImageData(canvasData, 0, 0);
  489. } else {
  490. context.drawImage(renderTexture.textureBuffer.canvas, 0, 0);
  491. }
  492. bitmap._setDirty();
  493. return bitmap;
  494. };
  495.  
  496. /**
  497. * Checks whether the bitmap is ready to render.
  498. *
  499. * @method isReady
  500. * @return {Boolean} True if the bitmap is ready to render
  501. */
  502. Bitmap.prototype.isReady = function() {
  503. return !this._isLoading;
  504. };
  505.  
  506. /**
  507. * Checks whether a loading error has occurred.
  508. *
  509. * @method isError
  510. * @return {Boolean} True if a loading error has occurred
  511. */
  512. Bitmap.prototype.isError = function() {
  513. return this._hasError;
  514. };
  515.  
  516. /**
  517. * [read-only] The url of the image file.
  518. *
  519. * @property url
  520. * @type String
  521. */
  522. Object.defineProperty(Bitmap.prototype, 'url', {
  523. get: function() {
  524. return this._url;
  525. },
  526. configurable: true
  527. });
  528.  
  529. /**
  530. * [read-only] The base texture that holds the image.
  531. *
  532. * @property baseTexture
  533. * @type PIXI.BaseTexture
  534. */
  535. Object.defineProperty(Bitmap.prototype, 'baseTexture', {
  536. get: function() {
  537. return this._baseTexture;
  538. },
  539. configurable: true
  540. });
  541.  
  542. /**
  543. * [read-only] The bitmap canvas.
  544. *
  545. * @property canvas
  546. * @type HTMLCanvasElement
  547. */
  548. Object.defineProperty(Bitmap.prototype, 'canvas', {
  549. get: function() {
  550. return this._canvas;
  551. },
  552. configurable: true
  553. });
  554.  
  555. /**
  556. * [read-only] The 2d context of the bitmap canvas.
  557. *
  558. * @property context
  559. * @type CanvasRenderingContext2D
  560. */
  561. Object.defineProperty(Bitmap.prototype, 'context', {
  562. get: function() {
  563. return this._context;
  564. },
  565. configurable: true
  566. });
  567.  
  568. /**
  569. * [read-only] The width of the bitmap.
  570. *
  571. * @property width
  572. * @type Number
  573. */
  574. Object.defineProperty(Bitmap.prototype, 'width', {
  575. get: function() {
  576. return this._isLoading ? 0 : this._canvas.width;
  577. },
  578. configurable: true
  579. });
  580.  
  581. /**
  582. * [read-only] The height of the bitmap.
  583. *
  584. * @property height
  585. * @type Number
  586. */
  587. Object.defineProperty(Bitmap.prototype, 'height', {
  588. get: function() {
  589. return this._isLoading ? 0 : this._canvas.height;
  590. },
  591. configurable: true
  592. });
  593.  
  594. /**
  595. * [read-only] The rectangle of the bitmap.
  596. *
  597. * @property rect
  598. * @type Rectangle
  599. */
  600. Object.defineProperty(Bitmap.prototype, 'rect', {
  601. get: function() {
  602. return new Rectangle(0, 0, this.width, this.height);
  603. },
  604. configurable: true
  605. });
  606.  
  607. /**
  608. * Whether the smooth scaling is applied.
  609. *
  610. * @property smooth
  611. * @type Boolean
  612. */
  613. Object.defineProperty(Bitmap.prototype, 'smooth', {
  614. get: function() {
  615. return this._smooth;
  616. },
  617. set: function(value) {
  618. if (this._smooth !== value) {
  619. this._smooth = value;
  620. if (this._smooth) {
  621. this._baseTexture.scaleMode = PIXI.scaleModes.LINEAR;
  622. } else {
  623. this._baseTexture.scaleMode = PIXI.scaleModes.NEAREST;
  624. }
  625. }
  626. },
  627. configurable: true
  628. });
  629.  
  630. /**
  631. * The opacity of the drawing object in the range (0, 255).
  632. *
  633. * @property paintOpacity
  634. * @type Number
  635. */
  636. Object.defineProperty(Bitmap.prototype, 'paintOpacity', {
  637. get: function() {
  638. return this._paintOpacity;
  639. },
  640. set: function(value) {
  641. if (this._paintOpacity !== value) {
  642. this._paintOpacity = value;
  643. this._context.globalAlpha = this._paintOpacity / 255;
  644. }
  645. },
  646. configurable: true
  647. });
  648.  
  649. /**
  650. * Resizes the bitmap.
  651. *
  652. * @method resize
  653. * @param {Number} width The new width of the bitmap
  654. * @param {Number} height The new height of the bitmap
  655. */
  656. Bitmap.prototype.resize = function(width, height) {
  657. width = Math.max(width || 0, 1);
  658. height = Math.max(height || 0, 1);
  659. this._canvas.width = width;
  660. this._canvas.height = height;
  661. this._baseTexture.width = width;
  662. this._baseTexture.height = height;
  663. };
  664.  
  665. /**
  666. * Performs a block transfer.
  667. *
  668. * @method blt
  669. * @param {Bitmap} source The bitmap to draw
  670. * @param {Number} sx The x coordinate in the source
  671. * @param {Number} sy The y coordinate in the source
  672. * @param {Number} sw The width of the source image
  673. * @param {Number} sh The height of the source image
  674. * @param {Number} dx The x coordinate in the destination
  675. * @param {Number} dy The y coordinate in the destination
  676. * @param {Number} [dw=sw] The width to draw the image in the destination
  677. * @param {Number} [dh=sh] The height to draw the image in the destination
  678. */
  679. Bitmap.prototype.blt = function(source, sx, sy, sw, sh, dx, dy, dw, dh) {
  680. dw = dw || sw;
  681. dh = dh || sh;
  682. if (sx >= 0 && sy >= 0 && sw > 0 && sh > 0 && dw > 0 && dh > 0 &&
  683. sx + sw <= source.width && sy + sh <= source.height) {
  684. this._context.globalCompositeOperation = 'source-over';
  685. this._context.drawImage(source._canvas, sx, sy, sw, sh, dx, dy, dw, dh);
  686. this._setDirty();
  687. }
  688. };
  689.  
  690. /**
  691. * Returns pixel color at the specified point.
  692. *
  693. * @method getPixel
  694. * @param {Number} x The x coordinate of the pixel in the bitmap
  695. * @param {Number} y The y coordinate of the pixel in the bitmap
  696. * @return {String} The pixel color (hex format)
  697. */
  698. Bitmap.prototype.getPixel = function(x, y) {
  699. var data = this._context.getImageData(x, y, 1, 1).data;
  700. var result = '#';
  701. for (var i = 0; i < 3; i++) {
  702. result += data[i].toString(16).padZero(2);
  703. }
  704. return result;
  705. };
  706.  
  707. /**
  708. * Returns alpha pixel value at the specified point.
  709. *
  710. * @method getAlphaPixel
  711. * @param {Number} x The x coordinate of the pixel in the bitmap
  712. * @param {Number} y The y coordinate of the pixel in the bitmap
  713. * @return {String} The alpha value
  714. */
  715. Bitmap.prototype.getAlphaPixel = function(x, y) {
  716. var data = this._context.getImageData(x, y, 1, 1).data;
  717. return data[3];
  718. };
  719.  
  720. /**
  721. * Clears the specified rectangle.
  722. *
  723. * @method clearRect
  724. * @param {Number} x The x coordinate for the upper-left corner
  725. * @param {Number} y The y coordinate for the upper-left corner
  726. * @param {Number} width The width of the rectangle to clear
  727. * @param {Number} height The height of the rectangle to clear
  728. */
  729. Bitmap.prototype.clearRect = function(x, y, width, height) {
  730. this._context.clearRect(x, y, width, height);
  731. this._setDirty();
  732. };
  733.  
  734. /**
  735. * Clears the entire bitmap.
  736. *
  737. * @method clear
  738. */
  739. Bitmap.prototype.clear = function() {
  740. this.clearRect(0, 0, this.width, this.height);
  741. };
  742.  
  743. /**
  744. * Fills the specified rectangle.
  745. *
  746. * @method fillRect
  747. * @param {Number} x The x coordinate for the upper-left corner
  748. * @param {Number} y The y coordinate for the upper-left corner
  749. * @param {Number} width The width of the rectangle to clear
  750. * @param {Number} height The height of the rectangle to clear
  751. * @param {String} color The color of the rectangle in CSS format
  752. */
  753. Bitmap.prototype.fillRect = function(x, y, width, height, color) {
  754. var context = this._context;
  755. context.save();
  756. context.fillStyle = color;
  757. context.fillRect(x, y, width, height);
  758. context.restore();
  759. this._setDirty();
  760. };
  761.  
  762. /**
  763. * Fills the entire bitmap.
  764. *
  765. * @method fillAll
  766. * @param {String} color The color of the rectangle in CSS format
  767. */
  768. Bitmap.prototype.fillAll = function(color) {
  769. this.fillRect(0, 0, this.width, this.height, color);
  770. };
  771.  
  772. /**
  773. * Draws the rectangle with a gradation.
  774. *
  775. * @method gradientFillRect
  776. * @param {Number} x The x coordinate for the upper-left corner
  777. * @param {Number} y The y coordinate for the upper-left corner
  778. * @param {Number} width The width of the rectangle to clear
  779. * @param {Number} height The height of the rectangle to clear
  780. * @param {String} color1 The start color of the gradation
  781. * @param {String} color2 The end color of the gradation
  782. * @param {Boolean} vertical Whether it draws a vertical gradient
  783. */
  784. Bitmap.prototype.gradientFillRect = function(x, y, width, height, color1,
  785. color2, vertical) {
  786. var context = this._context;
  787. var grad;
  788. if (vertical) {
  789. grad = context.createLinearGradient(x, y, x, y + height);
  790. } else {
  791. grad = context.createLinearGradient(x, y, x + width, y);
  792. }
  793. grad.addColorStop(0, color1);
  794. grad.addColorStop(1, color2);
  795. context.save();
  796. context.fillStyle = grad;
  797. context.fillRect(x, y, width, height);
  798. context.restore();
  799. this._setDirty();
  800. };
  801.  
  802. /**
  803. * Draw the filled circle.
  804. *
  805. * @method drawCircle
  806. * @param {Number} x The x coordinate of the center of the circle
  807. * @param {Number} y The y coordinate of the center of the circle
  808. * @param {Number} radius The radius of the circle
  809. * @param {String} color The color of the circle in CSS format
  810. */
  811. Bitmap.prototype.drawCircle = function(x, y, radius, color) {
  812. var context = this._context;
  813. context.save();
  814. context.fillStyle = color;
  815. context.beginPath();
  816. context.arc(x, y, radius, 0, Math.PI * 2, false);
  817. context.fill();
  818. context.restore();
  819. this._setDirty();
  820. };
  821.  
  822. /**
  823. * Draws the outline text to the bitmap.
  824. *
  825. * @method drawText
  826. * @param {String} text The text that will be drawn
  827. * @param {Number} x The x coordinate for the left of the text
  828. * @param {Number} y The y coordinate for the top of the text
  829. * @param {Number} maxWidth The maximum allowed width of the text
  830. * @param {Number} lineHeight The height of the text line
  831. * @param {String} align The alignment of the text
  832. */
  833. Bitmap.prototype.drawText = function(text, x, y, maxWidth, lineHeight, align) {
  834. // Note: Firefox has a bug with textBaseline: Bug 737852
  835. // So we use 'alphabetic' here.
  836. if (text !== undefined) {
  837. var tx = x;
  838. var ty = y + lineHeight - (lineHeight - this.fontSize * 0.7) / 2;
  839. var context = this._context;
  840. var alpha = context.globalAlpha;
  841. maxWidth = maxWidth || 0xffffffff;
  842. if (align === 'center') {
  843. tx += maxWidth / 2;
  844. }
  845. if (align === 'right') {
  846. tx += maxWidth;
  847. }
  848. context.save();
  849. context.font = this._makeFontNameText();
  850. context.textAlign = align;
  851. context.textBaseline = 'alphabetic';
  852. context.globalAlpha = 1;
  853. this._drawTextOutline(text, tx, ty, maxWidth);
  854. context.globalAlpha = alpha;
  855. this._drawTextBody(text, tx, ty, maxWidth);
  856. context.restore();
  857. this._setDirty();
  858. }
  859. };
  860.  
  861. /**
  862. * Returns the width of the specified text.
  863. *
  864. * @method measureTextWidth
  865. * @param {String} text The text to be measured
  866. * @return {Number} The width of the text in pixels
  867. */
  868. Bitmap.prototype.measureTextWidth = function(text) {
  869. var context = this._context;
  870. context.save();
  871. context.font = this._makeFontNameText();
  872. var width = context.measureText(text).width;
  873. context.restore();
  874. return width;
  875. };
  876.  
  877. /**
  878. * Changes the color tone of the entire bitmap.
  879. *
  880. * @method adjustTone
  881. * @param {Number} r The red strength in the range (-255, 255)
  882. * @param {Number} g The green strength in the range (-255, 255)
  883. * @param {Number} b The blue strength in the range (-255, 255)
  884. */
  885. Bitmap.prototype.adjustTone = function(r, g, b) {
  886. if ((r || g || b) && this.width > 0 && this.height > 0) {
  887. var context = this._context;
  888. var imageData = context.getImageData(0, 0, this.width, this.height);
  889. var pixels = imageData.data;
  890. for (var i = 0; i < pixels.length; i += 4) {
  891. pixels[i + 0] += r;
  892. pixels[i + 1] += g;
  893. pixels[i + 2] += b;
  894. }
  895. context.putImageData(imageData, 0, 0);
  896. this._setDirty();
  897. }
  898. };
  899.  
  900. /**
  901. * Rotates the hue of the entire bitmap.
  902. *
  903. * @method rotateHue
  904. * @param {Number} offset The hue offset in 360 degrees
  905. */
  906. Bitmap.prototype.rotateHue = function(offset) {
  907. function rgbToHsl(r, g, b) {
  908. var cmin = Math.min(r, g, b);
  909. var cmax = Math.max(r, g, b);
  910. var h = 0;
  911. var s = 0;
  912. var l = (cmin + cmax) / 2;
  913. var delta = cmax - cmin;
  914.  
  915. if (delta > 0) {
  916. if (r === cmax) {
  917. h = 60 * (((g - b) / delta + 6) % 6);
  918. } else if (g === cmax) {
  919. h = 60 * ((b - r) / delta + 2);
  920. } else {
  921. h = 60 * ((r - g) / delta + 4);
  922. }
  923. s = delta / (255 - Math.abs(2 * l - 255));
  924. }
  925. return [h, s, l];
  926. }
  927.  
  928. function hslToRgb(h, s, l) {
  929. var c = (255 - Math.abs(2 * l - 255)) * s;
  930. var x = c * (1 - Math.abs((h / 60) % 2 - 1));
  931. var m = l - c / 2;
  932. var cm = c + m;
  933. var xm = x + m;
  934.  
  935. if (h < 60) {
  936. return [cm, xm, m];
  937. } else if (h < 120) {
  938. return [xm, cm, m];
  939. } else if (h < 180) {
  940. return [m, cm, xm];
  941. } else if (h < 240) {
  942. return [m, xm, cm];
  943. } else if (h < 300) {
  944. return [xm, m, cm];
  945. } else {
  946. return [cm, m, xm];
  947. }
  948. }
  949.  
  950. if (offset && this.width > 0 && this.height > 0) {
  951. offset = ((offset % 360) + 360) % 360;
  952. var context = this._context;
  953. var imageData = context.getImageData(0, 0, this.width, this.height);
  954. var pixels = imageData.data;
  955. for (var i = 0; i < pixels.length; i += 4) {
  956. var hsl = rgbToHsl(pixels[i + 0], pixels[i + 1], pixels[i + 2]);
  957. var h = (hsl[0] + offset) % 360;
  958. var s = hsl[1];
  959. var l = hsl[2];
  960. var rgb = hslToRgb(h, s, l);
  961. pixels[i + 0] = rgb[0];
  962. pixels[i + 1] = rgb[1];
  963. pixels[i + 2] = rgb[2];
  964. }
  965. context.putImageData(imageData, 0, 0);
  966. this._setDirty();
  967. }
  968. };
  969.  
  970. /**
  971. * Applies a blur effect to the bitmap.
  972. *
  973. * @method blur
  974. */
  975. Bitmap.prototype.blur = function() {
  976. for (var i = 0; i < 2; i++) {
  977. var w = this.width;
  978. var h = this.height;
  979. var canvas = this._canvas;
  980. var context = this._context;
  981. var tempCanvas = document.createElement('canvas');
  982. var tempContext = tempCanvas.getContext('2d');
  983. tempCanvas.width = w + 2;
  984. tempCanvas.height = h + 2;
  985. tempContext.drawImage(canvas, 0, 0, w, h, 1, 1, w, h);
  986. tempContext.drawImage(canvas, 0, 0, w, 1, 1, 0, w, 1);
  987. tempContext.drawImage(canvas, 0, 0, 1, h, 0, 1, 1, h);
  988. tempContext.drawImage(canvas, 0, h - 1, w, 1, 1, h + 1, w, 1);
  989. tempContext.drawImage(canvas, w - 1, 0, 1, h, w + 1, 1, 1, h);
  990. context.save();
  991. context.fillStyle = 'black';
  992. context.fillRect(0, 0, w, h);
  993. context.globalCompositeOperation = 'lighter';
  994. context.globalAlpha = 1 / 9;
  995. for (var y = 0; y < 3; y++) {
  996. for (var x = 0; x < 3; x++) {
  997. context.drawImage(tempCanvas, x, y, w, h, 0, 0, w, h);
  998. }
  999. }
  1000. context.restore();
  1001. }
  1002. this._setDirty();
  1003. };
  1004.  
  1005. /**
  1006. * Add a callback function that will be called when the bitmap is loaded.
  1007. *
  1008. * @method addLoadListener
  1009. * @param {Function} listner The callback function
  1010. */
  1011. Bitmap.prototype.addLoadListener = function(listner) {
  1012. if (this._isLoading) {
  1013. this._loadListeners.push(listner);
  1014. } else {
  1015. listner();
  1016. }
  1017. };
  1018.  
  1019. /**
  1020. * @method _makeFontNameText
  1021. * @private
  1022. */
  1023. Bitmap.prototype._makeFontNameText = function() {
  1024. return (this.fontItalic ? 'Italic ' : '') +
  1025. this.fontSize + 'px ' + this.fontFace;
  1026. };
  1027.  
  1028. /**
  1029. * @method _drawTextOutline
  1030. * @param {String} text
  1031. * @param {Number} tx
  1032. * @param {Number} ty
  1033. * @param {Number} maxWidth
  1034. * @private
  1035. */
  1036. Bitmap.prototype._drawTextOutline = function(text, tx, ty, maxWidth) {
  1037. var context = this._context;
  1038. context.strokeStyle = this.outlineColor;
  1039. context.lineWidth = this.outlineWidth;
  1040. context.lineJoin = 'round';
  1041. context.strokeText(text, tx, ty, maxWidth);
  1042. };
  1043.  
  1044. /**
  1045. * @method _drawTextBody
  1046. * @param {String} text
  1047. * @param {Number} tx
  1048. * @param {Number} ty
  1049. * @param {Number} maxWidth
  1050. * @private
  1051. */
  1052. Bitmap.prototype._drawTextBody = function(text, tx, ty, maxWidth) {
  1053. var context = this._context;
  1054. context.fillStyle = this.textColor;
  1055. context.fillText(text, tx, ty, maxWidth);
  1056. };
  1057.  
  1058. /**
  1059. * @method _onLoad
  1060. * @private
  1061. */
  1062. Bitmap.prototype._onLoad = function() {
  1063. this._isLoading = false;
  1064. this.resize(this._image.width, this._image.height);
  1065. this._context.drawImage(this._image, 0, 0);
  1066. this._setDirty();
  1067. this._callLoadListeners();
  1068. };
  1069.  
  1070. /**
  1071. * @method _callLoadListeners
  1072. * @private
  1073. */
  1074. Bitmap.prototype._callLoadListeners = function() {
  1075. while (this._loadListeners.length > 0) {
  1076. var listener = this._loadListeners.shift();
  1077. listener();
  1078. }
  1079. };
  1080.  
  1081. /**
  1082. * @method _onError
  1083. * @private
  1084. */
  1085. Bitmap.prototype._onError = function() {
  1086. this._hasError = true;
  1087. };
  1088.  
  1089. /**
  1090. * @method _setDirty
  1091. * @private
  1092. */
  1093. Bitmap.prototype._setDirty = function() {
  1094. this._baseTexture.dirty();
  1095. };
  1096.  
  1097. //-----------------------------------------------------------------------------
  1098. /**
  1099. * The static class that carries out graphics processing.
  1100. *
  1101. * @class Graphics
  1102. */
  1103. function Graphics() {
  1104. throw new Error('This is a static class');
  1105. }
  1106.  
  1107. /**
  1108. * Initializes the graphics system.
  1109. *
  1110. * @static
  1111. * @method initialize
  1112. * @param {Number} width The width of the game screen
  1113. * @param {Number} height The height of the game screen
  1114. * @param {String} type The type of the renderer.
  1115. * 'canvas', 'webgl', or 'auto'.
  1116. */
  1117. Graphics.initialize = function(width, height, type) {
  1118. this._width = width || 800;
  1119. this._height = height || 600;
  1120. this._rendererType = type || 'auto';
  1121. this._boxWidth = this._width;
  1122. this._boxHeight = this._height;
  1123.  
  1124. this._scale = 1;
  1125. this._realScale = 1;
  1126.  
  1127. this._errorPrinter = null;
  1128. this._canvas = null;
  1129. this._video = null;
  1130. this._upperCanvas = null;
  1131. this._renderer = null;
  1132. this._fpsMeter = null;
  1133. this._modeBox = null;
  1134. this._skipCount = 0;
  1135. this._maxSkip = 3;
  1136. this._rendered = false;
  1137. this._loadingImage = null;
  1138. this._loadingCount = 0;
  1139. this._fpsMeterToggled = false;
  1140. this._stretchEnabled = this._defaultStretchMode();
  1141.  
  1142. this._canUseDifferenceBlend = false;
  1143. this._canUseSaturationBlend = false;
  1144. this._hiddenCanvas = null;
  1145.  
  1146. this._testCanvasBlendModes();
  1147. this._modifyExistingElements();
  1148. this._updateRealScale();
  1149. this._createAllElements();
  1150. this._disableTextSelection();
  1151. this._disableContextMenu();
  1152. this._setupEventHandlers();
  1153. };
  1154.  
  1155. /**
  1156. * The total frame count of the game screen.
  1157. *
  1158. * @static
  1159. * @property frameCount
  1160. * @type Number
  1161. */
  1162. Graphics.frameCount = 0;
  1163.  
  1164. /**
  1165. * The alias of PIXI.blendModes.NORMAL.
  1166. *
  1167. * @static
  1168. * @property BLEND_NORMAL
  1169. * @type Number
  1170. * @final
  1171. */
  1172. Graphics.BLEND_NORMAL = 0;
  1173.  
  1174. /**
  1175. * The alias of PIXI.blendModes.ADD.
  1176. *
  1177. * @static
  1178. * @property BLEND_ADD
  1179. * @type Number
  1180. * @final
  1181. */
  1182. Graphics.BLEND_ADD = 1;
  1183.  
  1184. /**
  1185. * The alias of PIXI.blendModes.MULTIPLY.
  1186. *
  1187. * @static
  1188. * @property BLEND_MULTIPLY
  1189. * @type Number
  1190. * @final
  1191. */
  1192. Graphics.BLEND_MULTIPLY = 2;
  1193.  
  1194. /**
  1195. * The alias of PIXI.blendModes.SCREEN.
  1196. *
  1197. * @static
  1198. * @property BLEND_SCREEN
  1199. * @type Number
  1200. * @final
  1201. */
  1202. Graphics.BLEND_SCREEN = 3;
  1203.  
  1204. /**
  1205. * Marks the beginning of each frame for FPSMeter.
  1206. *
  1207. * @static
  1208. * @method tickStart
  1209. */
  1210. Graphics.tickStart = function() {
  1211. if (this._fpsMeter) {
  1212. this._fpsMeter.tickStart();
  1213. }
  1214. };
  1215.  
  1216. /**
  1217. * Marks the end of each frame for FPSMeter.
  1218. *
  1219. * @static
  1220. * @method tickEnd
  1221. */
  1222. Graphics.tickEnd = function() {
  1223. if (this._fpsMeter && this._rendered) {
  1224. this._fpsMeter.tick();
  1225. }
  1226. };
  1227.  
  1228. /**
  1229. * Renders the stage to the game screen.
  1230. *
  1231. * @static
  1232. * @method render
  1233. * @param {Stage} stage The stage object to be rendered
  1234. */
  1235. Graphics.render = function(stage) {
  1236. if (this._skipCount === 0) {
  1237. var startTime = Date.now();
  1238. if (stage) {
  1239. this._renderer.render(stage);
  1240. }
  1241. var endTime = Date.now();
  1242. var elapsed = endTime - startTime;
  1243. this._skipCount = Math.min(Math.floor(elapsed / 15), this._maxSkip);
  1244. this._rendered = true;
  1245. } else {
  1246. this._skipCount--;
  1247. this._rendered = false;
  1248. }
  1249. this.frameCount++;
  1250. };
  1251.  
  1252. /**
  1253. * Checks whether the renderer type is WebGL.
  1254. *
  1255. * @static
  1256. * @method isWebGL
  1257. * @return {Boolean} True if the renderer type is WebGL
  1258. */
  1259. Graphics.isWebGL = function() {
  1260. return this._renderer && this._renderer.type === PIXI.WEBGL_RENDERER;
  1261. };
  1262.  
  1263. /**
  1264. * Checks whether the current browser supports WebGL.
  1265. *
  1266. * @static
  1267. * @method hasWebGL
  1268. * @return {Boolean} True if the current browser supports WebGL.
  1269. */
  1270. Graphics.hasWebGL = function() {
  1271. try {
  1272. var canvas = document.createElement('canvas');
  1273. return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
  1274. } catch (e) {
  1275. return false;
  1276. }
  1277. };
  1278.  
  1279. /**
  1280. * Checks whether the canvas blend mode 'difference' is supported.
  1281. *
  1282. * @static
  1283. * @method canUseDifferenceBlend
  1284. * @return {Boolean} True if the canvas blend mode 'difference' is supported
  1285. */
  1286. Graphics.canUseDifferenceBlend = function() {
  1287. return this._canUseDifferenceBlend;
  1288. };
  1289.  
  1290. /**
  1291. * Checks whether the canvas blend mode 'saturation' is supported.
  1292. *
  1293. * @static
  1294. * @method canUseSaturationBlend
  1295. * @return {Boolean} True if the canvas blend mode 'saturation' is supported
  1296. */
  1297. Graphics.canUseSaturationBlend = function() {
  1298. return this._canUseSaturationBlend;
  1299. };
  1300.  
  1301. /**
  1302. * Sets the source of the "Now Loading" image.
  1303. *
  1304. * @static
  1305. * @method setLoadingImage
  1306. */
  1307. Graphics.setLoadingImage = function(src) {
  1308. this._loadingImage = new Image();
  1309. this._loadingImage.src = src;
  1310. };
  1311.  
  1312. /**
  1313. * Initializes the counter for displaying the "Now Loading" image.
  1314. *
  1315. * @static
  1316. * @method startLoading
  1317. */
  1318. Graphics.startLoading = function() {
  1319. this._loadingCount = 0;
  1320. };
  1321.  
  1322. /**
  1323. * Increments the loading counter and displays the "Now Loading" image if necessary.
  1324. *
  1325. * @static
  1326. * @method updateLoading
  1327. */
  1328. Graphics.updateLoading = function() {
  1329. this._loadingCount++;
  1330. this._paintUpperCanvas();
  1331. this._upperCanvas.style.opacity = 1;
  1332. };
  1333.  
  1334. /**
  1335. * Erases the "Now Loading" image.
  1336. *
  1337. * @static
  1338. * @method endLoading
  1339. */
  1340. Graphics.endLoading = function() {
  1341. this._clearUpperCanvas();
  1342. this._upperCanvas.style.opacity = 0;
  1343. };
  1344.  
  1345. /**
  1346. * Displays the error text to the screen.
  1347. *
  1348. * @static
  1349. * @method printError
  1350. * @param {String} name The name of the error
  1351. * @param {String} message The message of the error
  1352. */
  1353. Graphics.printError = function(name, message) {
  1354. if (this._errorPrinter) {
  1355. this._errorPrinter.innerHTML = this._makeErrorHtml(name, message);
  1356. }
  1357. this._applyCanvasFilter();
  1358. this._clearUpperCanvas();
  1359. };
  1360.  
  1361. /**
  1362. * Shows the FPSMeter element.
  1363. *
  1364. * @static
  1365. * @method showFps
  1366. */
  1367. Graphics.showFps = function() {
  1368. if (this._fpsMeter) {
  1369. this._fpsMeter.show();
  1370. this._modeBox.style.opacity = 1;
  1371. }
  1372. };
  1373.  
  1374. /**
  1375. * Hides the FPSMeter element.
  1376. *
  1377. * @static
  1378. * @method hideFps
  1379. */
  1380. Graphics.hideFps = function() {
  1381. if (this._fpsMeter) {
  1382. this._fpsMeter.hide();
  1383. this._modeBox.style.opacity = 0;
  1384. }
  1385. };
  1386.  
  1387. /**
  1388. * Loads a font file.
  1389. *
  1390. * @static
  1391. * @method loadFont
  1392. * @param {String} name The face name of the font
  1393. * @param {String} url The url of the font file
  1394. */
  1395. Graphics.loadFont = function(name, url) {
  1396. var style = document.createElement('style');
  1397. var head = document.getElementsByTagName('head');
  1398. var rule = '@font-face { font-family: "' + name + '"; src: url("' + url + '"); }';
  1399. style.type = 'text/css';
  1400. head.item(0).appendChild(style);
  1401. style.sheet.insertRule(rule, 0);
  1402. this._createFontLoader(name);
  1403. };
  1404.  
  1405. /**
  1406. * Checks whether the font file is loaded.
  1407. *
  1408. * @static
  1409. * @method isFontLoaded
  1410. * @param {String} name The face name of the font
  1411. * @return {Boolean} True if the font file is loaded
  1412. */
  1413. Graphics.isFontLoaded = function(name) {
  1414. if (!this._hiddenCanvas) {
  1415. this._hiddenCanvas = document.createElement('canvas');
  1416. }
  1417. var context = this._hiddenCanvas.getContext('2d');
  1418. var text = 'abcdefghijklmnopqrstuvwxyz';
  1419. var width1, width2;
  1420. context.font = '40px ' + name + ', sans-serif';
  1421. width1 = context.measureText(text).width;
  1422. context.font = '40px sans-serif';
  1423. width2 = context.measureText(text).width;
  1424. return width1 !== width2;
  1425. };
  1426.  
  1427. /**
  1428. * Starts playback of a video.
  1429. *
  1430. * @static
  1431. * @method playVideo
  1432. * @param {String} src
  1433. */
  1434. Graphics.playVideo = function(src) {
  1435. this._video.src = src;
  1436. this._video.onloadeddata = this._onVideoLoad.bind(this);
  1437. this._video.onerror = this._onVideoError.bind(this);
  1438. this._video.onended = this._onVideoEnd.bind(this);
  1439. this._video.load();
  1440. };
  1441.  
  1442. /**
  1443. * Checks whether the video is playing.
  1444. *
  1445. * @static
  1446. * @method isVideoPlaying
  1447. * @return {Boolean} True if the video is playing
  1448. */
  1449. Graphics.isVideoPlaying = function() {
  1450. return this._video && this._isVideoVisible();
  1451. };
  1452.  
  1453. /**
  1454. * Checks whether the browser can play the specified video type.
  1455. *
  1456. * @static
  1457. * @method canPlayVideoType
  1458. * @param {String} type The video type to test support for
  1459. * @return {Boolean} True if the browser can play the specified video type
  1460. */
  1461. Graphics.canPlayVideoType = function(type) {
  1462. return this._video && this._video.canPlayType(type);
  1463. };
  1464.  
  1465. /**
  1466. * Converts an x coordinate on the page to the corresponding
  1467. * x coordinate on the canvas area.
  1468. *
  1469. * @static
  1470. * @method pageToCanvasX
  1471. * @param {Number} x The x coordinate on the page to be converted
  1472. * @return {Number} The x coordinate on the canvas area
  1473. */
  1474. Graphics.pageToCanvasX = function(x) {
  1475. if (this._canvas) {
  1476. var left = this._canvas.offsetLeft;
  1477. return Math.round((x - left) / this._realScale);
  1478. } else {
  1479. return 0;
  1480. }
  1481. };
  1482.  
  1483. /**
  1484. * Converts a y coordinate on the page to the corresponding
  1485. * y coordinate on the canvas area.
  1486. *
  1487. * @static
  1488. * @method pageToCanvasY
  1489. * @param {Number} y The y coordinate on the page to be converted
  1490. * @return {Number} The y coordinate on the canvas area
  1491. */
  1492. Graphics.pageToCanvasY = function(y) {
  1493. if (this._canvas) {
  1494. var top = this._canvas.offsetTop;
  1495. return Math.round((y - top) / this._realScale);
  1496. } else {
  1497. return 0;
  1498. }
  1499. };
  1500.  
  1501. /**
  1502. * Checks whether the specified point is inside the game canvas area.
  1503. *
  1504. * @static
  1505. * @method isInsideCanvas
  1506. * @param {Number} x The x coordinate on the canvas area
  1507. * @param {Number} y The y coordinate on the canvas area
  1508. * @return {Boolean} True if the specified point is inside the game canvas area
  1509. */
  1510. Graphics.isInsideCanvas = function(x, y) {
  1511. return (x >= 0 && x < this._width && y >= 0 && y < this._height);
  1512. };
  1513.  
  1514. /**
  1515. * The width of the game screen.
  1516. *
  1517. * @static
  1518. * @property width
  1519. * @type Number
  1520. */
  1521. Object.defineProperty(Graphics, 'width', {
  1522. get: function() {
  1523. return this._width;
  1524. },
  1525. set: function(value) {
  1526. if (this._width !== value) {
  1527. this._width = value;
  1528. this._updateAllElements();
  1529. }
  1530. },
  1531. configurable: true
  1532. });
  1533.  
  1534. /**
  1535. * The height of the game screen.
  1536. *
  1537. * @static
  1538. * @property height
  1539. * @type Number
  1540. */
  1541. Object.defineProperty(Graphics, 'height', {
  1542. get: function() {
  1543. return this._height;
  1544. },
  1545. set: function(value) {
  1546. if (this._height !== value) {
  1547. this._height = value;
  1548. this._updateAllElements();
  1549. }
  1550. },
  1551. configurable: true
  1552. });
  1553.  
  1554. /**
  1555. * The width of the window display area.
  1556. *
  1557. * @static
  1558. * @property boxWidth
  1559. * @type Number
  1560. */
  1561. Object.defineProperty(Graphics, 'boxWidth', {
  1562. get: function() {
  1563. return this._boxWidth;
  1564. },
  1565. set: function(value) {
  1566. this._boxWidth = value;
  1567. },
  1568. configurable: true
  1569. });
  1570.  
  1571. /**
  1572. * The height of the window display area.
  1573. *
  1574. * @static
  1575. * @property boxHeight
  1576. * @type Number
  1577. */
  1578. Object.defineProperty(Graphics, 'boxHeight', {
  1579. get: function() {
  1580. return this._boxHeight;
  1581. },
  1582. set: function(value) {
  1583. this._boxHeight = value;
  1584. },
  1585. configurable: true
  1586. });
  1587.  
  1588. /**
  1589. * The zoom scale of the game screen.
  1590. *
  1591. * @static
  1592. * @property scale
  1593. * @type Number
  1594. */
  1595. Object.defineProperty(Graphics, 'scale', {
  1596. get: function() {
  1597. return this._scale;
  1598. },
  1599. set: function(value) {
  1600. if (this._scale !== value) {
  1601. this._scale = value;
  1602. this._updateAllElements();
  1603. }
  1604. },
  1605. configurable: true
  1606. });
  1607.  
  1608. /**
  1609. * @static
  1610. * @method _createAllElements
  1611. * @private
  1612. */
  1613. Graphics._createAllElements = function() {
  1614. this._createErrorPrinter();
  1615. this._createCanvas();
  1616. this._createVideo();
  1617. this._createUpperCanvas();
  1618. this._createRenderer();
  1619. this._createFPSMeter();
  1620. this._createModeBox();
  1621. this._createGameFontLoader();
  1622. };
  1623.  
  1624. /**
  1625. * @static
  1626. * @method _updateAllElements
  1627. * @private
  1628. */
  1629. Graphics._updateAllElements = function() {
  1630. this._updateRealScale();
  1631. this._updateErrorPrinter();
  1632. this._updateCanvas();
  1633. this._updateVideo();
  1634. this._updateUpperCanvas();
  1635. this._updateRenderer();
  1636. this._paintUpperCanvas();
  1637. };
  1638.  
  1639. /**
  1640. * @static
  1641. * @method _updateRealScale
  1642. * @private
  1643. */
  1644. Graphics._updateRealScale = function() {
  1645. if (this._stretchEnabled) {
  1646. var h = window.innerWidth / this._width;
  1647. var v = window.innerHeight / this._height;
  1648. this._realScale = Math.min(h, v);
  1649. } else {
  1650. this._realScale = this._scale;
  1651. }
  1652. };
  1653.  
  1654. /**
  1655. * @static
  1656. * @method _makeErrorHtml
  1657. * @param {String} name
  1658. * @param {String} message
  1659. * @return {String}
  1660. * @private
  1661. */
  1662. Graphics._makeErrorHtml = function(name, message) {
  1663. return ('<font color="yellow"><b>' + name + '</b></font><br>' +
  1664. '<font color="white">' + message + '</font><br>');
  1665. };
  1666.  
  1667. /**
  1668. * @static
  1669. * @method _defaultStretchMode
  1670. * @private
  1671. */
  1672. Graphics._defaultStretchMode = function() {
  1673. return Utils.isNwjs() || Utils.isMobileDevice();
  1674. };
  1675.  
  1676. /**
  1677. * @static
  1678. * @method _testCanvasBlendModes
  1679. * @private
  1680. */
  1681. Graphics._testCanvasBlendModes = function() {
  1682. var canvas, context, imageData1, imageData2;
  1683. canvas = document.createElement('canvas');
  1684. canvas.width = 1;
  1685. canvas.height = 1;
  1686. context = canvas.getContext('2d');
  1687. context.globalCompositeOperation = 'source-over';
  1688. context.fillStyle = 'white';
  1689. context.fillRect(0, 0, 1, 1);
  1690. context.globalCompositeOperation = 'difference';
  1691. context.fillStyle = 'white';
  1692. context.fillRect(0, 0, 1, 1);
  1693. imageData1 = context.getImageData(0, 0, 1, 1);
  1694. context.globalCompositeOperation = 'source-over';
  1695. context.fillStyle = 'black';
  1696. context.fillRect(0, 0, 1, 1);
  1697. context.globalCompositeOperation = 'saturation';
  1698. context.fillStyle = 'white';
  1699. context.fillRect(0, 0, 1, 1);
  1700. imageData2 = context.getImageData(0, 0, 1, 1);
  1701. this._canUseDifferenceBlend = imageData1.data[0] === 0;
  1702. this._canUseSaturationBlend = imageData2.data[0] === 0;
  1703. };
  1704.  
  1705. /**
  1706. * @static
  1707. * @method _modifyExistingElements
  1708. * @private
  1709. */
  1710. Graphics._modifyExistingElements = function() {
  1711. var elements = document.getElementsByTagName('*');
  1712. for (var i = 0; i < elements.length; i++) {
  1713. if (elements[i].style.zIndex > 0) {
  1714. elements[i].style.zIndex = 0;
  1715. }
  1716. }
  1717. };
  1718.  
  1719. /**
  1720. * @static
  1721. * @method _createErrorPrinter
  1722. * @private
  1723. */
  1724. Graphics._createErrorPrinter = function() {
  1725. this._errorPrinter = document.createElement('p');
  1726. this._errorPrinter.id = 'ErrorPrinter';
  1727. this._updateErrorPrinter();
  1728. document.body.appendChild(this._errorPrinter);
  1729. };
  1730.  
  1731. /**
  1732. * @static
  1733. * @method _updateErrorPrinter
  1734. * @private
  1735. */
  1736. Graphics._updateErrorPrinter = function() {
  1737. this._errorPrinter.width = this._width * 0.9;
  1738. this._errorPrinter.height = 40;
  1739. this._errorPrinter.style.textAlign = 'center';
  1740. this._errorPrinter.style.textShadow = '1px 1px 3px #000';
  1741. this._errorPrinter.style.fontSize = '20px';
  1742. this._errorPrinter.style.zIndex = 99;
  1743. this._centerElement(this._errorPrinter);
  1744. };
  1745.  
  1746. /**
  1747. * @static
  1748. * @method _createCanvas
  1749. * @private
  1750. */
  1751. Graphics._createCanvas = function() {
  1752. this._canvas = document.createElement('canvas');
  1753. this._canvas.id = 'GameCanvas';
  1754. this._updateCanvas();
  1755. document.body.appendChild(this._canvas);
  1756. };
  1757.  
  1758. /**
  1759. * @static
  1760. * @method _updateCanvas
  1761. * @private
  1762. */
  1763. Graphics._updateCanvas = function() {
  1764. this._canvas.width = this._width;
  1765. this._canvas.height = this._height;
  1766. this._canvas.style.zIndex = 1;
  1767. this._centerElement(this._canvas);
  1768. };
  1769.  
  1770. /**
  1771. * @static
  1772. * @method _createVideo
  1773. * @private
  1774. */
  1775. Graphics._createVideo = function() {
  1776. this._video = document.createElement('video');
  1777. this._video.id = 'GameVideo';
  1778. this._video.style.opacity = 0;
  1779. this._updateVideo();
  1780. document.body.appendChild(this._video);
  1781. };
  1782.  
  1783. /**
  1784. * @static
  1785. * @method _updateVideo
  1786. * @private
  1787. */
  1788. Graphics._updateVideo = function() {
  1789. this._video.width = this._width;
  1790. this._video.height = this._height;
  1791. this._video.style.zIndex = 2;
  1792. this._centerElement(this._video);
  1793. };
  1794.  
  1795. /**
  1796. * @static
  1797. * @method _createUpperCanvas
  1798. * @private
  1799. */
  1800. Graphics._createUpperCanvas = function() {
  1801. this._upperCanvas = document.createElement('canvas');
  1802. this._upperCanvas.id = 'UpperCanvas';
  1803. this._updateUpperCanvas();
  1804. document.body.appendChild(this._upperCanvas);
  1805. };
  1806.  
  1807. /**
  1808. * @static
  1809. * @method _updateUpperCanvas
  1810. * @private
  1811. */
  1812. Graphics._updateUpperCanvas = function() {
  1813. this._upperCanvas.width = this._width;
  1814. this._upperCanvas.height = this._height;
  1815. this._upperCanvas.style.zIndex = 3;
  1816. this._centerElement(this._upperCanvas);
  1817. };
  1818.  
  1819. /**
  1820. * @static
  1821. * @method _clearUpperCanvas
  1822. * @private
  1823. */
  1824. Graphics._clearUpperCanvas = function() {
  1825. var context = this._upperCanvas.getContext('2d');
  1826. context.clearRect(0, 0, this._width, this._height);
  1827. };
  1828.  
  1829. /**
  1830. * @static
  1831. * @method _paintUpperCanvas
  1832. * @private
  1833. */
  1834. Graphics._paintUpperCanvas = function() {
  1835. this._clearUpperCanvas();
  1836. if (this._loadingImage && this._loadingCount >= 20) {
  1837. var context = this._upperCanvas.getContext('2d');
  1838. var dx = (this._width - this._loadingImage.width) / 2;
  1839. var dy = (this._height - this._loadingImage.height) / 2;
  1840. var alpha = ((this._loadingCount - 20) / 30).clamp(0, 1);
  1841. context.save();
  1842. context.globalAlpha = alpha;
  1843. context.drawImage(this._loadingImage, dx, dy);
  1844. context.restore();
  1845. }
  1846. };
  1847.  
  1848. /**
  1849. * @static
  1850. * @method _createRenderer
  1851. * @private
  1852. */
  1853. Graphics._createRenderer = function() {
  1854. PIXI.dontSayHello = true;
  1855. var width = this._width;
  1856. var height = this._height;
  1857. var options = { view: this._canvas };
  1858. try {
  1859. switch (this._rendererType) {
  1860. case 'canvas':
  1861. this._renderer = new PIXI.CanvasRenderer(width, height, options);
  1862. break;
  1863. case 'webgl':
  1864. this._renderer = new PIXI.WebGLRenderer(width, height, options);
  1865. break;
  1866. default:
  1867. this._renderer = PIXI.autoDetectRenderer(width, height, options);
  1868. break;
  1869. }
  1870. } catch (e) {
  1871. this._renderer = null;
  1872. }
  1873. };
  1874.  
  1875. /**
  1876. * @static
  1877. * @method _updateRenderer
  1878. * @private
  1879. */
  1880. Graphics._updateRenderer = function() {
  1881. if (this._renderer) {
  1882. this._renderer.resize(this._width, this._height);
  1883. }
  1884. };
  1885.  
  1886. /**
  1887. * @static
  1888. * @method _createFPSMeter
  1889. * @private
  1890. */
  1891. Graphics._createFPSMeter = function() {
  1892. var options = { graph: 1, decimals: 0, theme: 'transparent', toggleOn: null };
  1893. this._fpsMeter = new FPSMeter(options);
  1894. this._fpsMeter.hide();
  1895. };
  1896.  
  1897. /**
  1898. * @static
  1899. * @method _createModeBox
  1900. * @private
  1901. */
  1902. Graphics._createModeBox = function() {
  1903. var box = document.createElement('div');
  1904. box.id = 'modeTextBack';
  1905. box.style.position = 'absolute';
  1906. box.style.left = '5px';
  1907. box.style.top = '5px';
  1908. box.style.width = '119px';
  1909. box.style.height = '58px';
  1910. box.style.background = 'rgba(0,0,0,0.2)';
  1911. box.style.zIndex = 9;
  1912. box.style.opacity = 0;
  1913.  
  1914. var text = document.createElement('div');
  1915. text.id = 'modeText';
  1916. text.style.position = 'absolute';
  1917. text.style.left = '0px';
  1918. text.style.top = '41px';
  1919. text.style.width = '119px';
  1920. text.style.fontSize = '12px';
  1921. text.style.fontFamily = 'monospace';
  1922. text.style.color = 'white';
  1923. text.style.textAlign = 'center';
  1924. text.style.textShadow = '1px 1px 0 rgba(0,0,0,0.5)';
  1925. text.innerHTML = this.isWebGL() ? 'WebGL mode' : 'Canvas mode';
  1926.  
  1927. document.body.appendChild(box);
  1928. box.appendChild(text);
  1929.  
  1930. this._modeBox = box;
  1931. };
  1932.  
  1933. /**
  1934. * @static
  1935. * @method _createGameFontLoader
  1936. * @private
  1937. */
  1938. Graphics._createGameFontLoader = function() {
  1939. this._createFontLoader('GameFont');
  1940. };
  1941.  
  1942. /**
  1943. * @static
  1944. * @method _createFontLoader
  1945. * @param {String} name
  1946. * @private
  1947. */
  1948. Graphics._createFontLoader = function(name) {
  1949. var div = document.createElement('div');
  1950. var text = document.createTextNode('.');
  1951. div.style.fontFamily = name;
  1952. div.style.fontSize = '0px';
  1953. div.style.color = 'transparent';
  1954. div.style.position = 'absolute';
  1955. div.style.margin = 'auto';
  1956. div.style.top = '0px';
  1957. div.style.left = '0px';
  1958. div.style.width = '1px';
  1959. div.style.height = '1px';
  1960. div.appendChild(text);
  1961. document.body.appendChild(div);
  1962. };
  1963.  
  1964. /**
  1965. * @static
  1966. * @method _centerElement
  1967. * @param {HTMLElement} element
  1968. * @private
  1969. */
  1970. Graphics._centerElement = function(element) {
  1971. var width = element.width * this._realScale;
  1972. var height = element.height * this._realScale;
  1973. element.style.position = 'absolute';
  1974. element.style.margin = 'auto';
  1975. element.style.top = 0;
  1976. element.style.left = 0;
  1977. element.style.right = 0;
  1978. element.style.bottom = 0;
  1979. element.style.width = width + 'px';
  1980. element.style.height = height + 'px';
  1981. };
  1982.  
  1983. /**
  1984. * @static
  1985. * @method _disableTextSelection
  1986. * @private
  1987. */
  1988. Graphics._disableTextSelection = function() {
  1989. var body = document.body;
  1990. body.style.userSelect = 'none';
  1991. body.style.webkitUserSelect = 'none';
  1992. body.style.msUserSelect = 'none';
  1993. body.style.mozUserSelect = 'none';
  1994. };
  1995.  
  1996. /**
  1997. * @static
  1998. * @method _disableContextMenu
  1999. * @private
  2000. */
  2001. Graphics._disableContextMenu = function() {
  2002. var elements = document.body.getElementsByTagName('*');
  2003. var oncontextmenu = function() { return false; };
  2004. for (var i = 0; i < elements.length; i++) {
  2005. elements[i].oncontextmenu = oncontextmenu;
  2006. }
  2007. };
  2008.  
  2009. /**
  2010. * @static
  2011. * @method _applyCanvasFilter
  2012. * @private
  2013. */
  2014. Graphics._applyCanvasFilter = function() {
  2015. if (this._canvas) {
  2016. this._canvas.style.opacity = 0.5;
  2017. this._canvas.style.filter = 'blur(8px)';
  2018. this._canvas.style.webkitFilter = 'blur(8px)';
  2019. }
  2020. };
  2021.  
  2022. /**
  2023. * @static
  2024. * @method _onVideoLoad
  2025. * @private
  2026. */
  2027. Graphics._onVideoLoad = function() {
  2028. this._video.play();
  2029. this._updateVisibility(true);
  2030. };
  2031.  
  2032. /**
  2033. * @static
  2034. * @method _onVideoError
  2035. * @private
  2036. */
  2037. Graphics._onVideoError = function() {
  2038. this._updateVisibility(false);
  2039. };
  2040.  
  2041. /**
  2042. * @static
  2043. * @method _onVideoEnd
  2044. * @private
  2045. */
  2046. Graphics._onVideoEnd = function() {
  2047. this._updateVisibility(false);
  2048. };
  2049.  
  2050. /**
  2051. * @static
  2052. * @method _updateVisibility
  2053. * @param {Boolean} videoVisible
  2054. * @private
  2055. */
  2056. Graphics._updateVisibility = function(videoVisible) {
  2057. this._video.style.opacity = videoVisible ? 1 : 0;
  2058. this._canvas.style.opacity = videoVisible ? 0 : 1;
  2059. };
  2060.  
  2061. /**
  2062. * @static
  2063. * @method _isVideoVisible
  2064. * @return {Boolean}
  2065. * @private
  2066. */
  2067. Graphics._isVideoVisible = function() {
  2068. return this._video.style.opacity > 0;
  2069. };
  2070.  
  2071. /**
  2072. * @static
  2073. * @method _setupEventHandlers
  2074. * @private
  2075. */
  2076. Graphics._setupEventHandlers = function() {
  2077. window.addEventListener('resize', this._onWindowResize.bind(this));
  2078. document.addEventListener('keydown', this._onKeyDown.bind(this));
  2079. };
  2080.  
  2081. /**
  2082. * @static
  2083. * @method _onWindowResize
  2084. * @private
  2085. */
  2086. Graphics._onWindowResize = function() {
  2087. this._updateAllElements();
  2088. };
  2089.  
  2090. /**
  2091. * @static
  2092. * @method _onKeyDown
  2093. * @param {KeyboardEvent} event
  2094. * @private
  2095. */
  2096. Graphics._onKeyDown = function(event) {
  2097. if (!event.ctrlKey && !event.altKey) {
  2098. switch (event.keyCode) {
  2099. case 113: // F2
  2100. event.preventDefault();
  2101. this._switchFPSMeter();
  2102. break;
  2103. case 114: // F3
  2104. event.preventDefault();
  2105. this._switchStretchMode();
  2106. break;
  2107. case 115: // F4
  2108. event.preventDefault();
  2109. this._switchFullScreen();
  2110. break;
  2111. }
  2112. }
  2113. };
  2114.  
  2115. /**
  2116. * @static
  2117. * @method _switchFPSMeter
  2118. * @private
  2119. */
  2120. Graphics._switchFPSMeter = function() {
  2121. if (this._fpsMeter.isPaused) {
  2122. this.showFps();
  2123. this._fpsMeter.showFps();
  2124. this._fpsMeterToggled = false;
  2125. } else if (!this._fpsMeterToggled) {
  2126. this._fpsMeter.showDuration();
  2127. this._fpsMeterToggled = true;
  2128. } else {
  2129. this.hideFps();
  2130. }
  2131. };
  2132.  
  2133. /**
  2134. * @static
  2135. * @method _switchStretchMode
  2136. * @return {Boolean}
  2137. * @private
  2138. */
  2139. Graphics._switchStretchMode = function() {
  2140. this._stretchEnabled = !this._stretchEnabled;
  2141. this._updateAllElements();
  2142. };
  2143.  
  2144. /**
  2145. * @static
  2146. * @method _switchFullScreen
  2147. * @private
  2148. */
  2149. Graphics._switchFullScreen = function() {
  2150. if (this._isFullScreen()) {
  2151. this._requestFullScreen();
  2152. } else {
  2153. this._cancelFullScreen();
  2154. }
  2155. };
  2156.  
  2157. /**
  2158. * @static
  2159. * @method _isFullScreen
  2160. * @return {Boolean}
  2161. * @private
  2162. */
  2163. Graphics._isFullScreen = function() {
  2164. return ((document.fullScreenElement && document.fullScreenElement !== null) ||
  2165. (!document.mozFullScreen && !document.webkitFullscreenElement &&
  2166. !document.msFullscreenElement));
  2167. };
  2168.  
  2169. /**
  2170. * @static
  2171. * @method _requestFullScreen
  2172. * @private
  2173. */
  2174. Graphics._requestFullScreen = function() {
  2175. var element = document.body;
  2176. if (element.requestFullScreen) {
  2177. element.requestFullScreen();
  2178. } else if (element.mozRequestFullScreen) {
  2179. element.mozRequestFullScreen();
  2180. } else if (element.webkitRequestFullScreen) {
  2181. element.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
  2182. } else if (element.msRequestFullscreen) {
  2183. element.msRequestFullscreen();
  2184. }
  2185. };
  2186.  
  2187. /**
  2188. * @static
  2189. * @method _cancelFullScreen
  2190. * @private
  2191. */
  2192. Graphics._cancelFullScreen = function() {
  2193. if (document.cancelFullScreen) {
  2194. document.cancelFullScreen();
  2195. } else if (document.mozCancelFullScreen) {
  2196. document.mozCancelFullScreen();
  2197. } else if (document.webkitCancelFullScreen) {
  2198. document.webkitCancelFullScreen();
  2199. } else if (document.msExitFullscreen) {
  2200. document.msExitFullscreen();
  2201. }
  2202. };
  2203.  
  2204. //-----------------------------------------------------------------------------
  2205. /**
  2206. * The static class that handles input data from the keyboard and gamepads.
  2207. *
  2208. * @class Input
  2209. */
  2210. function Input() {
  2211. throw new Error('This is a static class');
  2212. }
  2213.  
  2214. /**
  2215. * Initializes the input system.
  2216. *
  2217. * @static
  2218. * @method initialize
  2219. */
  2220. Input.initialize = function() {
  2221. this.clear();
  2222. this._wrapNwjsAlert();
  2223. this._setupEventHandlers();
  2224. };
  2225.  
  2226. /**
  2227. * The wait time of the key repeat in frames.
  2228. *
  2229. * @static
  2230. * @property keyRepeatWait
  2231. * @type Number
  2232. */
  2233. Input.keyRepeatWait = 24;
  2234.  
  2235. /**
  2236. * The interval of the key repeat in frames.
  2237. *
  2238. * @static
  2239. * @property keyRepeatInterval
  2240. * @type Number
  2241. */
  2242. Input.keyRepeatInterval = 6;
  2243.  
  2244. /**
  2245. * A hash table to convert from a virtual key code to a mapped key name.
  2246. *
  2247. * @static
  2248. * @property keyMapper
  2249. * @type Object
  2250. */
  2251. Input.keyMapper = {
  2252. 9: 'tab', // tab
  2253. 13: 'ok', // enter
  2254. 16: 'shift', // shift
  2255. 17: 'control', // control
  2256. 18: 'control', // alt
  2257. 27: 'escape', // escape
  2258. 32: 'ok', // space
  2259. 33: 'pageup', // pageup
  2260. 34: 'pagedown', // pagedown
  2261. 37: 'left', // left arrow
  2262. 38: 'up', // up arrow
  2263. 39: 'right', // right arrow
  2264. 40: 'down', // down arrow
  2265. 45: 'escape', // insert
  2266. 81: 'pageup', // Q
  2267. 87: 'pagedown', // W
  2268. 88: 'escape', // X
  2269. 90: 'ok', // Z
  2270. 96: 'escape', // numpad 0
  2271. 98: 'down', // numpad 2
  2272. 100: 'left', // numpad 4
  2273. 102: 'right', // numpad 6
  2274. 104: 'up', // numpad 8
  2275. 120: 'debug' // F9
  2276. };
  2277.  
  2278. /**
  2279. * A hash table to convert from a gamepad button to a mapped key name.
  2280. *
  2281. * @static
  2282. * @property gamepadMapper
  2283. * @type Object
  2284. */
  2285. Input.gamepadMapper = {
  2286. 0: 'ok', // A
  2287. 1: 'cancel', // B
  2288. 2: 'shift', // X
  2289. 3: 'menu', // Y
  2290. 4: 'pageup', // LB
  2291. 5: 'pagedown', // RB
  2292. 12: 'up', // D-pad up
  2293. 13: 'down', // D-pad down
  2294. 14: 'left', // D-pad left
  2295. 15: 'right', // D-pad right
  2296. };
  2297.  
  2298. /**
  2299. * Clears all the input data.
  2300. *
  2301. * @static
  2302. * @method clear
  2303. */
  2304. Input.clear = function() {
  2305. this._currentState = {};
  2306. this._previousState = {};
  2307. this._gamepadStates = [];
  2308. this._latestButton = null;
  2309. this._pressedTime = 0;
  2310. this._dir4 = 0;
  2311. this._dir8 = 0;
  2312. this._preferredAxis = '';
  2313. this._date = 0;
  2314. };
  2315.  
  2316. /**
  2317. * Updates the input data.
  2318. *
  2319. * @static
  2320. * @method update
  2321. */
  2322. Input.update = function() {
  2323. this._pollGamepads();
  2324. if (this._currentState[this._latestButton]) {
  2325. this._pressedTime++;
  2326. } else {
  2327. this._latestButton = null;
  2328. }
  2329. for (var name in this._currentState) {
  2330. if (this._currentState[name] && !this._previousState[name]) {
  2331. this._latestButton = name;
  2332. this._pressedTime = 0;
  2333. this._date = Date.now();
  2334. }
  2335. this._previousState[name] = this._currentState[name];
  2336. }
  2337. this._updateDirection();
  2338. };
  2339.  
  2340. /**
  2341. * Checks whether a key is currently pressed down.
  2342. *
  2343. * @static
  2344. * @method isPressed
  2345. * @param {String} keyName The mapped name of the key
  2346. * @return {Boolean} True if the key is pressed
  2347. */
  2348. Input.isPressed = function(keyName) {
  2349. if (this._isEscapeCompatible(keyName) && this.isPressed('escape')) {
  2350. return true;
  2351. } else {
  2352. return !!this._currentState[keyName];
  2353. }
  2354. };
  2355.  
  2356. /**
  2357. * Checks whether a key is just pressed.
  2358. *
  2359. * @static
  2360. * @method isTriggered
  2361. * @param {String} keyName The mapped name of the key
  2362. * @return {Boolean} True if the key is triggered
  2363. */
  2364. Input.isTriggered = function(keyName) {
  2365. if (this._isEscapeCompatible(keyName) && this.isTriggered('escape')) {
  2366. return true;
  2367. } else {
  2368. return this._latestButton === keyName && this._pressedTime === 0;
  2369. }
  2370. };
  2371.  
  2372. /**
  2373. * Checks whether a key is just pressed or a key repeat occurred.
  2374. *
  2375. * @static
  2376. * @method isRepeated
  2377. * @param {String} keyName The mapped name of the key
  2378. * @return {Boolean} True if the key is repeated
  2379. */
  2380. Input.isRepeated = function(keyName) {
  2381. if (this._isEscapeCompatible(keyName) && this.isRepeated('escape')) {
  2382. return true;
  2383. } else {
  2384. return (this._latestButton === keyName &&
  2385. (this._pressedTime === 0 ||
  2386. (this._pressedTime >= this.keyRepeatWait &&
  2387. this._pressedTime % this.keyRepeatInterval === 0)));
  2388. }
  2389. };
  2390.  
  2391. /**
  2392. * Checks whether a key is kept depressed.
  2393. *
  2394. * @static
  2395. * @method isLongPressed
  2396. * @param {String} keyName The mapped name of the key
  2397. * @return {Boolean} True if the key is long-pressed
  2398. */
  2399. Input.isLongPressed = function(keyName) {
  2400. if (this._isEscapeCompatible(keyName) && this.isLongPressed('escape')) {
  2401. return true;
  2402. } else {
  2403. return (this._latestButton === keyName &&
  2404. this._pressedTime >= this.keyRepeatWait);
  2405. }
  2406. };
  2407.  
  2408. /**
  2409. * [read-only] The four direction value as a number of the numpad, or 0 for neutral.
  2410. *
  2411. * @static
  2412. * @property dir4
  2413. * @type Number
  2414. */
  2415. Object.defineProperty(Input, 'dir4', {
  2416. get: function() {
  2417. return this._dir4;
  2418. },
  2419. configurable: true
  2420. });
  2421.  
  2422. /**
  2423. * [read-only] The eight direction value as a number of the numpad, or 0 for neutral.
  2424. *
  2425. * @static
  2426. * @property dir8
  2427. * @type Number
  2428. */
  2429. Object.defineProperty(Input, 'dir8', {
  2430. get: function() {
  2431. return this._dir8;
  2432. },
  2433. configurable: true
  2434. });
  2435.  
  2436. /**
  2437. * [read-only] The time of the last input in milliseconds.
  2438. *
  2439. * @static
  2440. * @property date
  2441. * @type Number
  2442. */
  2443. Object.defineProperty(Input, 'date', {
  2444. get: function() {
  2445. return this._date;
  2446. },
  2447. configurable: true
  2448. });
  2449.  
  2450. /**
  2451. * @static
  2452. * @method _wrapNwjsAlert
  2453. * @private
  2454. */
  2455. Input._wrapNwjsAlert = function() {
  2456. if (Utils.isNwjs()) {
  2457. var _alert = window.alert;
  2458. window.alert = function() {
  2459. var gui = require('nw.gui');
  2460. var win = gui.Window.get();
  2461. _alert.apply(this, arguments);
  2462. win.focus();
  2463. Input.clear();
  2464. };
  2465. }
  2466. };
  2467.  
  2468. /**
  2469. * @static
  2470. * @method _setupEventHandlers
  2471. * @private
  2472. */
  2473. Input._setupEventHandlers = function() {
  2474. document.addEventListener('keydown', this._onKeyDown.bind(this));
  2475. document.addEventListener('keyup', this._onKeyUp.bind(this));
  2476. window.addEventListener('blur', this._onLostFocus.bind(this));
  2477. };
  2478.  
  2479. /**
  2480. * @static
  2481. * @method _onKeyDown
  2482. * @param {KeyboardEvent} event
  2483. * @private
  2484. */
  2485. Input._onKeyDown = function(event) {
  2486. if (this._shouldPreventDefault(event.keyCode)) {
  2487. event.preventDefault();
  2488. }
  2489. if (event.keyCode === 144) { // Numlock
  2490. this.clear();
  2491. }
  2492. var buttonName = this.keyMapper[event.keyCode];
  2493. if (buttonName) {
  2494. this._currentState[buttonName] = true;
  2495. }
  2496. };
  2497.  
  2498. /**
  2499. * @static
  2500. * @method _shouldPreventDefault
  2501. * @param {Number} keyCode
  2502. * @private
  2503. */
  2504. Input._shouldPreventDefault = function(keyCode) {
  2505. switch (keyCode) {
  2506. case 8: // backspace
  2507. case 33: // pageup
  2508. case 34: // pagedown
  2509. case 37: // left arrow
  2510. case 38: // up arrow
  2511. case 39: // right arrow
  2512. case 40: // down arrow
  2513. return true;
  2514. }
  2515. return false;
  2516. };
  2517.  
  2518. /**
  2519. * @static
  2520. * @method _onKeyUp
  2521. * @param {KeyboardEvent} event
  2522. * @private
  2523. */
  2524. Input._onKeyUp = function(event) {
  2525. var buttonName = this.keyMapper[event.keyCode];
  2526. if (buttonName) {
  2527. this._currentState[buttonName] = false;
  2528. }
  2529. if (event.keyCode === 0) { // For QtWebEngine on OS X
  2530. this.clear();
  2531. }
  2532. };
  2533.  
  2534. /**
  2535. * @static
  2536. * @method _onLostFocus
  2537. * @private
  2538. */
  2539. Input._onLostFocus = function() {
  2540. this.clear();
  2541. };
  2542.  
  2543. /**
  2544. * @static
  2545. * @method _pollGamepads
  2546. * @private
  2547. */
  2548. Input._pollGamepads = function() {
  2549. if (navigator.getGamepads) {
  2550. var gamepads = navigator.getGamepads();
  2551. if (gamepads) {
  2552. for (var i = 0; i < gamepads.length; i++) {
  2553. var gamepad = gamepads[i];
  2554. if (gamepad && gamepad.connected) {
  2555. this._updateGamepadState(gamepad);
  2556. }
  2557. }
  2558. }
  2559. }
  2560. };
  2561.  
  2562. /**
  2563. * @static
  2564. * @method _updateGamepadState
  2565. * @param {Gamepad} gamepad
  2566. * @param {Number} index
  2567. * @private
  2568. */
  2569. Input._updateGamepadState = function(gamepad) {
  2570. var lastState = this._gamepadStates[gamepad.index] || [];
  2571. var newState = [];
  2572. var buttons = gamepad.buttons;
  2573. var axes = gamepad.axes;
  2574. var threshold = 0.5;
  2575. for (var i = 0; i < buttons.length; i++) {
  2576. newState[i] = buttons[i].pressed;
  2577. }
  2578. if (axes[1] < -threshold) {
  2579. newState[12] = true; // up
  2580. } else if (axes[1] > threshold) {
  2581. newState[13] = true; // down
  2582. }
  2583. if (axes[0] < -threshold) {
  2584. newState[14] = true; // left
  2585. } else if (axes[0] > threshold) {
  2586. newState[15] = true; // right
  2587. }
  2588. for (var j = 0; j < newState.length; j++) {
  2589. if (newState[j] !== lastState[j]) {
  2590. var buttonName = this.gamepadMapper[j];
  2591. if (buttonName) {
  2592. this._currentState[buttonName] = newState[j];
  2593. }
  2594. }
  2595. }
  2596. this._gamepadStates[gamepad.index] = newState;
  2597. };
  2598.  
  2599. /**
  2600. * @static
  2601. * @method _updateDirection
  2602. * @private
  2603. */
  2604. Input._updateDirection = function() {
  2605. var x = this._signX();
  2606. var y = this._signY();
  2607.  
  2608. this._dir8 = this._makeNumpadDirection(x, y);
  2609.  
  2610. if (x !== 0 && y !== 0) {
  2611. if (this._preferredAxis === 'x') {
  2612. y = 0;
  2613. } else {
  2614. x = 0;
  2615. }
  2616. } else if (x !== 0) {
  2617. this._preferredAxis = 'y';
  2618. } else if (y !== 0) {
  2619. this._preferredAxis = 'x';
  2620. }
  2621.  
  2622. this._dir4 = this._makeNumpadDirection(x, y);
  2623. };
  2624.  
  2625. /**
  2626. * @static
  2627. * @method _signX
  2628. * @private
  2629. */
  2630. Input._signX = function() {
  2631. var x = 0;
  2632.  
  2633. if (this.isPressed('left')) {
  2634. x--;
  2635. }
  2636. if (this.isPressed('right')) {
  2637. x++;
  2638. }
  2639. return x;
  2640. };
  2641.  
  2642. /**
  2643. * @static
  2644. * @method _signY
  2645. * @private
  2646. */
  2647. Input._signY = function() {
  2648. var y = 0;
  2649.  
  2650. if (this.isPressed('up')) {
  2651. y--;
  2652. }
  2653. if (this.isPressed('down')) {
  2654. y++;
  2655. }
  2656. return y;
  2657. };
  2658.  
  2659. /**
  2660. * @static
  2661. * @method _makeNumpadDirection
  2662. * @param {Number} x
  2663. * @param {Number} y
  2664. * @return {Number}
  2665. * @private
  2666. */
  2667. Input._makeNumpadDirection = function(x, y) {
  2668. if (x !== 0 || y !== 0) {
  2669. return 5 - y * 3 + x;
  2670. }
  2671. return 0;
  2672. };
  2673.  
  2674. /**
  2675. * @static
  2676. * @method _isEscapeCompatible
  2677. * @param {String} keyName
  2678. * @return {Boolean}
  2679. * @private
  2680. */
  2681. Input._isEscapeCompatible = function(keyName) {
  2682. return keyName === 'cancel' || keyName === 'menu';
  2683. };
  2684.  
  2685. //-----------------------------------------------------------------------------
  2686. /**
  2687. * The static class that handles input data from the mouse and touchscreen.
  2688. *
  2689. * @class TouchInput
  2690. */
  2691. function TouchInput() {
  2692. throw new Error('This is a static class');
  2693. }
  2694.  
  2695. /**
  2696. * Initializes the touch system.
  2697. *
  2698. * @static
  2699. * @method initialize
  2700. */
  2701. TouchInput.initialize = function() {
  2702. this.clear();
  2703. this._setupEventHandlers();
  2704. };
  2705.  
  2706. /**
  2707. * The wait time of the pseudo key repeat in frames.
  2708. *
  2709. * @static
  2710. * @property keyRepeatWait
  2711. * @type Number
  2712. */
  2713. TouchInput.keyRepeatWait = 24;
  2714.  
  2715. /**
  2716. * The interval of the pseudo key repeat in frames.
  2717. *
  2718. * @static
  2719. * @property keyRepeatInterval
  2720. * @type Number
  2721. */
  2722. TouchInput.keyRepeatInterval = 6;
  2723.  
  2724. /**
  2725. * Clears all the touch data.
  2726. *
  2727. * @static
  2728. * @method clear
  2729. */
  2730. TouchInput.clear = function() {
  2731. this._mousePressed = false;
  2732. this._screenPressed = false;
  2733. this._pressedTime = 0;
  2734. this._events = {};
  2735. this._events.triggered = false;
  2736. this._events.cancelled = false;
  2737. this._events.moved = false;
  2738. this._events.released = false;
  2739. this._events.wheelX = 0;
  2740. this._events.wheelY = 0;
  2741. this._triggered = false;
  2742. this._cancelled = false;
  2743. this._moved = false;
  2744. this._released = false;
  2745. this._wheelX = 0;
  2746. this._wheelY = 0;
  2747. this._x = 0;
  2748. this._y = 0;
  2749. this._date = 0;
  2750. };
  2751.  
  2752. /**
  2753. * Updates the touch data.
  2754. *
  2755. * @static
  2756. * @method update
  2757. */
  2758. TouchInput.update = function() {
  2759. this._triggered = this._events.triggered;
  2760. this._cancelled = this._events.cancelled;
  2761. this._moved = this._events.moved;
  2762. this._released = this._events.released;
  2763. this._wheelX = this._events.wheelX;
  2764. this._wheelY = this._events.wheelY;
  2765. this._events.triggered = false;
  2766. this._events.cancelled = false;
  2767. this._events.moved = false;
  2768. this._events.released = false;
  2769. this._events.wheelX = 0;
  2770. this._events.wheelY = 0;
  2771. if (this.isPressed()) {
  2772. this._pressedTime++;
  2773. }
  2774. };
  2775.  
  2776. /**
  2777. * Checks whether the mouse button or touchscreen is currently pressed down.
  2778. *
  2779. * @static
  2780. * @method isPressed
  2781. * @return {Boolean} True if the mouse button or touchscreen is pressed
  2782. */
  2783. TouchInput.isPressed = function() {
  2784. return this._mousePressed || this._screenPressed;
  2785. };
  2786.  
  2787. /**
  2788. * Checks whether the left mouse button or touchscreen is just pressed.
  2789. *
  2790. * @static
  2791. * @method isTriggered
  2792. * @return {Boolean} True if the mouse button or touchscreen is triggered
  2793. */
  2794. TouchInput.isTriggered = function() {
  2795. return this._triggered;
  2796. };
  2797.  
  2798. /**
  2799. * Checks whether the left mouse button or touchscreen is just pressed
  2800. * or a pseudo key repeat occurred.
  2801. *
  2802. * @static
  2803. * @method isRepeated
  2804. * @return {Boolean} True if the mouse button or touchscreen is repeated
  2805. */
  2806. TouchInput.isRepeated = function() {
  2807. return (this.isPressed() &&
  2808. (this._triggered ||
  2809. (this._pressedTime >= this.keyRepeatWait &&
  2810. this._pressedTime % this.keyRepeatInterval === 0)));
  2811. };
  2812.  
  2813. /**
  2814. * Checks whether the left mouse button or touchscreen is kept depressed.
  2815. *
  2816. * @static
  2817. * @method isLongPressed
  2818. * @return {Boolean} True if the left mouse button or touchscreen is long-pressed
  2819. */
  2820. TouchInput.isLongPressed = function() {
  2821. return this.isPressed() && this._pressedTime >= this.keyRepeatWait;
  2822. };
  2823.  
  2824. /**
  2825. * Checks whether the right mouse button is just pressed.
  2826. *
  2827. * @static
  2828. * @method isCancelled
  2829. * @return {Boolean} True if the right mouse button is just pressed
  2830. */
  2831. TouchInput.isCancelled = function() {
  2832. return this._cancelled;
  2833. };
  2834.  
  2835. /**
  2836. * Checks whether the mouse or a finger on the touchscreen is moved.
  2837. *
  2838. * @static
  2839. * @method isMoved
  2840. * @return {Boolean} True if the mouse or a finger on the touchscreen is moved
  2841. */
  2842. TouchInput.isMoved = function() {
  2843. return this._moved;
  2844. };
  2845.  
  2846. /**
  2847. * Checks whether the left mouse button or touchscreen is released.
  2848. *
  2849. * @static
  2850. * @method isReleased
  2851. * @return {Boolean} True if the mouse button or touchscreen is released
  2852. */
  2853. TouchInput.isReleased = function() {
  2854. return this._released;
  2855. };
  2856.  
  2857. /**
  2858. * [read-only] The horizontal scroll amount.
  2859. *
  2860. * @static
  2861. * @property wheelX
  2862. * @type Number
  2863. */
  2864. Object.defineProperty(TouchInput, 'wheelX', {
  2865. get: function() {
  2866. return this._wheelX;
  2867. },
  2868. configurable: true
  2869. });
  2870.  
  2871. /**
  2872. * [read-only] The vertical scroll amount.
  2873. *
  2874. * @static
  2875. * @property wheelY
  2876. * @type Number
  2877. */
  2878. Object.defineProperty(TouchInput, 'wheelY', {
  2879. get: function() {
  2880. return this._wheelY;
  2881. },
  2882. configurable: true
  2883. });
  2884.  
  2885. /**
  2886. * [read-only] The x coordinate on the canvas area of the latest touch event.
  2887. *
  2888. * @static
  2889. * @property x
  2890. * @type Number
  2891. */
  2892. Object.defineProperty(TouchInput, 'x', {
  2893. get: function() {
  2894. return this._x;
  2895. },
  2896. configurable: true
  2897. });
  2898.  
  2899. /**
  2900. * [read-only] The y coordinate on the canvas area of the latest touch event.
  2901. *
  2902. * @static
  2903. * @property y
  2904. * @type Number
  2905. */
  2906. Object.defineProperty(TouchInput, 'y', {
  2907. get: function() {
  2908. return this._y;
  2909. },
  2910. configurable: true
  2911. });
  2912.  
  2913. /**
  2914. * [read-only] The time of the last input in milliseconds.
  2915. *
  2916. * @static
  2917. * @property date
  2918. * @type Number
  2919. */
  2920. Object.defineProperty(TouchInput, 'date', {
  2921. get: function() {
  2922. return this._date;
  2923. },
  2924. configurable: true
  2925. });
  2926.  
  2927. /**
  2928. * @static
  2929. * @method _setupEventHandlers
  2930. * @private
  2931. */
  2932. TouchInput._setupEventHandlers = function() {
  2933. document.addEventListener('mousedown', this._onMouseDown.bind(this));
  2934. document.addEventListener('mousemove', this._onMouseMove.bind(this));
  2935. document.addEventListener('mouseup', this._onMouseUp.bind(this));
  2936. document.addEventListener('wheel', this._onWheel.bind(this));
  2937. document.addEventListener('touchstart', this._onTouchStart.bind(this));
  2938. document.addEventListener('touchmove', this._onTouchMove.bind(this));
  2939. document.addEventListener('touchend', this._onTouchEnd.bind(this));
  2940. document.addEventListener('touchcancel', this._onTouchCancel.bind(this));
  2941. document.addEventListener('pointerdown', this._onPointerDown.bind(this));
  2942. };
  2943.  
  2944. /**
  2945. * @static
  2946. * @method _onMouseDown
  2947. * @param {MouseEvent} event
  2948. * @private
  2949. */
  2950. TouchInput._onMouseDown = function(event) {
  2951. if (event.button === 0) {
  2952. this._onLeftButtonDown(event);
  2953. } else if (event.button === 1) {
  2954. this._onMiddleButtonDown(event);
  2955. } else if (event.button === 2) {
  2956. this._onRightButtonDown(event);
  2957. }
  2958. };
  2959.  
  2960. /**
  2961. * @static
  2962. * @method _onLeftButtonDown
  2963. * @param {MouseEvent} event
  2964. * @private
  2965. */
  2966. TouchInput._onLeftButtonDown = function(event) {
  2967. var x = Graphics.pageToCanvasX(event.pageX);
  2968. var y = Graphics.pageToCanvasY(event.pageY);
  2969. if (Graphics.isInsideCanvas(x, y)) {
  2970. this._mousePressed = true;
  2971. this._pressedTime = 0;
  2972. this._onTrigger(x, y);
  2973. }
  2974. };
  2975.  
  2976. /**
  2977. * @static
  2978. * @method _onMiddleButtonDown
  2979. * @param {MouseEvent} event
  2980. * @private
  2981. */
  2982. TouchInput._onMiddleButtonDown = function(event) {
  2983. };
  2984.  
  2985. /**
  2986. * @static
  2987. * @method _onRightButtonDown
  2988. * @param {MouseEvent} event
  2989. * @private
  2990. */
  2991. TouchInput._onRightButtonDown = function(event) {
  2992. var x = Graphics.pageToCanvasX(event.pageX);
  2993. var y = Graphics.pageToCanvasY(event.pageY);
  2994. if (Graphics.isInsideCanvas(x, y)) {
  2995. this._onCancel(x, y);
  2996. }
  2997. };
  2998.  
  2999. /**
  3000. * @static
  3001. * @method _onMouseMove
  3002. * @param {MouseEvent} event
  3003. * @private
  3004. */
  3005. TouchInput._onMouseMove = function(event) {
  3006. if (this._mousePressed) {
  3007. var x = Graphics.pageToCanvasX(event.pageX);
  3008. var y = Graphics.pageToCanvasY(event.pageY);
  3009. this._onMove(x, y);
  3010. }
  3011. };
  3012.  
  3013. /**
  3014. * @static
  3015. * @method _onMouseUp
  3016. * @param {MouseEvent} event
  3017. * @private
  3018. */
  3019. TouchInput._onMouseUp = function(event) {
  3020. if (event.button === 0) {
  3021. var x = Graphics.pageToCanvasX(event.pageX);
  3022. var y = Graphics.pageToCanvasY(event.pageY);
  3023. this._mousePressed = false;
  3024. this._onRelease(x, y);
  3025. }
  3026. };
  3027.  
  3028. /**
  3029. * @static
  3030. * @method _onWheel
  3031. * @param {WheelEvent} event
  3032. * @private
  3033. */
  3034. TouchInput._onWheel = function(event) {
  3035. this._events.wheelX += event.deltaX;
  3036. this._events.wheelY += event.deltaY;
  3037. event.preventDefault();
  3038. };
  3039.  
  3040. /**
  3041. * @static
  3042. * @method _onTouchStart
  3043. * @param {TouchEvent} event
  3044. * @private
  3045. */
  3046. TouchInput._onTouchStart = function(event) {
  3047. for (var i = 0; i < event.changedTouches.length; i++) {
  3048. var touch = event.changedTouches[i];
  3049. var x = Graphics.pageToCanvasX(touch.pageX);
  3050. var y = Graphics.pageToCanvasY(touch.pageY);
  3051. if (Graphics.isInsideCanvas(x, y)) {
  3052. this._screenPressed = true;
  3053. this._pressedTime = 0;
  3054. if (event.touches.length >= 2) {
  3055. this._onCancel(x, y);
  3056. } else {
  3057. this._onTrigger(x, y);
  3058. }
  3059. event.preventDefault();
  3060. }
  3061. }
  3062. if (window.cordova || window.navigator.standalone) {
  3063. event.preventDefault();
  3064. }
  3065. };
  3066.  
  3067. /**
  3068. * @static
  3069. * @method _onTouchMove
  3070. * @param {TouchEvent} event
  3071. * @private
  3072. */
  3073. TouchInput._onTouchMove = function(event) {
  3074. for (var i = 0; i < event.changedTouches.length; i++) {
  3075. var touch = event.changedTouches[i];
  3076. var x = Graphics.pageToCanvasX(touch.pageX);
  3077. var y = Graphics.pageToCanvasY(touch.pageY);
  3078. this._onMove(x, y);
  3079. }
  3080. };
  3081.  
  3082. /**
  3083. * @static
  3084. * @method _onTouchEnd
  3085. * @param {TouchEvent} event
  3086. * @private
  3087. */
  3088. TouchInput._onTouchEnd = function(event) {
  3089. for (var i = 0; i < event.changedTouches.length; i++) {
  3090. var touch = event.changedTouches[i];
  3091. var x = Graphics.pageToCanvasX(touch.pageX);
  3092. var y = Graphics.pageToCanvasY(touch.pageY);
  3093. this._screenPressed = false;
  3094. this._onRelease(x, y);
  3095. }
  3096. };
  3097.  
  3098. /**
  3099. * @static
  3100. * @method _onTouchCancel
  3101. * @param {TouchEvent} event
  3102. * @private
  3103. */
  3104. TouchInput._onTouchCancel = function(event) {
  3105. this._screenPressed = false;
  3106. };
  3107.  
  3108. /**
  3109. * @static
  3110. * @method _onPointerDown
  3111. * @param {PointerEvent} event
  3112. * @private
  3113. */
  3114. TouchInput._onPointerDown = function(event) {
  3115. if (event.pointerType === 'touch' && !event.isPrimary) {
  3116. var x = Graphics.pageToCanvasX(event.pageX);
  3117. var y = Graphics.pageToCanvasY(event.pageY);
  3118. if (Graphics.isInsideCanvas(x, y)) {
  3119. // For Microsoft Edge
  3120. this._onCancel(x, y);
  3121. event.preventDefault();
  3122. }
  3123. }
  3124. };
  3125.  
  3126. /**
  3127. * @static
  3128. * @method _onTrigger
  3129. * @param {Number} x
  3130. * @param {Number} y
  3131. * @private
  3132. */
  3133. TouchInput._onTrigger = function(x, y) {
  3134. this._events.triggered = true;
  3135. this._x = x;
  3136. this._y = y;
  3137. this._date = Date.now();
  3138. };
  3139.  
  3140. /**
  3141. * @static
  3142. * @method _onCancel
  3143. * @param {Number} x
  3144. * @param {Number} y
  3145. * @private
  3146. */
  3147. TouchInput._onCancel = function(x, y) {
  3148. this._events.cancelled = true;
  3149. this._x = x;
  3150. this._y = y;
  3151. };
  3152.  
  3153. /**
  3154. * @static
  3155. * @method _onMove
  3156. * @param {Number} x
  3157. * @param {Number} y
  3158. * @private
  3159. */
  3160. TouchInput._onMove = function(x, y) {
  3161. this._events.moved = true;
  3162. this._x = x;
  3163. this._y = y;
  3164. };
  3165.  
  3166. /**
  3167. * @static
  3168. * @method _onRelease
  3169. * @param {Number} x
  3170. * @param {Number} y
  3171. * @private
  3172. */
  3173. TouchInput._onRelease = function(x, y) {
  3174. this._events.released = true;
  3175. this._x = x;
  3176. this._y = y;
  3177. };
  3178.  
  3179. //-----------------------------------------------------------------------------
  3180. /**
  3181. * The basic object that is rendered to the game screen.
  3182. *
  3183. * @class Sprite
  3184. * @constructor
  3185. * @param {Bitmap} bitmap The image for the sprite
  3186. */
  3187. function Sprite() {
  3188. this.initialize.apply(this, arguments);
  3189. }
  3190.  
  3191. Sprite.prototype = Object.create(PIXI.Sprite.prototype);
  3192. Sprite.prototype.constructor = Sprite;
  3193.  
  3194. Sprite.prototype.initialize = function(bitmap) {
  3195. var texture = new PIXI.Texture(new PIXI.BaseTexture());
  3196.  
  3197. PIXI.Sprite.call(this, texture);
  3198.  
  3199. this._bitmap = null;
  3200. this._frame = new Rectangle();
  3201. this._realFrame = new Rectangle();
  3202. this._offset = new Point();
  3203. this._blendColor = [0, 0, 0, 0];
  3204. this._colorTone = [0, 0, 0, 0];
  3205. this._canvas = null;
  3206. this._context = null;
  3207. this._tintTexture = null;
  3208.  
  3209. this.spriteId = Sprite._counter++;
  3210. this.opaque = false;
  3211.  
  3212. this.bitmap = bitmap;
  3213. };
  3214.  
  3215. // Number of the created objects.
  3216. Sprite._counter = 0;
  3217.  
  3218. /**
  3219. * The image for the sprite.
  3220. *
  3221. * @property bitmap
  3222. * @type Bitmap
  3223. */
  3224. Object.defineProperty(Sprite.prototype, 'bitmap', {
  3225. get: function() {
  3226. return this._bitmap;
  3227. },
  3228. set: function(value) {
  3229. if (this._bitmap !== value) {
  3230. this._bitmap = value;
  3231. if (this._bitmap) {
  3232. this.setFrame(0, 0, 0, 0);
  3233. this._bitmap.addLoadListener(this._onBitmapLoad.bind(this));
  3234. } else {
  3235. this.texture.setFrame(Rectangle.emptyRectangle);
  3236. }
  3237. }
  3238. },
  3239. configurable: true
  3240. });
  3241.  
  3242. /**
  3243. * The width of the sprite without the scale.
  3244. *
  3245. * @property width
  3246. * @type Number
  3247. */
  3248. Object.defineProperty(Sprite.prototype, 'width', {
  3249. get: function() {
  3250. return this._frame.width;
  3251. },
  3252. set: function(value) {
  3253. this._frame.width = value;
  3254. this._refresh();
  3255. },
  3256. configurable: true
  3257. });
  3258.  
  3259. /**
  3260. * The height of the sprite without the scale.
  3261. *
  3262. * @property height
  3263. * @type Number
  3264. */
  3265. Object.defineProperty(Sprite.prototype, 'height', {
  3266. get: function() {
  3267. return this._frame.height;
  3268. },
  3269. set: function(value) {
  3270. this._frame.height = value;
  3271. this._refresh();
  3272. },
  3273. configurable: true
  3274. });
  3275.  
  3276. /**
  3277. * The opacity of the sprite (0 to 255).
  3278. *
  3279. * @property opacity
  3280. * @type Number
  3281. */
  3282. Object.defineProperty(Sprite.prototype, 'opacity', {
  3283. get: function() {
  3284. return this.alpha * 255;
  3285. },
  3286. set: function(value) {
  3287. this.alpha = value.clamp(0, 255) / 255;
  3288. },
  3289. configurable: true
  3290. });
  3291.  
  3292. /**
  3293. * Updates the sprite for each frame.
  3294. *
  3295. * @method update
  3296. */
  3297. Sprite.prototype.update = function() {
  3298. this.children.forEach(function(child) {
  3299. if (child.update) {
  3300. child.update();
  3301. }
  3302. });
  3303. };
  3304.  
  3305. /**
  3306. * Sets the x and y at once.
  3307. *
  3308. * @method move
  3309. * @param {Number} x The x coordinate of the sprite
  3310. * @param {Number} y The y coordinate of the sprite
  3311. */
  3312. Sprite.prototype.move = function(x, y) {
  3313. this.x = x;
  3314. this.y = y;
  3315. };
  3316.  
  3317. /**
  3318. * Sets the rectagle of the bitmap that the sprite displays.
  3319. *
  3320. * @method setFrame
  3321. * @param {Number} x The x coordinate of the frame
  3322. * @param {Number} y The y coordinate of the frame
  3323. * @param {Number} width The width of the frame
  3324. * @param {Number} height The height of the frame
  3325. */
  3326. Sprite.prototype.setFrame = function(x, y, width, height) {
  3327. var frame = this._frame;
  3328. if (x !== frame.x || y !== frame.y ||
  3329. width !== frame.width || height !== frame.height) {
  3330. frame.x = x;
  3331. frame.y = y;
  3332. frame.width = width;
  3333. frame.height = height;
  3334. this._refresh();
  3335. }
  3336. };
  3337.  
  3338. /**
  3339. * Gets the blend color for the sprite.
  3340. *
  3341. * @method getBlendColor
  3342. * @return {Array} The blend color [r, g, b, a]
  3343. */
  3344. Sprite.prototype.getBlendColor = function() {
  3345. return this._blendColor.clone();
  3346. };
  3347.  
  3348. /**
  3349. * Sets the blend color for the sprite.
  3350. *
  3351. * @method setBlendColor
  3352. * @param {Array} color The blend color [r, g, b, a]
  3353. */
  3354. Sprite.prototype.setBlendColor = function(color) {
  3355. if (!(color instanceof Array)) {
  3356. throw new Error('Argument must be an array');
  3357. }
  3358. if (!this._blendColor.equals(color)) {
  3359. this._blendColor = color.clone();
  3360. this._refresh();
  3361. }
  3362. };
  3363.  
  3364. /**
  3365. * Gets the color tone for the sprite.
  3366. *
  3367. * @method getColorTone
  3368. * @return {Array} The color tone [r, g, b, gray]
  3369. */
  3370. Sprite.prototype.getColorTone = function() {
  3371. return this._colorTone.clone();
  3372. };
  3373.  
  3374. /**
  3375. * Sets the color tone for the sprite.
  3376. *
  3377. * @method setColorTone
  3378. * @param {Array} tone The color tone [r, g, b, gray]
  3379. */
  3380. Sprite.prototype.setColorTone = function(tone) {
  3381. if (!(tone instanceof Array)) {
  3382. throw new Error('Argument must be an array');
  3383. }
  3384. if (!this._colorTone.equals(tone)) {
  3385. this._colorTone = tone.clone();
  3386. this._refresh();
  3387. }
  3388. };
  3389.  
  3390. /**
  3391. * @method _onBitmapLoad
  3392. * @private
  3393. */
  3394. Sprite.prototype._onBitmapLoad = function() {
  3395. if (this._frame.width === 0 && this._frame.height === 0) {
  3396. this._frame.width = this._bitmap.width;
  3397. this._frame.height = this._bitmap.height;
  3398. }
  3399. this._refresh();
  3400. };
  3401.  
  3402. /**
  3403. * @method _refresh
  3404. * @private
  3405. */
  3406. Sprite.prototype._refresh = function() {
  3407. var frameX = Math.floor(this._frame.x);
  3408. var frameY = Math.floor(this._frame.y);
  3409. var frameW = Math.floor(this._frame.width);
  3410. var frameH = Math.floor(this._frame.height);
  3411. var bitmapW = this._bitmap ? this._bitmap.width : 0;
  3412. var bitmapH = this._bitmap ? this._bitmap.height : 0;
  3413. var realX = frameX.clamp(0, bitmapW);
  3414. var realY = frameY.clamp(0, bitmapH);
  3415. var realW = (frameW - realX + frameX).clamp(0, bitmapW - realX);
  3416. var realH = (frameH - realY + frameY).clamp(0, bitmapH - realY);
  3417.  
  3418. this._realFrame.x = realX;
  3419. this._realFrame.y = realY;
  3420. this._realFrame.width = realW;
  3421. this._realFrame.height = realH;
  3422. this._offset.x = realX - frameX;
  3423. this._offset.y = realY - frameY;
  3424.  
  3425. if (realW > 0 && realH > 0) {
  3426. if (this._needsTint()) {
  3427. this._createTinter(realW, realH);
  3428. this._executeTint(realX, realY, realW, realH);
  3429. this._tintTexture.dirty();
  3430. this.texture.baseTexture = this._tintTexture;
  3431. this.texture.setFrame(new Rectangle(0, 0, realW, realH));
  3432. } else {
  3433. if (this._bitmap) {
  3434. this.texture.baseTexture = this._bitmap.baseTexture;
  3435. }
  3436. this.texture.setFrame(this._realFrame);
  3437. }
  3438. } else if (this._bitmap) {
  3439. this.texture.setFrame(Rectangle.emptyRectangle);
  3440. } else {
  3441. this.texture.trim = this._frame;
  3442. this.texture.setFrame(this._frame);
  3443. this.texture.trim = null;
  3444. }
  3445. };
  3446.  
  3447. /**
  3448. * @method _isInBitmapRect
  3449. * @param {Number} x
  3450. * @param {Number} y
  3451. * @param {Number} w
  3452. * @param {Number} h
  3453. * @return {Boolean}
  3454. * @private
  3455. */
  3456. Sprite.prototype._isInBitmapRect = function(x, y, w, h) {
  3457. return (this._bitmap && x + w > 0 && y + h > 0 &&
  3458. x < this._bitmap.width && y < this._bitmap.height);
  3459. };
  3460.  
  3461. /**
  3462. * @method _needsTint
  3463. * @return {Boolean}
  3464. * @private
  3465. */
  3466. Sprite.prototype._needsTint = function() {
  3467. var tone = this._colorTone;
  3468. return tone[0] || tone[1] || tone[2] || tone[3] || this._blendColor[3] > 0;
  3469. };
  3470.  
  3471. /**
  3472. * @method _createTinter
  3473. * @param {Number} w
  3474. * @param {Number} h
  3475. * @private
  3476. */
  3477. Sprite.prototype._createTinter = function(w, h) {
  3478. if (!this._canvas) {
  3479. this._canvas = document.createElement('canvas');
  3480. this._context = this._canvas.getContext('2d');
  3481. }
  3482.  
  3483. this._canvas.width = w;
  3484. this._canvas.height = h;
  3485.  
  3486. if (!this._tintTexture) {
  3487. this._tintTexture = new PIXI.BaseTexture(this._canvas);
  3488. }
  3489.  
  3490. this._tintTexture.width = w;
  3491. this._tintTexture.height = h;
  3492. this._tintTexture.scaleMode = this._bitmap.baseTexture.scaleMode;
  3493. };
  3494.  
  3495. /**
  3496. * @method _executeTint
  3497. * @param {Number} x
  3498. * @param {Number} y
  3499. * @param {Number} w
  3500. * @param {Number} h
  3501. * @private
  3502. */
  3503. Sprite.prototype._executeTint = function(x, y, w, h) {
  3504. var context = this._context;
  3505. var tone = this._colorTone;
  3506. var color = this._blendColor;
  3507.  
  3508. context.globalCompositeOperation = 'copy';
  3509. context.drawImage(this._bitmap.canvas, x, y, w, h, 0, 0, w, h);
  3510.  
  3511. if (Graphics.canUseSaturationBlend()) {
  3512. var gray = Math.max(0, tone[3]);
  3513. context.globalCompositeOperation = 'saturation';
  3514. context.fillStyle = 'rgba(255,255,255,' + gray / 255 + ')';
  3515. context.fillRect(0, 0, w, h);
  3516. }
  3517.  
  3518. var r1 = Math.max(0, tone[0]);
  3519. var g1 = Math.max(0, tone[1]);
  3520. var b1 = Math.max(0, tone[2]);
  3521. context.globalCompositeOperation = 'lighter';
  3522. context.fillStyle = Utils.rgbToCssColor(r1, g1, b1);
  3523. context.fillRect(0, 0, w, h);
  3524.  
  3525. if (Graphics.canUseDifferenceBlend()) {
  3526. context.globalCompositeOperation = 'difference';
  3527. context.fillStyle = 'white';
  3528. context.fillRect(0, 0, w, h);
  3529.  
  3530. var r2 = Math.max(0, -tone[0]);
  3531. var g2 = Math.max(0, -tone[1]);
  3532. var b2 = Math.max(0, -tone[2]);
  3533. context.globalCompositeOperation = 'lighter';
  3534. context.fillStyle = Utils.rgbToCssColor(r2, g2, b2);
  3535. context.fillRect(0, 0, w, h);
  3536.  
  3537. context.globalCompositeOperation = 'difference';
  3538. context.fillStyle = 'white';
  3539. context.fillRect(0, 0, w, h);
  3540. }
  3541.  
  3542. var r3 = Math.max(0, color[0]);
  3543. var g3 = Math.max(0, color[1]);
  3544. var b3 = Math.max(0, color[2]);
  3545. var a3 = Math.max(0, color[3]);
  3546. context.globalCompositeOperation = 'source-atop';
  3547. context.fillStyle = Utils.rgbToCssColor(r3, g3, b3);
  3548. context.globalAlpha = a3 / 255;
  3549. context.fillRect(0, 0, w, h);
  3550.  
  3551. context.globalCompositeOperation = 'destination-in';
  3552. context.globalAlpha = 1;
  3553. context.drawImage(this._bitmap.canvas, x, y, w, h, 0, 0, w, h);
  3554. };
  3555.  
  3556. /**
  3557. * @method updateTransform
  3558. * @private
  3559. */
  3560. Sprite.prototype.updateTransform = function() {
  3561. PIXI.Sprite.prototype.updateTransform.call(this);
  3562. this.worldTransform.tx += this._offset.x;
  3563. this.worldTransform.ty += this._offset.y;
  3564. };
  3565.  
  3566. /**
  3567. * @method _renderCanvas
  3568. * @param {Object} renderSession
  3569. * @private
  3570. */
  3571. Sprite.prototype._renderCanvas = function(renderSession) {
  3572. if (this.visible && this.alpha > 0) {
  3573. if (this.texture.crop.width <= 0 || this.texture.crop.height <= 0) {
  3574. if (this._mask) {
  3575. renderSession.maskManager.pushMask(this._mask, renderSession);
  3576. }
  3577. for (var i = 0, j = this.children.length; i < j; i++) {
  3578. this.children[i]._renderCanvas(renderSession);
  3579. }
  3580. if (this._mask) {
  3581. renderSession.maskManager.popMask(renderSession);
  3582. }
  3583. } else {
  3584. PIXI.Sprite.prototype._renderCanvas.call(this, renderSession);
  3585. }
  3586. }
  3587. };
  3588.  
  3589. /**
  3590. * @method _renderWebGL
  3591. * @param {Object} renderSession
  3592. * @private
  3593. */
  3594. Sprite.prototype._renderWebGL = function(renderSession) {
  3595. if (this.visible && this.alpha > 0) {
  3596. var spriteBatch = renderSession.spriteBatch;
  3597. if (this._filters) {
  3598. spriteBatch.flush();
  3599. renderSession.filterManager.pushFilter(this._filterBlock);
  3600. if (this.opaque) {
  3601. // Required for a bug in Firefox on Windows
  3602. renderSession.gl.clearColor(0, 0, 0, 1);
  3603. renderSession.gl.clear(renderSession.gl.COLOR_BUFFER_BIT);
  3604. }
  3605. }
  3606. if (this._mask) {
  3607. spriteBatch.stop();
  3608. renderSession.maskManager.pushMask(this.mask, renderSession);
  3609. spriteBatch.start();
  3610. }
  3611. spriteBatch.render(this);
  3612. for (var i = 0, j = this.children.length; i < j; i++) {
  3613. this.children[i]._renderWebGL(renderSession);
  3614. }
  3615. if (this._mask) {
  3616. spriteBatch.stop();
  3617. renderSession.maskManager.popMask(this._mask, renderSession);
  3618. spriteBatch.start();
  3619. }
  3620. if (this._filters) {
  3621. spriteBatch.stop();
  3622. renderSession.filterManager.popFilter();
  3623. spriteBatch.start();
  3624. }
  3625. }
  3626. };
  3627.  
  3628. // The important members from Pixi.js
  3629.  
  3630. /**
  3631. * The visibility of the sprite.
  3632. *
  3633. * @property visible
  3634. * @type Boolean
  3635. */
  3636.  
  3637. /**
  3638. * The x coordinate of the sprite.
  3639. *
  3640. * @property x
  3641. * @type Number
  3642. */
  3643.  
  3644. /**
  3645. * The y coordinate of the sprite.
  3646. *
  3647. * @property y
  3648. * @type Number
  3649. */
  3650.  
  3651. /**
  3652. * The origin point of the sprite. (0,0) to (1,1).
  3653. *
  3654. * @property anchor
  3655. * @type Point
  3656. */
  3657.  
  3658. /**
  3659. * The scale factor of the sprite.
  3660. *
  3661. * @property scale
  3662. * @type Point
  3663. */
  3664.  
  3665. /**
  3666. * The rotation of the sprite in radians.
  3667. *
  3668. * @property rotation
  3669. * @type Number
  3670. */
  3671.  
  3672. /**
  3673. * The blend mode to be applied to the sprite.
  3674. *
  3675. * @property blendMode
  3676. * @type Number
  3677. */
  3678.  
  3679. /**
  3680. * Sets the filters for the sprite.
  3681. *
  3682. * @property filters
  3683. * @type Array
  3684. */
  3685.  
  3686. /**
  3687. * [read-only] The array of children of the sprite.
  3688. *
  3689. * @property children
  3690. * @type Array
  3691. */
  3692.  
  3693. /**
  3694. * [read-only] The object that contains the sprite.
  3695. *
  3696. * @property parent
  3697. * @type Object
  3698. */
  3699.  
  3700. /**
  3701. * Adds a child to the container.
  3702. *
  3703. * @method addChild
  3704. * @param {Object} child The child to add
  3705. * @return {Object} The child that was added
  3706. */
  3707.  
  3708. /**
  3709. * Adds a child to the container at a specified index.
  3710. *
  3711. * @method addChildAt
  3712. * @param {Object} child The child to add
  3713. * @param {Number} index The index to place the child in
  3714. * @return {Object} The child that was added
  3715. */
  3716.  
  3717. /**
  3718. * Removes a child from the container.
  3719. *
  3720. * @method removeChild
  3721. * @param {Object} child The child to remove
  3722. * @return {Object} The child that was removed
  3723. */
  3724.  
  3725. /**
  3726. * Removes a child from the specified index position.
  3727. *
  3728. * @method removeChildAt
  3729. * @param {Number} index The index to get the child from
  3730. * @return {Object} The child that was removed
  3731. */
  3732.  
  3733. //-----------------------------------------------------------------------------
  3734. /**
  3735. * The tilemap which displays 2D tile-based game map.
  3736. *
  3737. * @class Tilemap
  3738. * @constructor
  3739. */
  3740. function Tilemap() {
  3741. this.initialize.apply(this, arguments);
  3742. }
  3743.  
  3744. Tilemap.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  3745. Tilemap.prototype.constructor = Tilemap;
  3746.  
  3747. Tilemap.prototype.initialize = function() {
  3748. PIXI.DisplayObjectContainer.call(this);
  3749.  
  3750. this._margin = 20;
  3751. this._width = Graphics.width + this._margin * 2;
  3752. this._height = Graphics.height + this._margin * 2;
  3753. this._tileWidth = 48;
  3754. this._tileHeight = 48;
  3755. this._mapWidth = 0;
  3756. this._mapHeight = 0;
  3757. this._mapData = null;
  3758. this._layerWidth = 0;
  3759. this._layerHeight = 0;
  3760. this._lastTiles = [];
  3761.  
  3762. /**
  3763. * The bitmaps used as a tileset.
  3764. *
  3765. * @property bitmaps
  3766. * @type Array
  3767. */
  3768. this.bitmaps = [];
  3769.  
  3770. /**
  3771. * The origin point of the tilemap for scrolling.
  3772. *
  3773. * @property origin
  3774. * @type Point
  3775. */
  3776. this.origin = new Point();
  3777.  
  3778. /**
  3779. * The tileset flags.
  3780. *
  3781. * @property flags
  3782. * @type Array
  3783. */
  3784. this.flags = [];
  3785.  
  3786. /**
  3787. * The animation count for autotiles.
  3788. *
  3789. * @property animationCount
  3790. * @type Number
  3791. */
  3792. this.animationCount = 0;
  3793.  
  3794. /**
  3795. * Whether the tilemap loops horizontal.
  3796. *
  3797. * @property horizontalWrap
  3798. * @type Boolean
  3799. */
  3800. this.horizontalWrap = false;
  3801.  
  3802. /**
  3803. * Whether the tilemap loops vertical.
  3804. *
  3805. * @property verticalWrap
  3806. * @type Boolean
  3807. */
  3808. this.verticalWrap = false;
  3809.  
  3810. this._createLayers();
  3811. this.refresh();
  3812. };
  3813.  
  3814. /**
  3815. * The width of the screen in pixels.
  3816. *
  3817. * @property width
  3818. * @type Number
  3819. */
  3820. Object.defineProperty(Tilemap.prototype, 'width', {
  3821. get: function() {
  3822. return this._width;
  3823. },
  3824. set: function(value) {
  3825. if (this._width !== value) {
  3826. this._width = value;
  3827. this._createLayers();
  3828. }
  3829. }
  3830. });
  3831.  
  3832. /**
  3833. * The height of the screen in pixels.
  3834. *
  3835. * @property height
  3836. * @type Number
  3837. */
  3838. Object.defineProperty(Tilemap.prototype, 'height', {
  3839. get: function() {
  3840. return this._height;
  3841. },
  3842. set: function(value) {
  3843. if (this._height !== value) {
  3844. this._height = value;
  3845. this._createLayers();
  3846. }
  3847. }
  3848. });
  3849.  
  3850. /**
  3851. * The width of a tile in pixels.
  3852. *
  3853. * @property tileWidth
  3854. * @type Number
  3855. */
  3856. Object.defineProperty(Tilemap.prototype, 'tileWidth', {
  3857. get: function() {
  3858. return this._tileWidth;
  3859. },
  3860. set: function(value) {
  3861. if (this._tileWidth !== value) {
  3862. this._tileWidth = value;
  3863. this._createLayers();
  3864. }
  3865. }
  3866. });
  3867.  
  3868. /**
  3869. * The height of a tile in pixels.
  3870. *
  3871. * @property tileHeight
  3872. * @type Number
  3873. */
  3874. Object.defineProperty(Tilemap.prototype, 'tileHeight', {
  3875. get: function() {
  3876. return this._tileHeight;
  3877. },
  3878. set: function(value) {
  3879. if (this._tileHeight !== value) {
  3880. this._tileHeight = value;
  3881. this._createLayers();
  3882. }
  3883. }
  3884. });
  3885.  
  3886. /**
  3887. * Sets the tilemap data.
  3888. *
  3889. * @method setData
  3890. * @param {Number} width The width of the map in number of tiles
  3891. * @param {Number} height The height of the map in number of tiles
  3892. * @param {Array} data The one dimensional array for the map data
  3893. */
  3894. Tilemap.prototype.setData = function(width, height, data) {
  3895. this._mapWidth = width;
  3896. this._mapHeight = height;
  3897. this._mapData = data;
  3898. };
  3899.  
  3900. /**
  3901. * Checks whether the tileset is ready to render.
  3902. *
  3903. * @method isReady
  3904. * @type Boolean
  3905. * @return {Boolean} True if the tilemap is ready
  3906. */
  3907. Tilemap.prototype.isReady = function() {
  3908. for (var i = 0; i < this.bitmaps.length; i++) {
  3909. if (this.bitmaps[i] && !this.bitmaps[i].isReady()) {
  3910. return false;
  3911. }
  3912. }
  3913. return true;
  3914. };
  3915.  
  3916. /**
  3917. * Updates the tilemap for each frame.
  3918. *
  3919. * @method update
  3920. */
  3921. Tilemap.prototype.update = function() {
  3922. this.animationCount++;
  3923. this.children.forEach(function(child) {
  3924. if (child.update) {
  3925. child.update();
  3926. }
  3927. });
  3928. };
  3929.  
  3930. /**
  3931. * Forces to repaint the entire tilemap.
  3932. *
  3933. * @method refresh
  3934. */
  3935. Tilemap.prototype.refresh = function() {
  3936. this._lastTiles.length = 0;
  3937. };
  3938.  
  3939. /**
  3940. * @method updateTransform
  3941. * @private
  3942. */
  3943. Tilemap.prototype.updateTransform = function() {
  3944. var ox = Math.floor(this.origin.x);
  3945. var oy = Math.floor(this.origin.y);
  3946. var startX = Math.floor((ox - this._margin) / this._tileWidth);
  3947. var startY = Math.floor((oy - this._margin) / this._tileHeight);
  3948. this._updateLayerPositions(startX, startY);
  3949. this._paintAllTiles(startX, startY);
  3950. this._sortChildren();
  3951. PIXI.DisplayObjectContainer.prototype.updateTransform.call(this);
  3952. };
  3953.  
  3954. /**
  3955. * @method _createLayers
  3956. * @private
  3957. */
  3958. Tilemap.prototype._createLayers = function() {
  3959. var width = this._width;
  3960. var height = this._height;
  3961. var margin = this._margin;
  3962. var tileCols = Math.ceil(width / this._tileWidth) + 1;
  3963. var tileRows = Math.ceil(height / this._tileHeight) + 1;
  3964. var layerWidth = tileCols * this._tileWidth;
  3965. var layerHeight = tileRows * this._tileHeight;
  3966. this._lowerBitmap = new Bitmap(layerWidth, layerHeight);
  3967. this._upperBitmap = new Bitmap(layerWidth, layerHeight);
  3968. this._layerWidth = layerWidth;
  3969. this._layerHeight = layerHeight;
  3970.  
  3971. /*
  3972. * Z coordinate:
  3973. *
  3974. * 0 : Lower tiles
  3975. * 1 : Lower characters
  3976. * 3 : Normal characters
  3977. * 4 : Upper tiles
  3978. * 5 : Upper characters
  3979. * 6 : Airship shadow
  3980. * 7 : Balloon
  3981. * 8 : Animation
  3982. * 9 : Destination
  3983. */
  3984.  
  3985. this._lowerLayer = new Sprite();
  3986. this._lowerLayer.move(-margin, -margin, width, height);
  3987. this._lowerLayer.z = 0;
  3988.  
  3989. this._upperLayer = new Sprite();
  3990. this._upperLayer.move(-margin, -margin, width, height);
  3991. this._upperLayer.z = 4;
  3992.  
  3993. for (var i = 0; i < 4; i++) {
  3994. this._lowerLayer.addChild(new Sprite(this._lowerBitmap));
  3995. this._upperLayer.addChild(new Sprite(this._upperBitmap));
  3996. }
  3997.  
  3998. this.addChild(this._lowerLayer);
  3999. this.addChild(this._upperLayer);
  4000. };
  4001.  
  4002. /**
  4003. * @method _updateLayerPositions
  4004. * @param {Number} startX
  4005. * @param {Number} startY
  4006. * @private
  4007. */
  4008. Tilemap.prototype._updateLayerPositions = function(startX, startY) {
  4009. var m = this._margin;
  4010. var ox = Math.floor(this.origin.x);
  4011. var oy = Math.floor(this.origin.y);
  4012. var x2 = (ox - m).mod(this._layerWidth);
  4013. var y2 = (oy - m).mod(this._layerHeight);
  4014. var w1 = this._layerWidth - x2;
  4015. var h1 = this._layerHeight - y2;
  4016. var w2 = this._width - w1;
  4017. var h2 = this._height - h1;
  4018.  
  4019. for (var i = 0; i < 2; i++) {
  4020. var children;
  4021. if (i === 0) {
  4022. children = this._lowerLayer.children;
  4023. } else {
  4024. children = this._upperLayer.children;
  4025. }
  4026. children[0].move(0, 0, w1, h1);
  4027. children[0].setFrame(x2, y2, w1, h1);
  4028. children[1].move(w1, 0, w2, h1);
  4029. children[1].setFrame(0, y2, w2, h1);
  4030. children[2].move(0, h1, w1, h2);
  4031. children[2].setFrame(x2, 0, w1, h2);
  4032. children[3].move(w1, h1, w2, h2);
  4033. children[3].setFrame(0, 0, w2, h2);
  4034. }
  4035. };
  4036.  
  4037. /**
  4038. * @method _paintAllTiles
  4039. * @param {Number} startX
  4040. * @param {Number} startY
  4041. * @private
  4042. */
  4043. Tilemap.prototype._paintAllTiles = function(startX, startY) {
  4044. var tileCols = Math.ceil(this._width / this._tileWidth) + 1;
  4045. var tileRows = Math.ceil(this._height / this._tileHeight) + 1;
  4046. for (var y = 0; y < tileRows; y++) {
  4047. for (var x = 0; x < tileCols; x++) {
  4048. this._paintTiles(startX, startY, x, y);
  4049. }
  4050. }
  4051. };
  4052.  
  4053. /**
  4054. * @method _paintTiles
  4055. * @param {Number} startX
  4056. * @param {Number} startY
  4057. * @param {Number} x
  4058. * @param {Number} y
  4059. * @private
  4060. */
  4061. Tilemap.prototype._paintTiles = function(startX, startY, x, y) {
  4062. var tableEdgeVirtualId = 10000;
  4063. var mx = startX + x;
  4064. var my = startY + y;
  4065. var dx = (mx * this._tileWidth).mod(this._layerWidth);
  4066. var dy = (my * this._tileHeight).mod(this._layerHeight);
  4067. var lx = dx / this._tileWidth;
  4068. var ly = dy / this._tileHeight;
  4069. var tileId0 = this._readMapData(mx, my, 0);
  4070. var tileId1 = this._readMapData(mx, my, 1);
  4071. var tileId2 = this._readMapData(mx, my, 2);
  4072. var tileId3 = this._readMapData(mx, my, 3);
  4073. var shadowBits = this._readMapData(mx, my, 4);
  4074. var upperTileId1 = this._readMapData(mx, my - 1, 1);
  4075. var lowerTiles = [];
  4076. var upperTiles = [];
  4077.  
  4078. if (this._isHigherTile(tileId0)) {
  4079. upperTiles.push(tileId0);
  4080. } else {
  4081. lowerTiles.push(tileId0);
  4082. }
  4083. if (this._isHigherTile(tileId1)) {
  4084. upperTiles.push(tileId1);
  4085. } else {
  4086. lowerTiles.push(tileId1);
  4087. }
  4088.  
  4089. lowerTiles.push(-shadowBits);
  4090.  
  4091. if (this._isTableTile(upperTileId1) && !this._isTableTile(tileId1)) {
  4092. if (!Tilemap.isShadowingTile(tileId0)) {
  4093. lowerTiles.push(tableEdgeVirtualId + upperTileId1);
  4094. }
  4095. }
  4096.  
  4097. if (this._isOverpassPosition(mx, my)) {
  4098. upperTiles.push(tileId2);
  4099. upperTiles.push(tileId3);
  4100. } else {
  4101. if (this._isHigherTile(tileId2)) {
  4102. upperTiles.push(tileId2);
  4103. } else {
  4104. lowerTiles.push(tileId2);
  4105. }
  4106. if (this._isHigherTile(tileId3)) {
  4107. upperTiles.push(tileId3);
  4108. } else {
  4109. lowerTiles.push(tileId3);
  4110. }
  4111. }
  4112.  
  4113. var count = 1000 + this.animationCount - my;
  4114. var frameUpdated = (count % 30 === 0);
  4115. this._animationFrame = Math.floor(count / 30);
  4116.  
  4117. var lastLowerTiles = this._readLastTiles(0, lx, ly);
  4118. if (!lowerTiles.equals(lastLowerTiles) ||
  4119. (Tilemap.isTileA1(tileId0) && frameUpdated)) {
  4120. this._lowerBitmap.clearRect(dx, dy, this._tileWidth, this._tileHeight);
  4121. for (var i = 0; i < lowerTiles.length; i++) {
  4122. var lowerTileId = lowerTiles[i];
  4123. if (lowerTileId < 0) {
  4124. this._drawShadow(this._lowerBitmap, shadowBits, dx, dy);
  4125. } else if (lowerTileId >= tableEdgeVirtualId) {
  4126. this._drawTableEdge(this._lowerBitmap, upperTileId1, dx, dy);
  4127. } else {
  4128. this._drawTile(this._lowerBitmap, lowerTileId, dx, dy);
  4129. }
  4130. }
  4131. this._writeLastTiles(0, lx, ly, lowerTiles);
  4132. }
  4133.  
  4134. var lastUpperTiles = this._readLastTiles(1, lx, ly);
  4135. if (!upperTiles.equals(lastUpperTiles)) {
  4136. this._upperBitmap.clearRect(dx, dy, this._tileWidth, this._tileHeight);
  4137. for (var j = 0; j < upperTiles.length; j++) {
  4138. this._drawTile(this._upperBitmap, upperTiles[j], dx, dy);
  4139. }
  4140. this._writeLastTiles(1, lx, ly, upperTiles);
  4141. }
  4142. };
  4143.  
  4144. /**
  4145. * @method _readLastTiles
  4146. * @param {Number} i
  4147. * @param {Number} x
  4148. * @param {Number} y
  4149. * @private
  4150. */
  4151. Tilemap.prototype._readLastTiles = function(i, x, y) {
  4152. var array1 = this._lastTiles[i];
  4153. if (array1) {
  4154. var array2 = array1[y];
  4155. if (array2) {
  4156. var tiles = array2[x];
  4157. if (tiles) {
  4158. return tiles;
  4159. }
  4160. }
  4161. }
  4162. return [];
  4163. };
  4164.  
  4165. /**
  4166. * @method _writeLastTiles
  4167. * @param {Number} i
  4168. * @param {Number} x
  4169. * @param {Number} y
  4170. * @param {Array} tiles
  4171. * @private
  4172. */
  4173. Tilemap.prototype._writeLastTiles = function(i, x, y, tiles) {
  4174. var array1 = this._lastTiles[i];
  4175. if (!array1) {
  4176. array1 = this._lastTiles[i] = [];
  4177. }
  4178. var array2 = array1[y];
  4179. if (!array2) {
  4180. array2 = array1[y] = [];
  4181. }
  4182. array2[x] = tiles;
  4183. };
  4184.  
  4185. /**
  4186. * @method _drawTile
  4187. * @param {Bitmap} bitmap
  4188. * @param {Number} tileId
  4189. * @param {Number} dx
  4190. * @param {Number} dy
  4191. * @private
  4192. */
  4193. Tilemap.prototype._drawTile = function(bitmap, tileId, dx, dy) {
  4194. if (Tilemap.isVisibleTile(tileId)) {
  4195. if (Tilemap.isAutotile(tileId)) {
  4196. this._drawAutotile(bitmap, tileId, dx, dy);
  4197. } else {
  4198. this._drawNormalTile(bitmap, tileId, dx, dy);
  4199. }
  4200. }
  4201. };
  4202.  
  4203. /**
  4204. * @method _drawNormalTile
  4205. * @param {Bitmap} bitmap
  4206. * @param {Number} tileId
  4207. * @param {Number} dx
  4208. * @param {Number} dy
  4209. * @private
  4210. */
  4211. Tilemap.prototype._drawNormalTile = function(bitmap, tileId, dx, dy) {
  4212. var setNumber = 0;
  4213.  
  4214. if (Tilemap.isTileA5(tileId)) {
  4215. setNumber = 4;
  4216. } else {
  4217. setNumber = 5 + Math.floor(tileId / 256);
  4218. }
  4219.  
  4220. var w = this._tileWidth;
  4221. var h = this._tileHeight;
  4222. var sx = (Math.floor(tileId / 128) % 2 * 8 + tileId % 8) * w;
  4223. var sy = (Math.floor(tileId % 256 / 8) % 16) * h;
  4224.  
  4225. var source = this.bitmaps[setNumber];
  4226. if (source) {
  4227. bitmap.blt(source, sx, sy, w, h, dx, dy, w, h);
  4228. }
  4229. };
  4230.  
  4231. /**
  4232. * @method _drawAutotile
  4233. * @param {Bitmap} bitmap
  4234. * @param {Number} tileId
  4235. * @param {Number} dx
  4236. * @param {Number} dy
  4237. * @private
  4238. */
  4239. Tilemap.prototype._drawAutotile = function(bitmap, tileId, dx, dy) {
  4240. var autotileTable = Tilemap.FLOOR_AUTOTILE_TABLE;
  4241. var kind = Tilemap.getAutotileKind(tileId);
  4242. var shape = Tilemap.getAutotileShape(tileId);
  4243. var tx = kind % 8;
  4244. var ty = Math.floor(kind / 8);
  4245. var bx = 0;
  4246. var by = 0;
  4247. var setNumber = 0;
  4248. var isTable = false;
  4249.  
  4250. if (Tilemap.isTileA1(tileId)) {
  4251. var waterSurfaceIndex = [0, 1, 2, 1][this._animationFrame % 4];
  4252. setNumber = 0;
  4253. if (kind === 0) {
  4254. bx = waterSurfaceIndex * 2;
  4255. by = 0;
  4256. } else if (kind === 1) {
  4257. bx = waterSurfaceIndex * 2;
  4258. by = 3;
  4259. } else if (kind === 2) {
  4260. bx = 6;
  4261. by = 0;
  4262. } else if (kind === 3) {
  4263. bx = 6;
  4264. by = 3;
  4265. } else {
  4266. bx = Math.floor(tx / 4) * 8;
  4267. by = ty * 6 + Math.floor(tx / 2) % 2 * 3;
  4268. if (kind % 2 === 0) {
  4269. bx += waterSurfaceIndex * 2;
  4270. }
  4271. else {
  4272. bx += 6;
  4273. autotileTable = Tilemap.WATERFALL_AUTOTILE_TABLE;
  4274. by += this._animationFrame % 3;
  4275. }
  4276. }
  4277. } else if (Tilemap.isTileA2(tileId)) {
  4278. setNumber = 1;
  4279. bx = tx * 2;
  4280. by = (ty - 2) * 3;
  4281. isTable = this._isTableTile(tileId);
  4282. } else if (Tilemap.isTileA3(tileId)) {
  4283. setNumber = 2;
  4284. bx = tx * 2;
  4285. by = (ty - 6) * 2;
  4286. autotileTable = Tilemap.WALL_AUTOTILE_TABLE;
  4287. } else if (Tilemap.isTileA4(tileId)) {
  4288. setNumber = 3;
  4289. bx = tx * 2;
  4290. by = Math.floor((ty - 10) * 2.5 + (ty % 2 === 1 ? 0.5 : 0));
  4291. if (ty % 2 === 1) {
  4292. autotileTable = Tilemap.WALL_AUTOTILE_TABLE;
  4293. }
  4294. }
  4295.  
  4296. var table = autotileTable[shape];
  4297. var source = this.bitmaps[setNumber];
  4298.  
  4299. if (table && source) {
  4300. var w1 = this._tileWidth / 2;
  4301. var h1 = this._tileHeight / 2;
  4302. for (var i = 0; i < 4; i++) {
  4303. var qsx = table[i][0];
  4304. var qsy = table[i][1];
  4305. var sx1 = (bx * 2 + qsx) * w1;
  4306. var sy1 = (by * 2 + qsy) * h1;
  4307. var dx1 = dx + (i % 2) * w1;
  4308. var dy1 = dy + Math.floor(i / 2) * h1;
  4309. if (isTable && (qsy === 1 || qsy === 5)) {
  4310. var qsx2 = qsx;
  4311. var qsy2 = 3;
  4312. if (qsy === 1) {
  4313. qsx2 = [0,3,2,1][qsx];
  4314. }
  4315. var sx2 = (bx * 2 + qsx2) * w1;
  4316. var sy2 = (by * 2 + qsy2) * h1;
  4317. bitmap.blt(source, sx2, sy2, w1, h1, dx1, dy1, w1, h1);
  4318. dy1 += h1/2;
  4319. bitmap.blt(source, sx1, sy1, w1, h1/2, dx1, dy1, w1, h1/2);
  4320. } else {
  4321. bitmap.blt(source, sx1, sy1, w1, h1, dx1, dy1, w1, h1);
  4322. }
  4323. }
  4324. }
  4325. };
  4326.  
  4327. /**
  4328. * @method _drawTableEdge
  4329. * @param {Bitmap} bitmap
  4330. * @param {Number} tileId
  4331. * @param {Number} dx
  4332. * @param {Number} dy
  4333. * @private
  4334. */
  4335. Tilemap.prototype._drawTableEdge = function(bitmap, tileId, dx, dy) {
  4336. if (Tilemap.isTileA2(tileId)) {
  4337. var autotileTable = Tilemap.FLOOR_AUTOTILE_TABLE;
  4338. var kind = Tilemap.getAutotileKind(tileId);
  4339. var shape = Tilemap.getAutotileShape(tileId);
  4340. var tx = kind % 8;
  4341. var ty = Math.floor(kind / 8);
  4342. var setNumber = 1;
  4343. var bx = tx * 2;
  4344. var by = (ty - 2) * 3;
  4345. var table = autotileTable[shape];
  4346.  
  4347. if (table) {
  4348. var source = this.bitmaps[setNumber];
  4349. var w1 = this._tileWidth / 2;
  4350. var h1 = this._tileHeight / 2;
  4351. for (var i = 0; i < 2; i++) {
  4352. var qsx = table[2 + i][0];
  4353. var qsy = table[2 + i][1];
  4354. var sx1 = (bx * 2 + qsx) * w1;
  4355. var sy1 = (by * 2 + qsy) * h1 + h1/2;
  4356. var dx1 = dx + (i % 2) * w1;
  4357. var dy1 = dy + Math.floor(i / 2) * h1;
  4358. bitmap.blt(source, sx1, sy1, w1, h1/2, dx1, dy1, w1, h1/2);
  4359. }
  4360. }
  4361. }
  4362. };
  4363.  
  4364. /**
  4365. * @method _drawShadow
  4366. * @param {Bitmap} bitmap
  4367. * @param {Number} shadowBits
  4368. * @param {Number} dx
  4369. * @param {Number} dy
  4370. * @private
  4371. */
  4372. Tilemap.prototype._drawShadow = function(bitmap, shadowBits, dx, dy) {
  4373. if (shadowBits & 0x0f) {
  4374. var w1 = this._tileWidth / 2;
  4375. var h1 = this._tileHeight / 2;
  4376. var color = 'rgba(0,0,0,0.5)';
  4377. for (var i = 0; i < 4; i++) {
  4378. if (shadowBits & (1 << i)) {
  4379. var dx1 = dx + (i % 2) * w1;
  4380. var dy1 = dy + Math.floor(i / 2) * h1;
  4381. bitmap.fillRect(dx1, dy1, w1, h1, color);
  4382. }
  4383. }
  4384. }
  4385. };
  4386.  
  4387. /**
  4388. * @method _readMapData
  4389. * @param {Number} x
  4390. * @param {Number} y
  4391. * @param {Number} z
  4392. * @return {Number}
  4393. * @private
  4394. */
  4395. Tilemap.prototype._readMapData = function(x, y, z) {
  4396. if (this._mapData) {
  4397. var width = this._mapWidth;
  4398. var height = this._mapHeight;
  4399. if (this.horizontalWrap) {
  4400. x = x.mod(width);
  4401. }
  4402. if (this.verticalWrap) {
  4403. y = y.mod(height);
  4404. }
  4405. if (x >= 0 && x < width && y >= 0 && y < height) {
  4406. return this._mapData[(z * height + y) * width + x] || 0;
  4407. } else {
  4408. return 0;
  4409. }
  4410. } else {
  4411. return 0;
  4412. }
  4413. };
  4414.  
  4415. /**
  4416. * @method _isHigherTile
  4417. * @param {Number} tileId
  4418. * @return {Boolean}
  4419. * @private
  4420. */
  4421. Tilemap.prototype._isHigherTile = function(tileId) {
  4422. return this.flags[tileId] & 0x10;
  4423. };
  4424.  
  4425. /**
  4426. * @method _isTableTile
  4427. * @param {Number} tileId
  4428. * @return {Boolean}
  4429. * @private
  4430. */
  4431. Tilemap.prototype._isTableTile = function(tileId) {
  4432. return Tilemap.isTileA2(tileId) && (this.flags[tileId] & 0x80);
  4433. };
  4434.  
  4435. /**
  4436. * @method _isOverpassPosition
  4437. * @param {Number} mx
  4438. * @param {Number} my
  4439. * @return {Boolean}
  4440. * @private
  4441. */
  4442. Tilemap.prototype._isOverpassPosition = function(mx, my) {
  4443. return false;
  4444. };
  4445.  
  4446. /**
  4447. * @method _sortChildren
  4448. * @private
  4449. */
  4450. Tilemap.prototype._sortChildren = function() {
  4451. this.children.sort(this._compareChildOrder.bind(this));
  4452. };
  4453.  
  4454. /**
  4455. * @method _compareChildOrder
  4456. * @param {Object} a
  4457. * @param {Object} b
  4458. * @private
  4459. */
  4460. Tilemap.prototype._compareChildOrder = function(a, b) {
  4461. if (a.z !== b.z) {
  4462. return a.z - b.z;
  4463. } else if (a.y !== b.y) {
  4464. return a.y - b.y;
  4465. } else {
  4466. return a.spriteId - b.spriteId;
  4467. }
  4468. };
  4469.  
  4470. // Tile type checkers
  4471.  
  4472. Tilemap.TILE_ID_B = 0;
  4473. Tilemap.TILE_ID_C = 256;
  4474. Tilemap.TILE_ID_D = 512;
  4475. Tilemap.TILE_ID_E = 768;
  4476. Tilemap.TILE_ID_A5 = 1536;
  4477. Tilemap.TILE_ID_A1 = 2048;
  4478. Tilemap.TILE_ID_A2 = 2816;
  4479. Tilemap.TILE_ID_A3 = 4352;
  4480. Tilemap.TILE_ID_A4 = 5888;
  4481. Tilemap.TILE_ID_MAX = 8192;
  4482.  
  4483. Tilemap.isVisibleTile = function(tileId) {
  4484. return tileId > 0 && tileId < this.TILE_ID_MAX;
  4485. };
  4486.  
  4487. Tilemap.isAutotile = function(tileId) {
  4488. return tileId >= this.TILE_ID_A1;
  4489. };
  4490.  
  4491. Tilemap.getAutotileKind = function(tileId) {
  4492. return Math.floor((tileId - this.TILE_ID_A1) / 48);
  4493. };
  4494.  
  4495. Tilemap.getAutotileShape = function(tileId) {
  4496. return (tileId - this.TILE_ID_A1) % 48;
  4497. };
  4498.  
  4499. Tilemap.makeAutotileId = function(kind, shape) {
  4500. return this.TILE_ID_A1 + kind * 48 + shape;
  4501. };
  4502.  
  4503. Tilemap.isSameKindTile = function(tileID1, tileID2) {
  4504. if (this.isAutotile(tileID1) && this.isAutotile(tileID2)) {
  4505. return this.getAutotileKind(tileID1) === this.getAutotileKind(tileID2);
  4506. } else {
  4507. return tileID1 === tileID2;
  4508. }
  4509. };
  4510.  
  4511. Tilemap.isTileA1 = function(tileId) {
  4512. return tileId >= this.TILE_ID_A1 && tileId < this.TILE_ID_A2;
  4513. };
  4514.  
  4515. Tilemap.isTileA2 = function(tileId) {
  4516. return tileId >= this.TILE_ID_A2 && tileId < this.TILE_ID_A3;
  4517. };
  4518.  
  4519. Tilemap.isTileA3 = function(tileId) {
  4520. return tileId >= this.TILE_ID_A3 && tileId < this.TILE_ID_A4;
  4521. };
  4522.  
  4523. Tilemap.isTileA4 = function(tileId) {
  4524. return tileId >= this.TILE_ID_A4 && tileId < this.TILE_ID_MAX;
  4525. };
  4526.  
  4527. Tilemap.isTileA5 = function(tileId) {
  4528. return tileId >= this.TILE_ID_A5 && tileId < this.TILE_ID_A1;
  4529. };
  4530.  
  4531. Tilemap.isWaterTile = function(tileId) {
  4532. if (this.isTileA1(tileId)) {
  4533. return !(tileId >= this.TILE_ID_A1 + 96 && tileId < this.TILE_ID_A1 + 192);
  4534. } else {
  4535. return false;
  4536. }
  4537. };
  4538.  
  4539. Tilemap.isWaterfallTile = function(tileId) {
  4540. if (tileId >= this.TILE_ID_A1 + 192 && tileId < this.TILE_ID_A2) {
  4541. return this.getAutotileKind(tileId) % 2 === 1;
  4542. } else {
  4543. return false;
  4544. }
  4545. };
  4546.  
  4547. Tilemap.isGroundTile = function(tileId) {
  4548. return this.isTileA1(tileId) || this.isTileA2(tileId) || this.isTileA5(tileId);
  4549. };
  4550.  
  4551. Tilemap.isShadowingTile = function(tileId) {
  4552. return this.isTileA3(tileId) || this.isTileA4(tileId);
  4553. };
  4554.  
  4555. Tilemap.isRoofTile = function(tileId) {
  4556. return this.isTileA3(tileId) && this.getAutotileKind(tileId) % 16 < 8;
  4557. };
  4558.  
  4559. Tilemap.isWallTopTile = function(tileId) {
  4560. return this.isTileA4(tileId) && this.getAutotileKind(tileId) % 16 < 8;
  4561. };
  4562.  
  4563. Tilemap.isWallSideTile = function(tileId) {
  4564. return (this.isTileA3(tileId) || this.isTileA4(tileId)) &&
  4565. getAutotileKind(tileId) % 16 >= 8;
  4566. };
  4567.  
  4568. Tilemap.isWallTile = function(tileId) {
  4569. return this.isWallTopTile(tileId) || this.isWallSideTile(tileId);
  4570. };
  4571.  
  4572. Tilemap.isFloorTypeAutotile = function(tileId) {
  4573. return (this.isTileA1(tileId) && !this.isWaterfallTile(tileId)) ||
  4574. this.isTileA2(tileId) || this.isWallTopTile(tileId);
  4575. };
  4576.  
  4577. Tilemap.isWallTypeAutotile = function(tileId) {
  4578. return this.isRoofTile(tileId) || this.isWallSideTile(tileId);
  4579. };
  4580.  
  4581. Tilemap.isWaterfallTypeAutotile = function(tileId) {
  4582. return this.isWaterfallTile(tileId);
  4583. };
  4584.  
  4585. // Autotile shape number to coordinates of tileset images
  4586.  
  4587. Tilemap.FLOOR_AUTOTILE_TABLE = [
  4588. [[2,4],[1,4],[2,3],[1,3]],[[2,0],[1,4],[2,3],[1,3]],
  4589. [[2,4],[3,0],[2,3],[1,3]],[[2,0],[3,0],[2,3],[1,3]],
  4590. [[2,4],[1,4],[2,3],[3,1]],[[2,0],[1,4],[2,3],[3,1]],
  4591. [[2,4],[3,0],[2,3],[3,1]],[[2,0],[3,0],[2,3],[3,1]],
  4592. [[2,4],[1,4],[2,1],[1,3]],[[2,0],[1,4],[2,1],[1,3]],
  4593. [[2,4],[3,0],[2,1],[1,3]],[[2,0],[3,0],[2,1],[1,3]],
  4594. [[2,4],[1,4],[2,1],[3,1]],[[2,0],[1,4],[2,1],[3,1]],
  4595. [[2,4],[3,0],[2,1],[3,1]],[[2,0],[3,0],[2,1],[3,1]],
  4596. [[0,4],[1,4],[0,3],[1,3]],[[0,4],[3,0],[0,3],[1,3]],
  4597. [[0,4],[1,4],[0,3],[3,1]],[[0,4],[3,0],[0,3],[3,1]],
  4598. [[2,2],[1,2],[2,3],[1,3]],[[2,2],[1,2],[2,3],[3,1]],
  4599. [[2,2],[1,2],[2,1],[1,3]],[[2,2],[1,2],[2,1],[3,1]],
  4600. [[2,4],[3,4],[2,3],[3,3]],[[2,4],[3,4],[2,1],[3,3]],
  4601. [[2,0],[3,4],[2,3],[3,3]],[[2,0],[3,4],[2,1],[3,3]],
  4602. [[2,4],[1,4],[2,5],[1,5]],[[2,0],[1,4],[2,5],[1,5]],
  4603. [[2,4],[3,0],[2,5],[1,5]],[[2,0],[3,0],[2,5],[1,5]],
  4604. [[0,4],[3,4],[0,3],[3,3]],[[2,2],[1,2],[2,5],[1,5]],
  4605. [[0,2],[1,2],[0,3],[1,3]],[[0,2],[1,2],[0,3],[3,1]],
  4606. [[2,2],[3,2],[2,3],[3,3]],[[2,2],[3,2],[2,1],[3,3]],
  4607. [[2,4],[3,4],[2,5],[3,5]],[[2,0],[3,4],[2,5],[3,5]],
  4608. [[0,4],[1,4],[0,5],[1,5]],[[0,4],[3,0],[0,5],[1,5]],
  4609. [[0,2],[3,2],[0,3],[3,3]],[[0,2],[1,2],[0,5],[1,5]],
  4610. [[0,4],[3,4],[0,5],[3,5]],[[2,2],[3,2],[2,5],[3,5]],
  4611. [[0,2],[3,2],[0,5],[3,5]],[[0,0],[1,0],[0,1],[1,1]]
  4612. ];
  4613.  
  4614. Tilemap.WALL_AUTOTILE_TABLE = [
  4615. [[2,2],[1,2],[2,1],[1,1]],[[0,2],[1,2],[0,1],[1,1]],
  4616. [[2,0],[1,0],[2,1],[1,1]],[[0,0],[1,0],[0,1],[1,1]],
  4617. [[2,2],[3,2],[2,1],[3,1]],[[0,2],[3,2],[0,1],[3,1]],
  4618. [[2,0],[3,0],[2,1],[3,1]],[[0,0],[3,0],[0,1],[3,1]],
  4619. [[2,2],[1,2],[2,3],[1,3]],[[0,2],[1,2],[0,3],[1,3]],
  4620. [[2,0],[1,0],[2,3],[1,3]],[[0,0],[1,0],[0,3],[1,3]],
  4621. [[2,2],[3,2],[2,3],[3,3]],[[0,2],[3,2],[0,3],[3,3]],
  4622. [[2,0],[3,0],[2,3],[3,3]],[[0,0],[3,0],[0,3],[3,3]]
  4623. ];
  4624.  
  4625. Tilemap.WATERFALL_AUTOTILE_TABLE = [
  4626. [[2,0],[1,0],[2,1],[1,1]],[[0,0],[1,0],[0,1],[1,1]],
  4627. [[2,0],[3,0],[2,1],[3,1]],[[0,0],[3,0],[0,1],[3,1]]
  4628. ];
  4629.  
  4630. // The important members from Pixi.js
  4631.  
  4632. /**
  4633. * [read-only] The array of children of the tilemap.
  4634. *
  4635. * @property children
  4636. * @type Array
  4637. */
  4638.  
  4639. /**
  4640. * [read-only] The object that contains the tilemap.
  4641. *
  4642. * @property parent
  4643. * @type Object
  4644. */
  4645.  
  4646. /**
  4647. * Adds a child to the container.
  4648. *
  4649. * @method addChild
  4650. * @param {Object} child The child to add
  4651. * @return {Object} The child that was added
  4652. */
  4653.  
  4654. /**
  4655. * Adds a child to the container at a specified index.
  4656. *
  4657. * @method addChildAt
  4658. * @param {Object} child The child to add
  4659. * @param {Number} index The index to place the child in
  4660. * @return {Object} The child that was added
  4661. */
  4662.  
  4663. /**
  4664. * Removes a child from the container.
  4665. *
  4666. * @method removeChild
  4667. * @param {Object} child The child to remove
  4668. * @return {Object} The child that was removed
  4669. */
  4670.  
  4671. /**
  4672. * Removes a child from the specified index position.
  4673. *
  4674. * @method removeChildAt
  4675. * @param {Number} index The index to get the child from
  4676. * @return {Object} The child that was removed
  4677. */
  4678.  
  4679. //-----------------------------------------------------------------------------
  4680. /**
  4681. * The sprite object for a tiling image.
  4682. *
  4683. * @class TilingSprite
  4684. * @constructor
  4685. * @param {Bitmap} bitmap The image for the tiling sprite
  4686. */
  4687. function TilingSprite() {
  4688. this.initialize.apply(this, arguments);
  4689. }
  4690.  
  4691. TilingSprite.prototype = Object.create(PIXI.TilingSprite.prototype);
  4692. TilingSprite.prototype.constructor = TilingSprite;
  4693.  
  4694. TilingSprite.prototype.initialize = function(bitmap) {
  4695. var texture = new PIXI.Texture(new PIXI.BaseTexture());
  4696.  
  4697. PIXI.TilingSprite.call(this, texture);
  4698.  
  4699. this._bitmap = null;
  4700. this._width = 0;
  4701. this._height = 0;
  4702. this._frame = new Rectangle();
  4703.  
  4704. /**
  4705. * The origin point of the tiling sprite for scrolling.
  4706. *
  4707. * @property origin
  4708. * @type Point
  4709. */
  4710. this.origin = new Point();
  4711.  
  4712. this.bitmap = bitmap;
  4713. };
  4714.  
  4715. /**
  4716. * The image for the tiling sprite.
  4717. *
  4718. * @property bitmap
  4719. * @type Bitmap
  4720. */
  4721. Object.defineProperty(TilingSprite.prototype, 'bitmap', {
  4722. get: function() {
  4723. return this._bitmap;
  4724. },
  4725. set: function(value) {
  4726. if (this._bitmap !== value) {
  4727. this._bitmap = value;
  4728. if (this._bitmap) {
  4729. this._bitmap.addLoadListener(this._onBitmapLoad.bind(this));
  4730. } else {
  4731. this.texture.setFrame(Rectangle.emptyRectangle);
  4732. }
  4733. }
  4734. },
  4735. configurable: true
  4736. });
  4737.  
  4738. /**
  4739. * The opacity of the tiling sprite (0 to 255).
  4740. *
  4741. * @property opacity
  4742. * @type Number
  4743. */
  4744. Object.defineProperty(TilingSprite.prototype, 'opacity', {
  4745. get: function() {
  4746. return this.alpha * 255;
  4747. },
  4748. set: function(value) {
  4749. this.alpha = value.clamp(0, 255) / 255;
  4750. },
  4751. configurable: true
  4752. });
  4753.  
  4754. TilingSprite.prototype.generateTilingTexture = function(arg) {
  4755. PIXI.TilingSprite.prototype.generateTilingTexture.call(this, arg);
  4756. // Purge from Pixi's Cache
  4757. if (Graphics.isWebGL()) {
  4758. if (this.tilingTexture.canvasBuffer)
  4759. PIXI.Texture.removeTextureFromCache(this.tilingTexture.canvasBuffer.canvas._pixiId);
  4760. }
  4761. };
  4762.  
  4763. /**
  4764. * Updates the tiling sprite for each frame.
  4765. *
  4766. * @method update
  4767. */
  4768. TilingSprite.prototype.update = function() {
  4769. this.children.forEach(function(child) {
  4770. if (child.update) {
  4771. child.update();
  4772. }
  4773. });
  4774. };
  4775.  
  4776. /**
  4777. * Sets the x, y, width, and height all at once.
  4778. *
  4779. * @method move
  4780. * @param {Number} x The x coordinate of the tiling sprite
  4781. * @param {Number} y The y coordinate of the tiling sprite
  4782. * @param {Number} width The width of the tiling sprite
  4783. * @param {Number} height The height of the tiling sprite
  4784. */
  4785. TilingSprite.prototype.move = function(x, y, width, height) {
  4786. this.x = x || 0;
  4787. this.y = y || 0;
  4788. this._width = width || 0;
  4789. this._height = height || 0;
  4790. };
  4791.  
  4792. /**
  4793. * Specifies the region of the image that the tiling sprite will use.
  4794. *
  4795. * @method setFrame
  4796. * @param {Number} x The x coordinate of the frame
  4797. * @param {Number} y The y coordinate of the frame
  4798. * @param {Number} width The width of the frame
  4799. * @param {Number} height The height of the frame
  4800. */
  4801. TilingSprite.prototype.setFrame = function(x, y, width, height) {
  4802. this._frame.x = x;
  4803. this._frame.y = y;
  4804. this._frame.width = width;
  4805. this._frame.height = height;
  4806. this._refresh();
  4807. };
  4808.  
  4809. /**
  4810. * @method updateTransform
  4811. * @private
  4812. */
  4813. TilingSprite.prototype.updateTransform = function() {
  4814. this.tilePosition.x = Math.round(-this.origin.x);
  4815. this.tilePosition.y = Math.round(-this.origin.y);
  4816. if (!this.tilingTexture) {
  4817. this.originalTexture = null;
  4818. this.generateTilingTexture(true);
  4819. }
  4820. PIXI.TilingSprite.prototype.updateTransform.call(this);
  4821. };
  4822.  
  4823. /**
  4824. * @method _onBitmapLoad
  4825. * @private
  4826. */
  4827. TilingSprite.prototype._onBitmapLoad = function() {
  4828. this.texture.baseTexture = this._bitmap.baseTexture;
  4829. this._refresh();
  4830. };
  4831.  
  4832. /**
  4833. * @method _refresh
  4834. * @private
  4835. */
  4836. TilingSprite.prototype._refresh = function() {
  4837. var frame = this._frame.clone();
  4838. if (frame.width === 0 && frame.height === 0 && this._bitmap) {
  4839. frame.width = this._bitmap.width;
  4840. frame.height = this._bitmap.height;
  4841. }
  4842. var lastTrim = this.texture.trim;
  4843. this.texture.trim = frame;
  4844. this.texture.setFrame(frame);
  4845. this.texture.trim = lastTrim;
  4846. this.tilingTexture = null;
  4847. };
  4848.  
  4849. // The important members from Pixi.js
  4850.  
  4851. /**
  4852. * The visibility of the tiling sprite.
  4853. *
  4854. * @property visible
  4855. * @type Boolean
  4856. */
  4857.  
  4858. /**
  4859. * The x coordinate of the tiling sprite.
  4860. *
  4861. * @property x
  4862. * @type Number
  4863. */
  4864.  
  4865. /**
  4866. * The y coordinate of the tiling sprite.
  4867. *
  4868. * @property y
  4869. * @type Number
  4870. */
  4871.  
  4872. //-----------------------------------------------------------------------------
  4873. /**
  4874. * The sprite which covers the entire game screen.
  4875. *
  4876. * @class ScreenSprite
  4877. * @constructor
  4878. */
  4879. function ScreenSprite() {
  4880. this.initialize.apply(this, arguments);
  4881. }
  4882.  
  4883. ScreenSprite.prototype = Object.create(PIXI.Sprite.prototype);
  4884. ScreenSprite.prototype.constructor = ScreenSprite;
  4885.  
  4886. ScreenSprite.prototype.initialize = function() {
  4887. var texture = new PIXI.Texture(new PIXI.BaseTexture());
  4888.  
  4889. PIXI.Sprite.call(this, texture);
  4890.  
  4891. this._bitmap = new Bitmap(1, 1);
  4892. this.texture.baseTexture = this._bitmap.baseTexture;
  4893. this.texture.setFrame(new Rectangle(0, 0, 1, 1));
  4894. this.scale.x = Graphics.width;
  4895. this.scale.y = Graphics.height;
  4896. this.opacity = 0;
  4897.  
  4898. this._red = -1;
  4899. this._green = -1;
  4900. this._blue = -1;
  4901. this._colorText = '';
  4902. this.setBlack();
  4903. };
  4904.  
  4905. /**
  4906. * The opacity of the sprite (0 to 255).
  4907. *
  4908. * @property opacity
  4909. * @type Number
  4910. */
  4911. Object.defineProperty(ScreenSprite.prototype, 'opacity', {
  4912. get: function() {
  4913. return this.alpha * 255;
  4914. },
  4915. set: function(value) {
  4916. this.alpha = value.clamp(0, 255) / 255;
  4917. },
  4918. configurable: true
  4919. });
  4920.  
  4921. /**
  4922. * Sets black to the color of the screen sprite.
  4923. *
  4924. * @method setBlack
  4925. */
  4926. ScreenSprite.prototype.setBlack = function() {
  4927. this.setColor(0, 0, 0);
  4928. };
  4929.  
  4930. /**
  4931. * Sets white to the color of the screen sprite.
  4932. *
  4933. * @method setWhite
  4934. */
  4935. ScreenSprite.prototype.setWhite = function() {
  4936. this.setColor(255, 255, 255);
  4937. };
  4938.  
  4939. /**
  4940. * Sets the color of the screen sprite by values.
  4941. *
  4942. * @method setColor
  4943. * @param {Number} r The red value in the range (0, 255)
  4944. * @param {Number} g The green value in the range (0, 255)
  4945. * @param {Number} b The blue value in the range (0, 255)
  4946. */
  4947. ScreenSprite.prototype.setColor = function(r, g, b) {
  4948. if (this._red !== r || this._green !== g || this._blue !== b) {
  4949. r = Math.round(r || 0).clamp(0, 255);
  4950. g = Math.round(g || 0).clamp(0, 255);
  4951. b = Math.round(b || 0).clamp(0, 255);
  4952. this._red = r;
  4953. this._green = g;
  4954. this._blue = b;
  4955. this._colorText = Utils.rgbToCssColor(r, g, b);
  4956. this._bitmap.fillAll(this._colorText);
  4957. }
  4958. };
  4959.  
  4960. /**
  4961. * @method _renderCanvas
  4962. * @param {Object} renderSession
  4963. * @private
  4964. */
  4965. ScreenSprite.prototype._renderCanvas = function(renderSession) {
  4966. if (this.visible && this.alpha > 0) {
  4967. var context = renderSession.context;
  4968. var t = this.worldTransform;
  4969. var r = renderSession.resolution;
  4970. context.setTransform(t.a, t.b, t.c, t.d, t.tx * r, t.ty * r);
  4971. context.globalCompositeOperation = PIXI.blendModesCanvas[this.blendMode];
  4972. context.globalAlpha = this.alpha;
  4973. context.fillStyle = this._colorText;
  4974. context.fillRect(0, 0, Graphics.width, Graphics.height);
  4975. }
  4976. };
  4977.  
  4978. //-----------------------------------------------------------------------------
  4979. /**
  4980. * The window in the game.
  4981. *
  4982. * @class Window
  4983. * @constructor
  4984. */
  4985. function Window() {
  4986. this.initialize.apply(this, arguments);
  4987. }
  4988.  
  4989. Window.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  4990. Window.prototype.constructor = Window;
  4991.  
  4992. Window.prototype.initialize = function() {
  4993. PIXI.DisplayObjectContainer.call(this);
  4994.  
  4995. this._isWindow = true;
  4996. this._windowskin = null;
  4997. this._width = 0;
  4998. this._height = 0;
  4999. this._cursorRect = new Rectangle();
  5000. this._openness = 255;
  5001. this._animationCount = 0;
  5002.  
  5003. this._padding = 18;
  5004. this._margin = 4;
  5005. this._colorTone = [0, 0, 0];
  5006.  
  5007. this._windowSpriteContainer = null;
  5008. this._windowBackSprite = null;
  5009. this._windowCursorSprite = null;
  5010. this._windowFrameSprite = null;
  5011. this._windowContentsSprite = null;
  5012. this._windowArrowSprites = [];
  5013. this._windowPauseSignSprite = null;
  5014.  
  5015. this._createAllParts();
  5016.  
  5017. /**
  5018. * The origin point of the window for scrolling.
  5019. *
  5020. * @property origin
  5021. * @type Point
  5022. */
  5023. this.origin = new Point();
  5024.  
  5025. /**
  5026. * The active state for the window.
  5027. *
  5028. * @property active
  5029. * @type Boolean
  5030. */
  5031. this.active = true;
  5032.  
  5033. /**
  5034. * The visibility of the down scroll arrow.
  5035. *
  5036. * @property downArrowVisible
  5037. * @type Boolean
  5038. */
  5039. this.downArrowVisible = false;
  5040.  
  5041. /**
  5042. * The visibility of the up scroll arrow.
  5043. *
  5044. * @property upArrowVisible
  5045. * @type Boolean
  5046. */
  5047. this.upArrowVisible = false;
  5048.  
  5049. /**
  5050. * The visibility of the pause sign.
  5051. *
  5052. * @property pause
  5053. * @type Boolean
  5054. */
  5055. this.pause = false;
  5056. };
  5057.  
  5058. /**
  5059. * The image used as a window skin.
  5060. *
  5061. * @property windowskin
  5062. * @type Bitmap
  5063. */
  5064. Object.defineProperty(Window.prototype, 'windowskin', {
  5065. get: function() {
  5066. return this._windowskin;
  5067. },
  5068. set: function(value) {
  5069. if (this._windowskin !== value) {
  5070. this._windowskin = value;
  5071. this._windowskin.addLoadListener(this._onWindowskinLoad.bind(this));
  5072. }
  5073. },
  5074. configurable: true
  5075. });
  5076.  
  5077. /**
  5078. * The bitmap used for the window contents.
  5079. *
  5080. * @property contents
  5081. * @type Bitmap
  5082. */
  5083. Object.defineProperty(Window.prototype, 'contents', {
  5084. get: function() {
  5085. return this._windowContentsSprite.bitmap;
  5086. },
  5087. set: function(value) {
  5088. this._windowContentsSprite.bitmap = value;
  5089. },
  5090. configurable: true
  5091. });
  5092.  
  5093. /**
  5094. * The width of the window in pixels.
  5095. *
  5096. * @property width
  5097. * @type Number
  5098. */
  5099. Object.defineProperty(Window.prototype, 'width', {
  5100. get: function() {
  5101. return this._width;
  5102. },
  5103. set: function(value) {
  5104. this._width = value;
  5105. this._refreshAllParts();
  5106. },
  5107. configurable: true
  5108. });
  5109.  
  5110. /**
  5111. * The height of the window in pixels.
  5112. *
  5113. * @property height
  5114. * @type Number
  5115. */
  5116. Object.defineProperty(Window.prototype, 'height', {
  5117. get: function() {
  5118. return this._height;
  5119. },
  5120. set: function(value) {
  5121. this._height = value;
  5122. this._refreshAllParts();
  5123. },
  5124. configurable: true
  5125. });
  5126.  
  5127. /**
  5128. * The size of the padding between the frame and contents.
  5129. *
  5130. * @property padding
  5131. * @type Number
  5132. */
  5133. Object.defineProperty(Window.prototype, 'padding', {
  5134. get: function() {
  5135. return this._padding;
  5136. },
  5137. set: function(value) {
  5138. this._padding = value;
  5139. this._refreshAllParts();
  5140. },
  5141. configurable: true
  5142. });
  5143.  
  5144. /**
  5145. * The size of the margin for the window background.
  5146. *
  5147. * @property margin
  5148. * @type Number
  5149. */
  5150. Object.defineProperty(Window.prototype, 'margin', {
  5151. get: function() {
  5152. return this._margin;
  5153. },
  5154. set: function(value) {
  5155. this._margin = value;
  5156. this._refreshAllParts();
  5157. },
  5158. configurable: true
  5159. });
  5160.  
  5161. /**
  5162. * The opacity of the window without contents (0 to 255).
  5163. *
  5164. * @property opacity
  5165. * @type Number
  5166. */
  5167. Object.defineProperty(Window.prototype, 'opacity', {
  5168. get: function() {
  5169. return this._windowSpriteContainer.alpha * 255;
  5170. },
  5171. set: function(value) {
  5172. this._windowSpriteContainer.alpha = value.clamp(0, 255) / 255;
  5173. },
  5174. configurable: true
  5175. });
  5176.  
  5177. /**
  5178. * The opacity of the window background (0 to 255).
  5179. *
  5180. * @property backOpacity
  5181. * @type Number
  5182. */
  5183. Object.defineProperty(Window.prototype, 'backOpacity', {
  5184. get: function() {
  5185. return this._windowBackSprite.alpha * 255;
  5186. },
  5187. set: function(value) {
  5188. this._windowBackSprite.alpha = value.clamp(0, 255) / 255;
  5189. },
  5190. configurable: true
  5191. });
  5192.  
  5193. /**
  5194. * The opacity of the window contents (0 to 255).
  5195. *
  5196. * @property contentsOpacity
  5197. * @type Number
  5198. */
  5199. Object.defineProperty(Window.prototype, 'contentsOpacity', {
  5200. get: function() {
  5201. return this._windowContentsSprite.alpha * 255;
  5202. },
  5203. set: function(value) {
  5204. this._windowContentsSprite.alpha = value.clamp(0, 255) / 255;
  5205. },
  5206. configurable: true
  5207. });
  5208.  
  5209. /**
  5210. * The openness of the window (0 to 255).
  5211. *
  5212. * @property openness
  5213. * @type Number
  5214. */
  5215. Object.defineProperty(Window.prototype, 'openness', {
  5216. get: function() {
  5217. return this._openness;
  5218. },
  5219. set: function(value) {
  5220. if (this._openness !== value) {
  5221. this._openness = value.clamp(0, 255);
  5222. this._windowSpriteContainer.scale.y = this._openness / 255;
  5223. this._windowSpriteContainer.y = this.height / 2 * (1 - this._openness / 255);
  5224. }
  5225. },
  5226. configurable: true
  5227. });
  5228.  
  5229. /**
  5230. * Updates the window for each frame.
  5231. *
  5232. * @method update
  5233. */
  5234. Window.prototype.update = function() {
  5235. if (this.active) {
  5236. this._animationCount++;
  5237. }
  5238. this.children.forEach(function(child) {
  5239. if (child.update) {
  5240. child.update();
  5241. }
  5242. });
  5243. };
  5244.  
  5245. /**
  5246. * Sets the x, y, width, and height all at once.
  5247. *
  5248. * @method move
  5249. * @param {Number} x The x coordinate of the window
  5250. * @param {Number} y The y coordinate of the window
  5251. * @param {Number} width The width of the window
  5252. * @param {Number} height The height of the window
  5253. */
  5254. Window.prototype.move = function(x, y, width, height) {
  5255. this.x = x || 0;
  5256. this.y = y || 0;
  5257. if (this._width !== width || this._height !== height) {
  5258. this._width = width || 0;
  5259. this._height = height || 0;
  5260. this._refreshAllParts();
  5261. }
  5262. };
  5263.  
  5264. /**
  5265. * Returns true if the window is completely open (openness == 255).
  5266. *
  5267. * @method isOpen
  5268. */
  5269. Window.prototype.isOpen = function() {
  5270. return this._openness >= 255;
  5271. };
  5272.  
  5273. /**
  5274. * Returns true if the window is completely closed (openness == 0).
  5275. *
  5276. * @method isClosed
  5277. */
  5278. Window.prototype.isClosed = function() {
  5279. return this._openness <= 0;
  5280. };
  5281.  
  5282. /**
  5283. * Sets the position of the command cursor.
  5284. *
  5285. * @method setCursorRect
  5286. * @param {Number} x The x coordinate of the cursor
  5287. * @param {Number} y The y coordinate of the cursor
  5288. * @param {Number} width The width of the cursor
  5289. * @param {Number} height The height of the cursor
  5290. */
  5291. Window.prototype.setCursorRect = function(x, y, width, height) {
  5292. var cx = Math.floor(x || 0);
  5293. var cy = Math.floor(y || 0);
  5294. var cw = Math.floor(width || 0);
  5295. var ch = Math.floor(height || 0);
  5296. var rect = this._cursorRect;
  5297. if (rect.x !== cx || rect.y !== cy || rect.width !== cw || rect.height !== ch) {
  5298. this._cursorRect.x = cx;
  5299. this._cursorRect.y = cy;
  5300. this._cursorRect.width = cw;
  5301. this._cursorRect.height = ch;
  5302. this._refreshCursor();
  5303. }
  5304. };
  5305.  
  5306. /**
  5307. * Changes the color of the background.
  5308. *
  5309. * @method setTone
  5310. * @param {Number} r The red value in the range (-255, 255)
  5311. * @param {Number} g The green value in the range (-255, 255)
  5312. * @param {Number} b The blue value in the range (-255, 255)
  5313. */
  5314. Window.prototype.setTone = function(r, g, b) {
  5315. var tone = this._colorTone;
  5316. if (r !== tone[0] || g !== tone[1] || b !== tone[2]) {
  5317. this._colorTone = [r, g, b];
  5318. this._refreshBack();
  5319. }
  5320. };
  5321.  
  5322. /**
  5323. * Adds a child between the background and contents.
  5324. *
  5325. * @method addChildToBack
  5326. * @param {Object} child The child to add
  5327. * @return {Object} The child that was added
  5328. */
  5329. Window.prototype.addChildToBack = function(child) {
  5330. var containerIndex = this.children.indexOf(this._windowSpriteContainer);
  5331. return this.addChildAt(child, containerIndex + 1);
  5332. };
  5333.  
  5334. /**
  5335. * @method updateTransform
  5336. * @private
  5337. */
  5338. Window.prototype.updateTransform = function() {
  5339. this._updateCursor();
  5340. this._updateArrows();
  5341. this._updatePauseSign();
  5342. this._updateContents();
  5343. PIXI.DisplayObjectContainer.prototype.updateTransform.call(this);
  5344. };
  5345.  
  5346. /**
  5347. * @method _createAllParts
  5348. * @private
  5349. */
  5350. Window.prototype._createAllParts = function() {
  5351. this._windowSpriteContainer = new PIXI.DisplayObjectContainer();
  5352. this._windowBackSprite = new Sprite();
  5353. this._windowCursorSprite = new Sprite();
  5354. this._windowFrameSprite = new Sprite();
  5355. this._windowContentsSprite = new Sprite();
  5356. this._downArrowSprite = new Sprite();
  5357. this._upArrowSprite = new Sprite();
  5358. this._windowPauseSignSprite = new Sprite();
  5359. this._windowBackSprite.bitmap = new Bitmap(1, 1);
  5360. this._windowBackSprite.alpha = 192 / 255;
  5361. this.addChild(this._windowSpriteContainer);
  5362. this._windowSpriteContainer.addChild(this._windowBackSprite);
  5363. this._windowSpriteContainer.addChild(this._windowFrameSprite);
  5364. this.addChild(this._windowCursorSprite);
  5365. this.addChild(this._windowContentsSprite);
  5366. this.addChild(this._downArrowSprite);
  5367. this.addChild(this._upArrowSprite);
  5368. this.addChild(this._windowPauseSignSprite);
  5369. };
  5370.  
  5371. /**
  5372. * @method _onWindowskinLoad
  5373. * @private
  5374. */
  5375. Window.prototype._onWindowskinLoad = function() {
  5376. this._refreshAllParts();
  5377. };
  5378.  
  5379. /**
  5380. * @method _refreshAllParts
  5381. * @private
  5382. */
  5383. Window.prototype._refreshAllParts = function() {
  5384. this._refreshBack();
  5385. this._refreshFrame();
  5386. this._refreshCursor();
  5387. this._refreshContents();
  5388. this._refreshArrows();
  5389. this._refreshPauseSign();
  5390. };
  5391.  
  5392. /**
  5393. * @method _refreshBack
  5394. * @private
  5395. */
  5396. Window.prototype._refreshBack = function() {
  5397. var m = this._margin;
  5398. var w = this._width - m * 2;
  5399. var h = this._height - m * 2;
  5400. var bitmap = new Bitmap(w, h);
  5401.  
  5402. this._windowBackSprite.bitmap = bitmap;
  5403. this._windowBackSprite.setFrame(0, 0, w, h);
  5404. this._windowBackSprite.move(m, m);
  5405.  
  5406. if (w > 0 && h > 0 && this._windowskin) {
  5407. var p = 96;
  5408. bitmap.blt(this._windowskin, 0, 0, p, p, 0, 0, w, h);
  5409. for (var y = 0; y < h; y += p) {
  5410. for (var x = 0; x < w; x += p) {
  5411. bitmap.blt(this._windowskin, 0, p, p, p, x, y, p, p);
  5412. }
  5413. }
  5414. var tone = this._colorTone;
  5415. bitmap.adjustTone(tone[0], tone[1], tone[2]);
  5416. }
  5417. };
  5418.  
  5419. /**
  5420. * @method _refreshFrame
  5421. * @private
  5422. */
  5423. Window.prototype._refreshFrame = function() {
  5424. var w = this._width;
  5425. var h = this._height;
  5426. var m = 24;
  5427. var bitmap = new Bitmap(w, h);
  5428.  
  5429. this._windowFrameSprite.bitmap = bitmap;
  5430. this._windowFrameSprite.setFrame(0, 0, w, h);
  5431.  
  5432. if (w > 0 && h > 0 && this._windowskin) {
  5433. var skin = this._windowskin;
  5434. var p = 96;
  5435. var q = 96;
  5436. bitmap.blt(skin, p+m, 0+0, p-m*2, m, m, 0, w-m*2, m);
  5437. bitmap.blt(skin, p+m, 0+q-m, p-m*2, m, m, h-m, w-m*2, m);
  5438. bitmap.blt(skin, p+0, 0+m, m, p-m*2, 0, m, m, h-m*2);
  5439. bitmap.blt(skin, p+q-m, 0+m, m, p-m*2, w-m, m, m, h-m*2);
  5440. bitmap.blt(skin, p+0, 0+0, m, m, 0, 0, m, m);
  5441. bitmap.blt(skin, p+q-m, 0+0, m, m, w-m, 0, m, m);
  5442. bitmap.blt(skin, p+0, 0+q-m, m, m, 0, h-m, m, m);
  5443. bitmap.blt(skin, p+q-m, 0+q-m, m, m, w-m, h-m, m, m);
  5444. }
  5445. };
  5446.  
  5447. /**
  5448. * @method _refreshCursor
  5449. * @private
  5450. */
  5451. Window.prototype._refreshCursor = function() {
  5452. var pad = this._padding;
  5453. var x = this._cursorRect.x + pad - this.origin.x;
  5454. var y = this._cursorRect.y + pad - this.origin.y;
  5455. var w = this._cursorRect.width;
  5456. var h = this._cursorRect.height;
  5457. var m = 4;
  5458. var x2 = Math.max(x, pad);
  5459. var y2 = Math.max(y, pad);
  5460. var ox = x - x2;
  5461. var oy = y - y2;
  5462. var w2 = Math.min(w, this._width - pad - x2);
  5463. var h2 = Math.min(h, this._height - pad - y2);
  5464. var bitmap = new Bitmap(w2, h2);
  5465.  
  5466. this._windowCursorSprite.bitmap = bitmap;
  5467. this._windowCursorSprite.setFrame(0, 0, w2, h2);
  5468. this._windowCursorSprite.move(x2, y2);
  5469.  
  5470. if (w > 0 && h > 0 && this._windowskin) {
  5471. var skin = this._windowskin;
  5472. var p = 96;
  5473. var q = 48;
  5474. bitmap.blt(skin, p+m, p+m, q-m*2, q-m*2, ox+m, oy+m, w-m*2, h-m*2);
  5475. bitmap.blt(skin, p+m, p+0, q-m*2, m, ox+m, oy+0, w-m*2, m);
  5476. bitmap.blt(skin, p+m, p+q-m, q-m*2, m, ox+m, oy+h-m, w-m*2, m);
  5477. bitmap.blt(skin, p+0, p+m, m, q-m*2, ox+0, oy+m, m, h-m*2);
  5478. bitmap.blt(skin, p+q-m, p+m, m, q-m*2, ox+w-m, oy+m, m, h-m*2);
  5479. bitmap.blt(skin, p+0, p+0, m, m, ox+0, oy+0, m, m);
  5480. bitmap.blt(skin, p+q-m, p+0, m, m, ox+w-m, oy+0, m, m);
  5481. bitmap.blt(skin, p+0, p+q-m, m, m, ox+0, oy+h-m, m, m);
  5482. bitmap.blt(skin, p+q-m, p+q-m, m, m, ox+w-m, oy+h-m, m, m);
  5483. }
  5484. };
  5485.  
  5486. /**
  5487. * @method _refreshContents
  5488. * @private
  5489. */
  5490. Window.prototype._refreshContents = function() {
  5491. this._windowContentsSprite.move(this.padding, this.padding);
  5492. };
  5493.  
  5494. /**
  5495. * @method _refreshArrows
  5496. * @private
  5497. */
  5498. Window.prototype._refreshArrows = function() {
  5499. var w = this._width;
  5500. var h = this._height;
  5501. var p = 24;
  5502. var q = p/2;
  5503. var sx = 96+p;
  5504. var sy = 0+p;
  5505. this._downArrowSprite.bitmap = this._windowskin;
  5506. this._downArrowSprite.anchor.x = 0.5;
  5507. this._downArrowSprite.anchor.y = 0.5;
  5508. this._downArrowSprite.setFrame(sx+q, sy+q+p, p, q);
  5509. this._downArrowSprite.move(w/2, h-q);
  5510. this._upArrowSprite.bitmap = this._windowskin;
  5511. this._upArrowSprite.anchor.x = 0.5;
  5512. this._upArrowSprite.anchor.y = 0.5;
  5513. this._upArrowSprite.setFrame(sx+q, sy, p, q);
  5514. this._upArrowSprite.move(w/2, q);
  5515. };
  5516.  
  5517. /**
  5518. * @method _refreshPauseSign
  5519. * @private
  5520. */
  5521. Window.prototype._refreshPauseSign = function() {
  5522. var sx = 144;
  5523. var sy = 96;
  5524. var p = 24;
  5525. this._windowPauseSignSprite.bitmap = this._windowskin;
  5526. this._windowPauseSignSprite.anchor.x = 0.5;
  5527. this._windowPauseSignSprite.anchor.y = 1;
  5528. this._windowPauseSignSprite.move(this._width / 2, this._height);
  5529. this._windowPauseSignSprite.setFrame(sx, sy, p, p);
  5530. this._windowPauseSignSprite.alpha = 0;
  5531. };
  5532.  
  5533. /**
  5534. * @method _updateCursor
  5535. * @private
  5536. */
  5537. Window.prototype._updateCursor = function() {
  5538. var blinkCount = this._animationCount % 40;
  5539. var cursorOpacity = this.contentsOpacity;
  5540. if (this.active) {
  5541. if (blinkCount < 20) {
  5542. cursorOpacity -= blinkCount * 8;
  5543. } else {
  5544. cursorOpacity -= (40 - blinkCount) * 8;
  5545. }
  5546. }
  5547. this._windowCursorSprite.alpha = cursorOpacity / 255;
  5548. this._windowCursorSprite.visible = this.isOpen();
  5549. };
  5550.  
  5551. /**
  5552. * @method _updateContents
  5553. * @private
  5554. */
  5555. Window.prototype._updateContents = function() {
  5556. var w = this._width - this._padding * 2;
  5557. var h = this._height - this._padding * 2;
  5558. if (w > 0 && h > 0) {
  5559. this._windowContentsSprite.setFrame(this.origin.x, this.origin.y, w, h);
  5560. this._windowContentsSprite.visible = this.isOpen();
  5561. } else {
  5562. this._windowContentsSprite.visible = false;
  5563. }
  5564. };
  5565.  
  5566. /**
  5567. * @method _updateArrows
  5568. * @private
  5569. */
  5570. Window.prototype._updateArrows = function() {
  5571. this._downArrowSprite.visible = this.isOpen() && this.downArrowVisible;
  5572. this._upArrowSprite.visible = this.isOpen() && this.upArrowVisible;
  5573. };
  5574.  
  5575. /**
  5576. * @method _updatePauseSign
  5577. * @private
  5578. */
  5579. Window.prototype._updatePauseSign = function() {
  5580. var sprite = this._windowPauseSignSprite;
  5581. var x = Math.floor(this._animationCount / 16) % 2;
  5582. var y = Math.floor(this._animationCount / 16 / 2) % 2;
  5583. var sx = 144;
  5584. var sy = 96;
  5585. var p = 24;
  5586. if (!this.pause) {
  5587. sprite.alpha = 0;
  5588. } else if (sprite.alpha < 1) {
  5589. sprite.alpha = Math.min(sprite.alpha + 0.1, 1);
  5590. }
  5591. sprite.setFrame(sx+x*p, sy+y*p, p, p);
  5592. sprite.visible = this.isOpen();
  5593. };
  5594.  
  5595. // The important members from Pixi.js
  5596.  
  5597. /**
  5598. * The visibility of the window.
  5599. *
  5600. * @property visible
  5601. * @type Boolean
  5602. */
  5603.  
  5604. /**
  5605. * The x coordinate of the window.
  5606. *
  5607. * @property x
  5608. * @type Number
  5609. */
  5610.  
  5611. /**
  5612. * The y coordinate of the window.
  5613. *
  5614. * @property y
  5615. * @type Number
  5616. */
  5617.  
  5618. /**
  5619. * [read-only] The array of children of the window.
  5620. *
  5621. * @property children
  5622. * @type Array
  5623. */
  5624.  
  5625. /**
  5626. * [read-only] The object that contains the window.
  5627. *
  5628. * @property parent
  5629. * @type Object
  5630. */
  5631.  
  5632. /**
  5633. * Adds a child to the container.
  5634. *
  5635. * @method addChild
  5636. * @param {Object} child The child to add
  5637. * @return {Object} The child that was added
  5638. */
  5639.  
  5640. /**
  5641. * Adds a child to the container at a specified index.
  5642. *
  5643. * @method addChildAt
  5644. * @param {Object} child The child to add
  5645. * @param {Number} index The index to place the child in
  5646. * @return {Object} The child that was added
  5647. */
  5648.  
  5649. /**
  5650. * Removes a child from the container.
  5651. *
  5652. * @method removeChild
  5653. * @param {Object} child The child to remove
  5654. * @return {Object} The child that was removed
  5655. */
  5656.  
  5657. /**
  5658. * Removes a child from the specified index position.
  5659. *
  5660. * @method removeChildAt
  5661. * @param {Number} index The index to get the child from
  5662. * @return {Object} The child that was removed
  5663. */
  5664.  
  5665. //-----------------------------------------------------------------------------
  5666. /**
  5667. * The layer which contains game windows.
  5668. *
  5669. * @class WindowLayer
  5670. * @constructor
  5671. */
  5672. function WindowLayer() {
  5673. this.initialize.apply(this, arguments);
  5674. }
  5675.  
  5676. WindowLayer.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  5677. WindowLayer.prototype.constructor = WindowLayer;
  5678.  
  5679. WindowLayer.prototype.initialize = function() {
  5680. PIXI.DisplayObjectContainer.call(this);
  5681. this._width = 0;
  5682. this._height = 0;
  5683. this._tempCanvas = null;
  5684. this._vertexBuffer = null;
  5685. this._translationMatrix = [1, 0, 0, 0, 1, 0, 0, 0, 1];
  5686. this._dummySprite = new Sprite(new Bitmap(1, 1));
  5687. };
  5688.  
  5689. /**
  5690. * The width of the window layer in pixels.
  5691. *
  5692. * @property width
  5693. * @type Number
  5694. */
  5695. Object.defineProperty(WindowLayer.prototype, 'width', {
  5696. get: function() {
  5697. return this._width;
  5698. },
  5699. set: function(value) {
  5700. this._width = value;
  5701. },
  5702. configurable: true
  5703. });
  5704.  
  5705. /**
  5706. * The height of the window layer in pixels.
  5707. *
  5708. * @property height
  5709. * @type Number
  5710. */
  5711. Object.defineProperty(WindowLayer.prototype, 'height', {
  5712. get: function() {
  5713. return this._height;
  5714. },
  5715. set: function(value) {
  5716. this._height = value;
  5717. },
  5718. configurable: true
  5719. });
  5720.  
  5721. /**
  5722. * Sets the x, y, width, and height all at once.
  5723. *
  5724. * @method move
  5725. * @param {Number} x The x coordinate of the window layer
  5726. * @param {Number} y The y coordinate of the window layer
  5727. * @param {Number} width The width of the window layer
  5728. * @param {Number} height The height of the window layer
  5729. */
  5730. WindowLayer.prototype.move = function(x, y, width, height) {
  5731. this.x = x;
  5732. this.y = y;
  5733. this.width = width;
  5734. this.height = height;
  5735. };
  5736.  
  5737. /**
  5738. * Updates the window layer for each frame.
  5739. *
  5740. * @method update
  5741. */
  5742. WindowLayer.prototype.update = function() {
  5743. this.children.forEach(function(child) {
  5744. if (child.update) {
  5745. child.update();
  5746. }
  5747. });
  5748. };
  5749.  
  5750. /**
  5751. * @method _renderCanvas
  5752. * @param {Object} renderSession
  5753. * @private
  5754. */
  5755. WindowLayer.prototype._renderCanvas = function(renderSession) {
  5756. if (!this.visible) {
  5757. return;
  5758. }
  5759.  
  5760. if (!this._tempCanvas) {
  5761. this._tempCanvas = document.createElement('canvas');
  5762. }
  5763.  
  5764. this._tempCanvas.width = Graphics.width;
  5765. this._tempCanvas.height = Graphics.height;
  5766.  
  5767. var realCanvasContext = renderSession.context;
  5768. var context = this._tempCanvas.getContext('2d');
  5769.  
  5770. context.save();
  5771. context.clearRect(0, 0, Graphics.width, Graphics.height);
  5772. context.beginPath();
  5773. context.rect(this.x, this.y, this.width, this.height);
  5774. context.closePath();
  5775. context.clip();
  5776.  
  5777. renderSession.context = context;
  5778.  
  5779. for (var i = 0; i < this.children.length; i++) {
  5780. var child = this.children[i];
  5781. if (child._isWindow && child.visible && child.openness > 0) {
  5782. this._canvasClearWindowRect(renderSession, child);
  5783. context.save();
  5784. child._renderCanvas(renderSession);
  5785. context.restore();
  5786. }
  5787. }
  5788.  
  5789. context.restore();
  5790.  
  5791. renderSession.context = realCanvasContext;
  5792. renderSession.context.setTransform(1, 0, 0, 1, 0, 0);
  5793. renderSession.context.globalCompositeOperation = 'source-over';
  5794. renderSession.context.globalAlpha = 1;
  5795. renderSession.context.drawImage(this._tempCanvas, 0, 0);
  5796.  
  5797. for (var j = 0; j < this.children.length; j++) {
  5798. if (!this.children[j]._isWindow) {
  5799. this.children[j]._renderCanvas(renderSession);
  5800. }
  5801. }
  5802. };
  5803.  
  5804. /**
  5805. * @method _canvasClearWindowRect
  5806. * @param {Object} renderSession
  5807. * @param {Window} window
  5808. * @private
  5809. */
  5810. WindowLayer.prototype._canvasClearWindowRect = function(renderSession, window) {
  5811. var rx = this.x + window.x;
  5812. var ry = this.y + window.y + window.height / 2 * (1 - window._openness / 255);
  5813. var rw = window.width;
  5814. var rh = window.height * window._openness / 255;
  5815. renderSession.context.clearRect(rx, ry, rw, rh);
  5816. };
  5817.  
  5818. /**
  5819. * @method _renderWebGL
  5820. * @param {Object} renderSession
  5821. * @private
  5822. */
  5823. WindowLayer.prototype._renderWebGL = function(renderSession) {
  5824. if (!this.visible) {
  5825. return;
  5826. }
  5827.  
  5828. var gl = renderSession.gl;
  5829.  
  5830. if (!this._vertexBuffer) {
  5831. this._vertexBuffer = gl.createBuffer();
  5832. }
  5833.  
  5834. this._dummySprite._renderWebGL(renderSession);
  5835.  
  5836. renderSession.spriteBatch.stop();
  5837. gl.enable(gl.STENCIL_TEST);
  5838. gl.clear(gl.STENCIL_BUFFER_BIT);
  5839. this._webglMaskOutside(renderSession);
  5840. renderSession.spriteBatch.start();
  5841.  
  5842. for (var i = this.children.length - 1; i >= 0; i--) {
  5843. var child = this.children[i];
  5844. if (child._isWindow && child.visible && child.openness > 0) {
  5845. gl.stencilFunc(gl.EQUAL, 0, 0xFF);
  5846. child._renderWebGL(renderSession);
  5847. renderSession.spriteBatch.stop();
  5848. this._webglMaskWindow(renderSession, child);
  5849. renderSession.spriteBatch.start();
  5850. }
  5851. }
  5852.  
  5853. gl.disable(gl.STENCIL_TEST);
  5854.  
  5855. for (var j = 0; j < this.children.length; j++) {
  5856. if (!this.children[j]._isWindow) {
  5857. this.children[j]._renderWebGL(renderSession);
  5858. }
  5859. }
  5860. };
  5861.  
  5862. /**
  5863. * @method _webglMaskOutside
  5864. * @param {Object} renderSession
  5865. * @private
  5866. */
  5867. WindowLayer.prototype._webglMaskOutside = function(renderSession) {
  5868. var x1 = this.x;
  5869. var y1 = this.y;
  5870. var x2 = this.x + this.width;
  5871. var y2 = this.y + this.height;
  5872. this._webglMaskRect(renderSession, 0, 0, Graphics.width, y1);
  5873. this._webglMaskRect(renderSession, 0, y2, Graphics.width, Graphics.height - y2);
  5874. this._webglMaskRect(renderSession, 0, 0, x1, Graphics.height);
  5875. this._webglMaskRect(renderSession, x2, 0, Graphics.width - x2, Graphics.height);
  5876. };
  5877.  
  5878. /**
  5879. * @method _webglMaskWindow
  5880. * @param {Object} renderSession
  5881. * @param {Window} window
  5882. * @private
  5883. */
  5884. WindowLayer.prototype._webglMaskWindow = function(renderSession, window) {
  5885. var rx = this.x + window.x;
  5886. var ry = this.y + window.y + window.height / 2 * (1 - window._openness / 255);
  5887. var rw = window.width;
  5888. var rh = window.height * window._openness / 255;
  5889. this._webglMaskRect(renderSession, rx, ry, rw, rh);
  5890. };
  5891.  
  5892. /**
  5893. * @method _webglMaskRect
  5894. * @param {Object} renderSession
  5895. * @param {Number} x
  5896. * @param {Number} y
  5897. * @param {Number} w
  5898. * @param {Number} h
  5899. * @private
  5900. */
  5901. WindowLayer.prototype._webglMaskRect = function(renderSession, x, y, w, h) {
  5902. if (w > 0 && h > 0) {
  5903. var gl = renderSession.gl;
  5904.  
  5905. var projection = renderSession.projection;
  5906. var offset = renderSession.offset;
  5907. var shader = renderSession.shaderManager.primitiveShader;
  5908.  
  5909. renderSession.shaderManager.setShader(shader);
  5910.  
  5911. gl.uniformMatrix3fv(shader.translationMatrix, false, this._translationMatrix);
  5912. gl.uniform1f(shader.flipY, 1);
  5913. gl.uniform2f(shader.projectionVector, projection.x, -projection.y);
  5914. gl.uniform2f(shader.offsetVector, -offset.x, -offset.y);
  5915.  
  5916. gl.stencilFunc(gl.EQUAL, 0, 0xFF);
  5917. gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR);
  5918.  
  5919. var data = new Float32Array([x, y, x+w, y, x, y+h, x, y+h, x+w, y, x+w, y+h]);
  5920.  
  5921. gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
  5922. gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
  5923. gl.enableVertexAttribArray(shader.aVertexPosition);
  5924. gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
  5925. gl.drawArrays(gl.TRIANGLES, 0, 6);
  5926. gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  5927. }
  5928. };
  5929.  
  5930. // The important members from Pixi.js
  5931.  
  5932. /**
  5933. * The x coordinate of the window layer.
  5934. *
  5935. * @property x
  5936. * @type Number
  5937. */
  5938.  
  5939. /**
  5940. * The y coordinate of the window layer.
  5941. *
  5942. * @property y
  5943. * @type Number
  5944. */
  5945.  
  5946. /**
  5947. * [read-only] The array of children of the window layer.
  5948. *
  5949. * @property children
  5950. * @type Array
  5951. */
  5952.  
  5953. /**
  5954. * [read-only] The object that contains the window layer.
  5955. *
  5956. * @property parent
  5957. * @type Object
  5958. */
  5959.  
  5960. /**
  5961. * Adds a child to the container.
  5962. *
  5963. * @method addChild
  5964. * @param {Object} child The child to add
  5965. * @return {Object} The child that was added
  5966. */
  5967.  
  5968. /**
  5969. * Adds a child to the container at a specified index.
  5970. *
  5971. * @method addChildAt
  5972. * @param {Object} child The child to add
  5973. * @param {Number} index The index to place the child in
  5974. * @return {Object} The child that was added
  5975. */
  5976.  
  5977. /**
  5978. * Removes a child from the container.
  5979. *
  5980. * @method removeChild
  5981. * @param {Object} child The child to remove
  5982. * @return {Object} The child that was removed
  5983. */
  5984.  
  5985. /**
  5986. * Removes a child from the specified index position.
  5987. *
  5988. * @method removeChildAt
  5989. * @param {Number} index The index to get the child from
  5990. * @return {Object} The child that was removed
  5991. */
  5992.  
  5993. //-----------------------------------------------------------------------------
  5994. /**
  5995. * The weather effect which displays rain, storm, or snow.
  5996. *
  5997. * @class Weather
  5998. * @constructor
  5999. */
  6000. function Weather() {
  6001. this.initialize.apply(this, arguments);
  6002. }
  6003.  
  6004. Weather.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
  6005. Weather.prototype.constructor = Weather;
  6006.  
  6007. Weather.prototype.initialize = function() {
  6008. PIXI.DisplayObjectContainer.call(this);
  6009.  
  6010. this._width = Graphics.width;
  6011. this._height = Graphics.height;
  6012. this._sprites = [];
  6013.  
  6014. this._createBitmaps();
  6015. this._createDimmer();
  6016.  
  6017. /**
  6018. * The type of the weather in ['none', 'rain', 'storm', 'snow'].
  6019. *
  6020. * @property type
  6021. * @type String
  6022. */
  6023. this.type = 'none';
  6024.  
  6025. /**
  6026. * The power of the weather in the range (0, 9).
  6027. *
  6028. * @property power
  6029. * @type Number
  6030. */
  6031. this.power = 0;
  6032.  
  6033. /**
  6034. * The origin point of the weather for scrolling.
  6035. *
  6036. * @property origin
  6037. * @type Point
  6038. */
  6039. this.origin = new Point();
  6040. };
  6041.  
  6042. /**
  6043. * Updates the weather for each frame.
  6044. *
  6045. * @method update
  6046. */
  6047. Weather.prototype.update = function() {
  6048. this._updateDimmer();
  6049. this._updateAllSprites();
  6050. };
  6051.  
  6052. /**
  6053. * @method _createBitmaps
  6054. * @private
  6055. */
  6056. Weather.prototype._createBitmaps = function() {
  6057. this._rainBitmap = new Bitmap(1, 60);
  6058. this._rainBitmap.fillAll('white');
  6059. this._stormBitmap = new Bitmap(2, 100);
  6060. this._stormBitmap.fillAll('white');
  6061. this._snowBitmap = new Bitmap(9, 9);
  6062. this._snowBitmap.drawCircle(4, 4, 4, 'white');
  6063. };
  6064.  
  6065. /**
  6066. * @method _createDimmer
  6067. * @private
  6068. */
  6069. Weather.prototype._createDimmer = function() {
  6070. this._dimmerSprite = new ScreenSprite();
  6071. this._dimmerSprite.setColor(80, 80, 80);
  6072. this.addChild(this._dimmerSprite);
  6073. };
  6074.  
  6075. /**
  6076. * @method _updateDimmer
  6077. * @private
  6078. */
  6079. Weather.prototype._updateDimmer = function() {
  6080. this._dimmerSprite.opacity = Math.floor(this.power * 6);
  6081. };
  6082.  
  6083. /**
  6084. * @method _updateAllSprites
  6085. * @private
  6086. */
  6087. Weather.prototype._updateAllSprites = function() {
  6088. var maxSprites = Math.floor(this.power * 10);
  6089. while (this._sprites.length < maxSprites) {
  6090. this._addSprite();
  6091. }
  6092. while (this._sprites.length > maxSprites) {
  6093. this._removeSprite();
  6094. }
  6095. this._sprites.forEach(function(sprite) {
  6096. this._updateSprite(sprite);
  6097. sprite.x = sprite.ax - this.origin.x;
  6098. sprite.y = sprite.ay - this.origin.y;
  6099. }, this);
  6100. };
  6101.  
  6102. /**
  6103. * @method _addSprite
  6104. * @private
  6105. */
  6106. Weather.prototype._addSprite = function() {
  6107. var sprite = new Sprite(this.viewport);
  6108. sprite.opacity = 0;
  6109. this._sprites.push(sprite);
  6110. this.addChild(sprite);
  6111. };
  6112.  
  6113. /**
  6114. * @method _removeSprite
  6115. * @private
  6116. */
  6117. Weather.prototype._removeSprite = function() {
  6118. this.removeChild(this._sprites.pop());
  6119. };
  6120.  
  6121. /**
  6122. * @method _updateSprite
  6123. * @param {Sprite} sprite
  6124. * @private
  6125. */
  6126. Weather.prototype._updateSprite = function(sprite) {
  6127. switch (this.type) {
  6128. case 'rain':
  6129. this._updateRainSprite(sprite);
  6130. break;
  6131. case 'storm':
  6132. this._updateStormSprite(sprite);
  6133. break;
  6134. case 'snow':
  6135. this._updateSnowSprite(sprite);
  6136. break;
  6137. }
  6138. if (sprite.opacity < 40) {
  6139. this._rebornSprite(sprite);
  6140. }
  6141. };
  6142.  
  6143. /**
  6144. * @method _updateRainSprite
  6145. * @param {Sprite} sprite
  6146. * @private
  6147. */
  6148. Weather.prototype._updateRainSprite = function(sprite) {
  6149. sprite.bitmap = this._rainBitmap;
  6150. sprite.rotation = Math.PI / 16;
  6151. sprite.ax -= 6 * Math.sin(sprite.rotation);
  6152. sprite.ay += 6 * Math.cos(sprite.rotation);
  6153. sprite.opacity -= 6;
  6154. };
  6155.  
  6156. /**
  6157. * @method _updateStormSprite
  6158. * @param {Sprite} sprite
  6159. * @private
  6160. */
  6161. Weather.prototype._updateStormSprite = function(sprite) {
  6162. sprite.bitmap = this._stormBitmap;
  6163. sprite.rotation = Math.PI / 8;
  6164. sprite.ax -= 8 * Math.sin(sprite.rotation);
  6165. sprite.ay += 8 * Math.cos(sprite.rotation);
  6166. sprite.opacity -= 8;
  6167. };
  6168.  
  6169. /**
  6170. * @method _updateSnowSprite
  6171. * @param {Sprite} sprite
  6172. * @private
  6173. */
  6174. Weather.prototype._updateSnowSprite = function(sprite) {
  6175. sprite.bitmap = this._snowBitmap;
  6176. sprite.rotation = Math.PI / 16;
  6177. sprite.ax -= 3 * Math.sin(sprite.rotation);
  6178. sprite.ay += 3 * Math.cos(sprite.rotation);
  6179. sprite.opacity -= 3;
  6180. };
  6181.  
  6182. /**
  6183. * @method _rebornSprite
  6184. * @param {Sprite} sprite
  6185. * @private
  6186. */
  6187. Weather.prototype._rebornSprite = function(sprite) {
  6188. sprite.ax = Math.randomInt(Graphics.width + 100) - 100 + this.origin.x;
  6189. sprite.ay = Math.randomInt(Graphics.height + 200) - 200 + this.origin.y;
  6190. sprite.opacity = 160 + Math.randomInt(60);
  6191. };
  6192.  
  6193. //-----------------------------------------------------------------------------
  6194. /**
  6195. * The color matrix filter for WebGL.
  6196. *
  6197. * @class ToneFilter
  6198. * @constructor
  6199. */
  6200. function ToneFilter() {
  6201. PIXI.AbstractFilter.call(this);
  6202. this.initialize.apply(this, arguments);
  6203. }
  6204.  
  6205. ToneFilter.prototype = Object.create(PIXI.AbstractFilter.prototype);
  6206. ToneFilter.prototype.constructor = ToneFilter;
  6207.  
  6208. ToneFilter.prototype.initialize = function() {
  6209. this.passes = [this];
  6210.  
  6211. this.uniforms = {
  6212. matrix: {
  6213. type: 'mat4',
  6214. value: [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]
  6215. }
  6216. };
  6217.  
  6218. this.fragmentSrc = [
  6219. 'precision mediump float;',
  6220. 'varying vec2 vTextureCoord;',
  6221. 'varying vec4 vColor;',
  6222. 'uniform mat4 matrix;',
  6223. 'uniform sampler2D uSampler;',
  6224. 'void main(void) {',
  6225. ' gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;',
  6226. '}'
  6227. ];
  6228. };
  6229.  
  6230. /**
  6231. * Resets the filter.
  6232. *
  6233. * @method reset
  6234. */
  6235. ToneFilter.prototype.reset = function() {
  6236. this.uniforms.matrix.value = [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];
  6237. };
  6238.  
  6239. /**
  6240. * Changes the hue.
  6241. *
  6242. * @method adjustHue
  6243. * @param {Number} value The hue value in the range (-360, 360)
  6244. */
  6245. ToneFilter.prototype.adjustHue = function(value) {
  6246. value = (value || 0) / 180;
  6247.  
  6248. if (value !== 0) {
  6249. var c = Math.cos(value * Math.PI);
  6250. var s = Math.sin(value * Math.PI);
  6251. var a00 = 0.213 + c * 0.787 - s * 0.213;
  6252. var a01 = 0.715 - c * 0.715 - s * 0.715;
  6253. var a02 = 0.072 - c * 0.072 + s * 0.928;
  6254. var a10 = 0.213 - c * 0.213 + s * 0.143;
  6255. var a11 = 0.715 + c * 0.285 + s * 0.140;
  6256. var a12 = 0.072 - c * 0.072 - s * 0.283;
  6257. var a20 = 0.213 - c * 0.213 - s * 0.787;
  6258. var a21 = 0.715 - c * 0.715 + s * 0.715;
  6259. var a22 = 0.072 + c * 0.928 + s * 0.072;
  6260. this._multiplyMatrix([
  6261. a00, a01, a02, 0,
  6262. a10, a11, a12, 0,
  6263. a20, a21, a22, 0,
  6264. 0, 0, 0, 1
  6265. ]);
  6266. }
  6267. };
  6268.  
  6269. /**
  6270. * Changes the saturation.
  6271. *
  6272. * @method adjustSaturation
  6273. * @param {Number} value The saturation value in the range (-255, 255)
  6274. */
  6275. ToneFilter.prototype.adjustSaturation = function(value) {
  6276. value = (value || 0).clamp(-255, 255) / 255;
  6277.  
  6278. if (value !== 0) {
  6279. var a = 1 + value;
  6280. var a00 = 0.213 + 0.787 * a;
  6281. var a01 = 0.715 - 0.715 * a;
  6282. var a02 = 0.072 - 0.072 * a;
  6283. var a10 = 0.213 - 0.213 * a;
  6284. var a11 = 0.715 + 0.285 * a;
  6285. var a12 = 0.072 - 0.072 * a;
  6286. var a20 = 0.213 - 0.213 * a;
  6287. var a21 = 0.715 - 0.715 * a;
  6288. var a22 = 0.072 + 0.928 * a;
  6289. this._multiplyMatrix([
  6290. a00, a01, a02, 0,
  6291. a10, a11, a12, 0,
  6292. a20, a21, a22, 0,
  6293. 0, 0, 0, 1
  6294. ]);
  6295. }
  6296. };
  6297.  
  6298. /**
  6299. * Changes the tone.
  6300. *
  6301. * @method adjustTone
  6302. * @param {Number} r The red strength in the range (-255, 255)
  6303. * @param {Number} g The green strength in the range (-255, 255)
  6304. * @param {Number} b The blue strength in the range (-255, 255)
  6305. */
  6306. ToneFilter.prototype.adjustTone = function(r, g, b) {
  6307. r = (r || 0).clamp(-255, 255) / 255;
  6308. g = (g || 0).clamp(-255, 255) / 255;
  6309. b = (b || 0).clamp(-255, 255) / 255;
  6310.  
  6311. if (r !== 0 || g !== 0 || b !== 0) {
  6312. this._multiplyMatrix([
  6313. 1, 0, 0, r,
  6314. 0, 1, 0, g,
  6315. 0, 0, 1, b,
  6316. 0, 0, 0, 1
  6317. ]);
  6318. }
  6319. };
  6320.  
  6321. /**
  6322. * @method _multiplyMatrix
  6323. * @param {Array} matrix
  6324. * @private
  6325. */
  6326. ToneFilter.prototype._multiplyMatrix = function(matrix) {
  6327. var value = this.uniforms.matrix.value;
  6328. var temp = [];
  6329.  
  6330. for (var i = 0; i < 4; i++) {
  6331. for (var m = 0; m < 4; m++) {
  6332. temp[m] = value[i * 4 + m];
  6333. }
  6334. for (var j = 0; j < 4; j++) {
  6335. var val = 0;
  6336. for (var n = 0; n < 4; n++) {
  6337. val += matrix[n * 4 + j] * temp[n];
  6338. }
  6339. value[i * 4 + j] = val;
  6340. }
  6341. }
  6342. };
  6343.  
  6344. //-----------------------------------------------------------------------------
  6345. /**
  6346. * The sprite which changes the screen color in 2D canvas mode.
  6347. *
  6348. * @class ToneSprite
  6349. * @constructor
  6350. */
  6351. function ToneSprite() {
  6352. this.initialize.apply(this, arguments);
  6353. }
  6354.  
  6355. ToneSprite.prototype = Object.create(PIXI.DisplayObject.prototype);
  6356. ToneSprite.prototype.constructor = ToneSprite;
  6357.  
  6358. ToneSprite.prototype.initialize = function() {
  6359. PIXI.DisplayObject.call(this);
  6360. this.clear();
  6361. };
  6362.  
  6363. /**
  6364. * Clears the tone.
  6365. *
  6366. * @method reset
  6367. */
  6368. ToneSprite.prototype.clear = function() {
  6369. this._red = 0;
  6370. this._green = 0;
  6371. this._blue = 0;
  6372. this._gray = 0;
  6373. };
  6374.  
  6375. /**
  6376. * Sets the tone.
  6377. *
  6378. * @method setTone
  6379. * @param {Number} r The red strength in the range (-255, 255)
  6380. * @param {Number} g The green strength in the range (-255, 255)
  6381. * @param {Number} b The blue strength in the range (-255, 255)
  6382. * @param {Number} gray The grayscale level in the range (0, 255)
  6383. */
  6384. ToneSprite.prototype.setTone = function(r, g, b, gray) {
  6385. this._red = Math.round(r || 0).clamp(-255, 255);
  6386. this._green = Math.round(g || 0).clamp(-255, 255);
  6387. this._blue = Math.round(b || 0).clamp(-255, 255);
  6388. this._gray = Math.round(gray || 0).clamp(0, 255);
  6389. };
  6390.  
  6391. /**
  6392. * @method _renderCanvas
  6393. * @param {Object} renderSession
  6394. * @private
  6395. */
  6396. ToneSprite.prototype._renderCanvas = function(renderSession) {
  6397. if (this.visible) {
  6398. var context = renderSession.context;
  6399. var t = this.worldTransform;
  6400. var r = renderSession.resolution;
  6401. var width = Graphics.width;
  6402. var height = Graphics.height;
  6403. context.save();
  6404. context.setTransform(t.a, t.b, t.c, t.d, t.tx * r, t.ty * r);
  6405. if (Graphics.canUseSaturationBlend() && this._gray > 0) {
  6406. context.globalCompositeOperation = 'saturation';
  6407. context.globalAlpha = this._gray / 255;
  6408. context.fillStyle = '#ffffff';
  6409. context.fillRect(0, 0, width, height);
  6410. }
  6411. context.globalAlpha = 1;
  6412. var r1 = Math.max(0, this._red);
  6413. var g1 = Math.max(0, this._green);
  6414. var b1 = Math.max(0, this._blue);
  6415. if (r1 || g1 || b1) {
  6416. context.globalCompositeOperation = 'lighter';
  6417. context.fillStyle = Utils.rgbToCssColor(r1, g1, b1);
  6418. context.fillRect(0, 0, width, height);
  6419. }
  6420. if (Graphics.canUseDifferenceBlend()) {
  6421. var r2 = Math.max(0, -this._red);
  6422. var g2 = Math.max(0, -this._green);
  6423. var b2 = Math.max(0, -this._blue);
  6424. if (r2 || g2 || b2) {
  6425. context.globalCompositeOperation = 'difference';
  6426. context.fillStyle = '#ffffff';
  6427. context.fillRect(0, 0, width, height);
  6428. context.globalCompositeOperation = 'lighter';
  6429. context.fillStyle = Utils.rgbToCssColor(r2, g2, b2);
  6430. context.fillRect(0, 0, width, height);
  6431. context.globalCompositeOperation = 'difference';
  6432. context.fillStyle = '#ffffff';
  6433. context.fillRect(0, 0, width, height);
  6434. }
  6435. }
  6436. context.restore();
  6437. }
  6438. };
  6439.  
  6440. /**
  6441. * @method _renderWebGL
  6442. * @param {Object} renderSession
  6443. * @private
  6444. */
  6445. ToneSprite.prototype._renderWebGL = function(renderSession) {
  6446. // Not supported
  6447. };
  6448.  
  6449. //-----------------------------------------------------------------------------
  6450. /**
  6451. * The root object of the display tree.
  6452. *
  6453. * @class Stage
  6454. * @constructor
  6455. */
  6456. function Stage() {
  6457. this.initialize.apply(this, arguments);
  6458. }
  6459.  
  6460. Stage.prototype = Object.create(PIXI.Stage.prototype);
  6461. Stage.prototype.constructor = Stage;
  6462.  
  6463. Stage.prototype.initialize = function() {
  6464. PIXI.Stage.call(this);
  6465.  
  6466. // The interactive flag causes a memory leak.
  6467. this.interactive = false;
  6468. };
  6469.  
  6470. /**
  6471. * [read-only] The array of children of the stage.
  6472. *
  6473. * @property children
  6474. * @type Array
  6475. */
  6476.  
  6477. /**
  6478. * Adds a child to the container.
  6479. *
  6480. * @method addChild
  6481. * @param {Object} child The child to add
  6482. * @return {Object} The child that was added
  6483. */
  6484.  
  6485. /**
  6486. * Adds a child to the container at a specified index.
  6487. *
  6488. * @method addChildAt
  6489. * @param {Object} child The child to add
  6490. * @param {Number} index The index to place the child in
  6491. * @return {Object} The child that was added
  6492. */
  6493.  
  6494. /**
  6495. * Removes a child from the container.
  6496. *
  6497. * @method removeChild
  6498. * @param {Object} child The child to remove
  6499. * @return {Object} The child that was removed
  6500. */
  6501.  
  6502. /**
  6503. * Removes a child from the specified index position.
  6504. *
  6505. * @method removeChildAt
  6506. * @param {Number} index The index to get the child from
  6507. * @return {Object} The child that was removed
  6508. */
  6509.  
  6510. //-----------------------------------------------------------------------------
  6511. /**
  6512. * The audio object of Web Audio API.
  6513. *
  6514. * @class WebAudio
  6515. * @constructor
  6516. * @param {String} url The url of the audio file
  6517. */
  6518. function WebAudio() {
  6519. this.initialize.apply(this, arguments);
  6520. }
  6521.  
  6522. WebAudio.prototype.initialize = function(url) {
  6523. if (!WebAudio._initialized) {
  6524. WebAudio.initialize();
  6525. }
  6526. this.clear();
  6527. this._load(url);
  6528. this._url = url;
  6529. };
  6530.  
  6531. WebAudio._context = null;
  6532. WebAudio._masterGainNode = null;
  6533. WebAudio._initialized = false;
  6534. WebAudio._unlocked = false;
  6535.  
  6536. /**
  6537. * Initializes the audio system.
  6538. *
  6539. * @static
  6540. * @method initialize
  6541. * @param {Boolean} noAudio Flag for the no-audio mode
  6542. * @return {Boolean} True if the audio system is available
  6543. */
  6544. WebAudio.initialize = function(noAudio) {
  6545. if (!this._initialized) {
  6546. if (!noAudio) {
  6547. this._createContext();
  6548. this._detectCodecs();
  6549. this._createMasterGainNode();
  6550. this._setupEventHandlers();
  6551. }
  6552. this._initialized = true;
  6553. }
  6554. return !!this._context;
  6555. };
  6556.  
  6557. /**
  6558. * Checks whether the browser can play ogg files.
  6559. *
  6560. * @static
  6561. * @method canPlayOgg
  6562. * @return {Boolean} True if the browser can play ogg files
  6563. */
  6564. WebAudio.canPlayOgg = function() {
  6565. if (!this._initialized) {
  6566. this.initialize();
  6567. }
  6568. return !!this._canPlayOgg;
  6569. };
  6570.  
  6571. /**
  6572. * Checks whether the browser can play m4a files.
  6573. *
  6574. * @static
  6575. * @method canPlayM4a
  6576. * @return {Boolean} True if the browser can play m4a files
  6577. */
  6578. WebAudio.canPlayM4a = function() {
  6579. if (!this._initialized) {
  6580. this.initialize();
  6581. }
  6582. return !!this._canPlayM4a;
  6583. };
  6584.  
  6585. /**
  6586. * @static
  6587. * @method _createContext
  6588. * @private
  6589. */
  6590. WebAudio._createContext = function() {
  6591. try {
  6592. if (typeof AudioContext !== 'undefined') {
  6593. this._context = new AudioContext();
  6594. } else if (typeof webkitAudioContext !== 'undefined') {
  6595. this._context = new webkitAudioContext();
  6596. }
  6597. } catch (e) {
  6598. this._context = null;
  6599. }
  6600. };
  6601.  
  6602. /**
  6603. * @static
  6604. * @method _detectCodecs
  6605. * @private
  6606. */
  6607. WebAudio._detectCodecs = function() {
  6608. var audio = document.createElement('audio');
  6609. if (audio.canPlayType) {
  6610. this._canPlayOgg = audio.canPlayType('audio/ogg');
  6611. this._canPlayM4a = audio.canPlayType('audio/mp4');
  6612. }
  6613. };
  6614.  
  6615. /**
  6616. * @static
  6617. * @method _createMasterGainNode
  6618. * @private
  6619. */
  6620. WebAudio._createMasterGainNode = function() {
  6621. var context = WebAudio._context;
  6622. if (context) {
  6623. this._masterGainNode = context.createGain();
  6624. this._masterGainNode.gain.value = 1;
  6625. this._masterGainNode.connect(context.destination);
  6626. }
  6627. };
  6628.  
  6629. /**
  6630. * @static
  6631. * @method _setupEventHandlers
  6632. * @private
  6633. */
  6634. WebAudio._setupEventHandlers = function() {
  6635. document.addEventListener('touchstart', this._onTouchStart.bind(this));
  6636. document.addEventListener('visibilitychange', this._onVisibilityChange.bind(this));
  6637. };
  6638.  
  6639. /**
  6640. * @static
  6641. * @method _onTouchStart
  6642. * @private
  6643. */
  6644. WebAudio._onTouchStart = function() {
  6645. var context = WebAudio._context;
  6646. if (context && !this._unlocked) {
  6647. // Unlock Web Audio on iOS
  6648. var node = context.createBufferSource();
  6649. node.start(0);
  6650. this._unlocked = true;
  6651. }
  6652. };
  6653.  
  6654. /**
  6655. * @static
  6656. * @method _onVisibilityChange
  6657. * @private
  6658. */
  6659. WebAudio._onVisibilityChange = function() {
  6660. if (document.visibilityState === 'hidden') {
  6661. this._onHide();
  6662. } else {
  6663. this._onShow();
  6664. }
  6665. };
  6666.  
  6667. /**
  6668. * @static
  6669. * @method _onHide
  6670. * @private
  6671. */
  6672. WebAudio._onHide = function() {
  6673. if (this._shouldMuteOnHide()) {
  6674. this._fadeOut(1);
  6675. }
  6676. };
  6677.  
  6678. /**
  6679. * @static
  6680. * @method _onShow
  6681. * @private
  6682. */
  6683. WebAudio._onShow = function() {
  6684. if (this._shouldMuteOnHide()) {
  6685. this._fadeIn(0.5);
  6686. }
  6687. };
  6688.  
  6689. /**
  6690. * @static
  6691. * @method _shouldMuteOnHide
  6692. * @private
  6693. */
  6694. WebAudio._shouldMuteOnHide = function() {
  6695. return Utils.isMobileDevice();
  6696. };
  6697.  
  6698. /**
  6699. * @static
  6700. * @method _fadeIn
  6701. * @param {Number} duration
  6702. * @private
  6703. */
  6704. WebAudio._fadeIn = function(duration) {
  6705. if (this._masterGainNode) {
  6706. var gain = this._masterGainNode.gain;
  6707. var currentTime = WebAudio._context.currentTime;
  6708. gain.setValueAtTime(gain.value, currentTime);
  6709. gain.linearRampToValueAtTime(1, currentTime + duration);
  6710. }
  6711. };
  6712.  
  6713. /**
  6714. * @static
  6715. * @method _fadeOut
  6716. * @param {Number} duration
  6717. * @private
  6718. */
  6719. WebAudio._fadeOut = function(duration) {
  6720. if (this._masterGainNode) {
  6721. var gain = this._masterGainNode.gain;
  6722. var currentTime = WebAudio._context.currentTime;
  6723. gain.setValueAtTime(gain.value, currentTime);
  6724. gain.linearRampToValueAtTime(0, currentTime + duration);
  6725. }
  6726. };
  6727.  
  6728. /**
  6729. * Clears the audio data.
  6730. *
  6731. * @method clear
  6732. */
  6733. WebAudio.prototype.clear = function() {
  6734. this.stop();
  6735. this._buffer = null;
  6736. this._sourceNode = null;
  6737. this._gainNode = null;
  6738. this._pannerNode = null;
  6739. this._totalTime = 0;
  6740. this._sampleRate = 0;
  6741. this._loopStart = 0;
  6742. this._loopLength = 0;
  6743. this._startTime = 0;
  6744. this._volume = 1;
  6745. this._pitch = 1;
  6746. this._pan = 0;
  6747. this._endTimer = null;
  6748. this._loadListeners = [];
  6749. this._stopListeners = [];
  6750. this._hasError = false;
  6751. this._autoPlay = false;
  6752. };
  6753.  
  6754. /**
  6755. * [read-only] The url of the audio file.
  6756. *
  6757. * @property url
  6758. * @type String
  6759. */
  6760. Object.defineProperty(WebAudio.prototype, 'url', {
  6761. get: function() {
  6762. return this._url;
  6763. },
  6764. configurable: true
  6765. });
  6766.  
  6767. /**
  6768. * The volume of the audio.
  6769. *
  6770. * @property volume
  6771. * @type Number
  6772. */
  6773. Object.defineProperty(WebAudio.prototype, 'volume', {
  6774. get: function() {
  6775. return this._volume;
  6776. },
  6777. set: function(value) {
  6778. this._volume = value;
  6779. if (this._gainNode) {
  6780. this._gainNode.gain.value = this._volume;
  6781. }
  6782. },
  6783. configurable: true
  6784. });
  6785.  
  6786. /**
  6787. * The pitch of the audio.
  6788. *
  6789. * @property pitch
  6790. * @type Number
  6791. */
  6792. Object.defineProperty(WebAudio.prototype, 'pitch', {
  6793. get: function() {
  6794. return this._pitch;
  6795. },
  6796. set: function(value) {
  6797. if (this._pitch !== value) {
  6798. this._pitch = value;
  6799. if (this.isPlaying()) {
  6800. this.play(this._sourceNode.loop, 0);
  6801. }
  6802. }
  6803. },
  6804. configurable: true
  6805. });
  6806.  
  6807. /**
  6808. * The pan of the audio.
  6809. *
  6810. * @property pan
  6811. * @type Number
  6812. */
  6813. Object.defineProperty(WebAudio.prototype, 'pan', {
  6814. get: function() {
  6815. return this._pan;
  6816. },
  6817. set: function(value) {
  6818. this._pan = value;
  6819. this._updatePanner();
  6820. },
  6821. configurable: true
  6822. });
  6823.  
  6824. /**
  6825. * Checks whether the audio data is ready to play.
  6826. *
  6827. * @method isReady
  6828. * @return {Boolean} True if the audio data is ready to play
  6829. */
  6830. WebAudio.prototype.isReady = function() {
  6831. return !!this._buffer;
  6832. };
  6833.  
  6834. /**
  6835. * Checks whether a loading error has occurred.
  6836. *
  6837. * @method isError
  6838. * @return {Boolean} True if a loading error has occurred
  6839. */
  6840. WebAudio.prototype.isError = function() {
  6841. return this._hasError;
  6842. };
  6843.  
  6844. /**
  6845. * Checks whether the audio is playing.
  6846. *
  6847. * @method isPlaying
  6848. * @return {Boolean} True if the audio is playing
  6849. */
  6850. WebAudio.prototype.isPlaying = function() {
  6851. return !!this._sourceNode;
  6852. };
  6853.  
  6854. /**
  6855. * Plays the audio.
  6856. *
  6857. * @method play
  6858. * @param {Boolean} loop Whether the audio data play in a loop
  6859. * @param {Number} offset The start position to play in seconds
  6860. */
  6861. WebAudio.prototype.play = function(loop, offset) {
  6862. if (this.isReady()) {
  6863. offset = offset || 0;
  6864. this._startPlaying(loop, offset);
  6865. } else if (WebAudio._context) {
  6866. this._autoPlay = true;
  6867. this.addLoadListener(function() {
  6868. if (this._autoPlay) {
  6869. this.play(loop, offset);
  6870. }
  6871. }.bind(this));
  6872. }
  6873. };
  6874.  
  6875. /**
  6876. * Stops the audio.
  6877. *
  6878. * @method stop
  6879. */
  6880. WebAudio.prototype.stop = function() {
  6881. this._autoPlay = false;
  6882. this._removeEndTimer();
  6883. this._removeNodes();
  6884. if (this._stopListeners) {
  6885. while (this._stopListeners.length > 0) {
  6886. var listner = this._stopListeners.shift();
  6887. listner();
  6888. }
  6889. }
  6890. };
  6891.  
  6892. /**
  6893. * Performs the audio fade-in.
  6894. *
  6895. * @method fadeIn
  6896. * @param {Number} duration Fade-in time in seconds
  6897. */
  6898. WebAudio.prototype.fadeIn = function(duration) {
  6899. if (this.isReady()) {
  6900. if (this._gainNode) {
  6901. var gain = this._gainNode.gain;
  6902. var currentTime = WebAudio._context.currentTime;
  6903. gain.setValueAtTime(0, currentTime);
  6904. gain.linearRampToValueAtTime(this._volume, currentTime + duration);
  6905. }
  6906. } else if (this._autoPlay) {
  6907. this.addLoadListener(function() {
  6908. this.fadeIn(duration);
  6909. }.bind(this));
  6910. }
  6911. };
  6912.  
  6913. /**
  6914. * Performs the audio fade-out.
  6915. *
  6916. * @method fadeOut
  6917. * @param {Number} duration Fade-out time in seconds
  6918. */
  6919. WebAudio.prototype.fadeOut = function(duration) {
  6920. if (this._gainNode) {
  6921. var gain = this._gainNode.gain;
  6922. var currentTime = WebAudio._context.currentTime;
  6923. gain.setValueAtTime(gain.value, currentTime);
  6924. gain.linearRampToValueAtTime(0, currentTime + duration);
  6925. }
  6926. this._autoPlay = false;
  6927. };
  6928.  
  6929. /**
  6930. * Gets the seek position of the audio.
  6931. *
  6932. * @method seek
  6933. */
  6934. WebAudio.prototype.seek = function() {
  6935. if (WebAudio._context) {
  6936. var pos = (WebAudio._context.currentTime - this._startTime) * this._pitch;
  6937. if (this._loopLength > 0) {
  6938. while (pos >= this._loopStart + this._loopLength) {
  6939. pos -= this._loopLength;
  6940. }
  6941. }
  6942. return pos;
  6943. } else {
  6944. return 0;
  6945. }
  6946. };
  6947.  
  6948. /**
  6949. * Add a callback function that will be called when the audio data is loaded.
  6950. *
  6951. * @method addLoadListener
  6952. * @param {Function} listner The callback function
  6953. */
  6954. WebAudio.prototype.addLoadListener = function(listner) {
  6955. this._loadListeners.push(listner);
  6956. };
  6957.  
  6958. /**
  6959. * Add a callback function that will be called when the playback is stopped.
  6960. *
  6961. * @method addStopListener
  6962. * @param {Function} listner The callback function
  6963. */
  6964. WebAudio.prototype.addStopListener = function(listner) {
  6965. this._stopListeners.push(listner);
  6966. };
  6967.  
  6968. /**
  6969. * @method _load
  6970. * @param {String} url
  6971. * @private
  6972. */
  6973. WebAudio.prototype._load = function(url) {
  6974. if (WebAudio._context) {
  6975. var xhr = new XMLHttpRequest();
  6976. xhr.open('GET', url);
  6977. xhr.responseType = 'arraybuffer';
  6978. xhr.onload = function() {
  6979. if (xhr.status < 400) {
  6980. this._onXhrLoad(xhr);
  6981. }
  6982. }.bind(this);
  6983. xhr.onerror = function() {
  6984. this._hasError = true;
  6985. }.bind(this);
  6986. xhr.send();
  6987. }
  6988. };
  6989.  
  6990. /**
  6991. * @method _onXhrLoad
  6992. * @param {XMLHttpRequest} xhr
  6993. * @private
  6994. */
  6995. WebAudio.prototype._onXhrLoad = function(xhr) {
  6996. var array = new Uint8Array(xhr.response);
  6997. this._readLoopComments(array);
  6998. WebAudio._context.decodeAudioData(xhr.response, function(buffer) {
  6999. this._buffer = buffer;
  7000. this._totalTime = buffer.duration;
  7001. if (this._loopLength > 0 && this._sampleRate > 0) {
  7002. this._loopStart /= this._sampleRate;
  7003. this._loopLength /= this._sampleRate;
  7004. } else {
  7005. this._loopStart = 0;
  7006. this._loopLength = this._totalTime;
  7007. }
  7008. this._onLoad();
  7009. }.bind(this));
  7010. };
  7011.  
  7012. /**
  7013. * @method _startPlaying
  7014. * @param {Boolean} loop
  7015. * @param {Number} offset
  7016. * @private
  7017. */
  7018. WebAudio.prototype._startPlaying = function(loop, offset) {
  7019. this._removeEndTimer();
  7020. this._removeNodes();
  7021. this._createNodes();
  7022. this._connectNodes();
  7023. this._sourceNode.loop = loop;
  7024. this._sourceNode.start(0, offset);
  7025. this._startTime = WebAudio._context.currentTime - offset / this._pitch;
  7026. this._createEndTimer();
  7027. };
  7028.  
  7029. /**
  7030. * @method _createNodes
  7031. * @private
  7032. */
  7033. WebAudio.prototype._createNodes = function() {
  7034. var context = WebAudio._context;
  7035. this._sourceNode = context.createBufferSource();
  7036. this._sourceNode.buffer = this._buffer;
  7037. this._sourceNode.loopStart = this._loopStart;
  7038. this._sourceNode.loopEnd = this._loopStart + this._loopLength;
  7039. this._sourceNode.playbackRate.value = this._pitch;
  7040. this._gainNode = context.createGain();
  7041. this._gainNode.gain.value = this._volume;
  7042. this._pannerNode = context.createPanner();
  7043. this._pannerNode.panningModel = 'equalpower';
  7044. this._updatePanner();
  7045. };
  7046.  
  7047. /**
  7048. * @method _connectNodes
  7049. * @private
  7050. */
  7051. WebAudio.prototype._connectNodes = function() {
  7052. this._sourceNode.connect(this._gainNode);
  7053. this._gainNode.connect(this._pannerNode);
  7054. this._pannerNode.connect(WebAudio._masterGainNode);
  7055. };
  7056.  
  7057. /**
  7058. * @method _removeNodes
  7059. * @private
  7060. */
  7061. WebAudio.prototype._removeNodes = function() {
  7062. if (this._sourceNode) {
  7063. this._sourceNode.stop(0);
  7064. this._sourceNode = null;
  7065. this._gainNode = null;
  7066. this._pannerNode = null;
  7067. }
  7068. };
  7069.  
  7070. /**
  7071. * @method _createEndTimer
  7072. * @private
  7073. */
  7074. WebAudio.prototype._createEndTimer = function() {
  7075. if (this._sourceNode && !this._sourceNode.loop) {
  7076. var endTime = this._startTime + this._totalTime / this._pitch;
  7077. var delay = endTime - WebAudio._context.currentTime;
  7078. this._endTimer = setTimeout(function() {
  7079. this.stop();
  7080. }.bind(this), delay * 1000);
  7081. }
  7082. };
  7083.  
  7084. /**
  7085. * @method _removeEndTimer
  7086. * @private
  7087. */
  7088. WebAudio.prototype._removeEndTimer = function() {
  7089. if (this._endTimer) {
  7090. clearTimeout(this._endTimer);
  7091. this._endTimer = null;
  7092. }
  7093. };
  7094.  
  7095. /**
  7096. * @method _updatePanner
  7097. * @private
  7098. */
  7099. WebAudio.prototype._updatePanner = function() {
  7100. if (this._pannerNode) {
  7101. var x = this._pan;
  7102. var z = 1 - Math.abs(x);
  7103. this._pannerNode.setPosition(x, 0, z);
  7104. }
  7105. };
  7106.  
  7107. /**
  7108. * @method _onLoad
  7109. * @private
  7110. */
  7111. WebAudio.prototype._onLoad = function() {
  7112. while (this._loadListeners.length > 0) {
  7113. var listner = this._loadListeners.shift();
  7114. listner();
  7115. }
  7116. };
  7117.  
  7118. /**
  7119. * @method _readLoopComments
  7120. * @param {Uint8Array} array
  7121. * @private
  7122. */
  7123. WebAudio.prototype._readLoopComments = function(array) {
  7124. this._readOgg(array);
  7125. this._readMp4(array);
  7126. };
  7127.  
  7128. /**
  7129. * @method _readOgg
  7130. * @param {Uint8Array} array
  7131. * @private
  7132. */
  7133. WebAudio.prototype._readOgg = function(array) {
  7134. var index = 0;
  7135. while (index < array.length) {
  7136. if (this._readFourCharacters(array, index) === 'OggS') {
  7137. index += 26;
  7138. var vorbisHeaderFound = false;
  7139. var numSegments = array[index++];
  7140. var segments = [];
  7141. for (var i = 0; i < numSegments; i++) {
  7142. segments.push(array[index++]);
  7143. }
  7144. for (i = 0; i < numSegments; i++) {
  7145. if (this._readFourCharacters(array, index + 1) === 'vorb') {
  7146. var headerType = array[index];
  7147. if (headerType === 1) {
  7148. this._sampleRate = this._readLittleEndian(array, index + 12);
  7149. } else if (headerType === 3) {
  7150. this._readMetaData(array, index, segments[i]);
  7151. }
  7152. vorbisHeaderFound = true;
  7153. }
  7154. index += segments[i];
  7155. }
  7156. if (!vorbisHeaderFound) {
  7157. break;
  7158. }
  7159. } else {
  7160. break;
  7161. }
  7162. }
  7163. };
  7164.  
  7165. /**
  7166. * @method _readMp4
  7167. * @param {Uint8Array} array
  7168. * @private
  7169. */
  7170. WebAudio.prototype._readMp4 = function(array) {
  7171. if (this._readFourCharacters(array, 4) === 'ftyp') {
  7172. var index = 0;
  7173. while (index < array.length) {
  7174. var size = this._readBigEndian(array, index);
  7175. var name = this._readFourCharacters(array, index + 4);
  7176. if (name === 'moov') {
  7177. index += 8;
  7178. } else {
  7179. if (name === 'mvhd') {
  7180. this._sampleRate = this._readBigEndian(array, index + 20);
  7181. }
  7182. if (name === 'udta' || name === 'meta') {
  7183. this._readMetaData(array, index, size);
  7184. }
  7185. index += size;
  7186. if (size <= 1) {
  7187. break;
  7188. }
  7189. }
  7190. }
  7191. }
  7192. };
  7193.  
  7194. /**
  7195. * @method _readMetaData
  7196. * @param {Uint8Array} array
  7197. * @param {Number} index
  7198. * @param {Number} size
  7199. * @private
  7200. */
  7201. WebAudio.prototype._readMetaData = function(array, index, size) {
  7202. for (var i = index; i < index + size - 10; i++) {
  7203. if (this._readFourCharacters(array, i) === 'LOOP') {
  7204. var text = '';
  7205. while (array[i] > 0) {
  7206. text += String.fromCharCode(array[i++]);
  7207. }
  7208. if (text.match(/LOOPSTART=([0-9]+)/)) {
  7209. this._loopStart = parseInt(RegExp.$1);
  7210. }
  7211. if (text.match(/LOOPLENGTH=([0-9]+)/)) {
  7212. this._loopLength = parseInt(RegExp.$1);
  7213. }
  7214. if (text == 'LOOPSTART' || text == 'LOOPLENGTH') {
  7215. var text2 = '';
  7216. i += 16;
  7217. while (array[i] > 0) {
  7218. text2 += String.fromCharCode(array[i++]);
  7219. }
  7220. if (text == 'LOOPSTART') {
  7221. this._loopStart = parseInt(text2);
  7222. } else {
  7223. this._loopLength = parseInt(text2);
  7224. }
  7225. }
  7226. }
  7227. }
  7228. };
  7229.  
  7230. /**
  7231. * @method _readLittleEndian
  7232. * @param {Uint8Array} array
  7233. * @param {Number} index
  7234. * @private
  7235. */
  7236. WebAudio.prototype._readLittleEndian = function(array, index) {
  7237. return (array[index + 3] * 0x1000000 + array[index + 2] * 0x10000 +
  7238. array[index + 1] * 0x100 + array[index + 0]);
  7239. };
  7240.  
  7241. /**
  7242. * @method _readBigEndian
  7243. * @param {Uint8Array} array
  7244. * @param {Number} index
  7245. * @private
  7246. */
  7247. WebAudio.prototype._readBigEndian = function(array, index) {
  7248. return (array[index + 0] * 0x1000000 + array[index + 1] * 0x10000 +
  7249. array[index + 2] * 0x100 + array[index + 3]);
  7250. };
  7251.  
  7252. /**
  7253. * @method _readFourCharacters
  7254. * @param {Uint8Array} array
  7255. * @param {Number} index
  7256. * @private
  7257. */
  7258. WebAudio.prototype._readFourCharacters = function(array, index) {
  7259. var string = '';
  7260. for (var i = 0; i < 4; i++) {
  7261. string += String.fromCharCode(array[index + i]);
  7262. }
  7263. return string;
  7264. };
  7265.  
  7266. //-----------------------------------------------------------------------------
  7267. /**
  7268. * The static class that handles HTML5 Audio.
  7269. *
  7270. * @class Html5Audio
  7271. * @constructor
  7272. */
  7273. function Html5Audio() {
  7274. throw new Error('This is a static class');
  7275. }
  7276.  
  7277. Html5Audio._initialized = false;
  7278. Html5Audio._unlocked = false;
  7279. Html5Audio._audioElement = null;
  7280. Html5Audio._gainTweenInterval = null;
  7281. Html5Audio._tweenGain = 0;
  7282. Html5Audio._tweenTargetGain = 0;
  7283. Html5Audio._tweenGainStep = 0;
  7284. Html5Audio._staticSePath = null;
  7285.  
  7286. /**
  7287. * Sets up the Html5 Audio.
  7288. *
  7289. * @static
  7290. * @method setup
  7291. * @param {String} url The url of the audio file
  7292. */
  7293. Html5Audio.setup = function (url) {
  7294. if (!this._initialized) {
  7295. this.initialize();
  7296. }
  7297. this.clear();
  7298. this._url = url;
  7299. };
  7300.  
  7301. /**
  7302. * Initializes the audio system.
  7303. *
  7304. * @static
  7305. * @method initialize
  7306. * @return {Boolean} True if the audio system is available
  7307. */
  7308. Html5Audio.initialize = function () {
  7309. if (!this._initialized) {
  7310. if (!this._audioElement) {
  7311. try {
  7312. this._audioElement = new Audio();
  7313. } catch (e) {
  7314. this._audioElement = null;
  7315. }
  7316. }
  7317. if (!!this._audioElement) this._setupEventHandlers();
  7318. this._initialized = true;
  7319. }
  7320. return !!this._audioElement;
  7321. };
  7322.  
  7323. /**
  7324. * @static
  7325. * @method _setupEventHandlers
  7326. * @private
  7327. */
  7328. Html5Audio._setupEventHandlers = function () {
  7329. document.addEventListener('touchstart', this._onTouchStart.bind(this));
  7330. document.addEventListener('visibilitychange', this._onVisibilityChange.bind(this));
  7331. this._audioElement.addEventListener("loadeddata", this._onLoadedData.bind(this));
  7332. this._audioElement.addEventListener("error", this._onError.bind(this));
  7333. this._audioElement.addEventListener("ended", this._onEnded.bind(this));
  7334. };
  7335.  
  7336. /**
  7337. * @static
  7338. * @method _onTouchStart
  7339. * @private
  7340. */
  7341. Html5Audio._onTouchStart = function () {
  7342. if (this._audioElement && !this._unlocked) {
  7343. if (this._isLoading) {
  7344. this._load(this._url);
  7345. this._unlocked = true;
  7346. } else {
  7347. if (this._staticSePath) {
  7348. this._audioElement.src = this._staticSePath;
  7349. this._audioElement.volume = 0;
  7350. this._audioElement.loop = false;
  7351. this._audioElement.play();
  7352. this._unlocked = true;
  7353. }
  7354. }
  7355. }
  7356. };
  7357.  
  7358. /**
  7359. * @static
  7360. * @method _onVisibilityChange
  7361. * @private
  7362. */
  7363. Html5Audio._onVisibilityChange = function () {
  7364. if (document.visibilityState === 'hidden') {
  7365. this._onHide();
  7366. } else {
  7367. this._onShow();
  7368. }
  7369. };
  7370.  
  7371. /**
  7372. * @static
  7373. * @method _onLoadedData
  7374. * @private
  7375. */
  7376. Html5Audio._onLoadedData = function () {
  7377. this._buffered = true;
  7378. if (this._unlocked) this._onLoad();
  7379. };
  7380.  
  7381. /**
  7382. * @static
  7383. * @method _onError
  7384. * @private
  7385. */
  7386. Html5Audio._onError = function () {
  7387. this._hasError = true;
  7388. };
  7389.  
  7390. /**
  7391. * @static
  7392. * @method _onEnded
  7393. * @private
  7394. */
  7395. Html5Audio._onEnded = function () {
  7396. if (!this._audioElement.loop) {
  7397. this.stop();
  7398. }
  7399. };
  7400.  
  7401. /**
  7402. * @static
  7403. * @method _onHide
  7404. * @private
  7405. */
  7406. Html5Audio._onHide = function () {
  7407. this._audioElement.volume = 0;
  7408. this._tweenGain = 0;
  7409. };
  7410.  
  7411. /**
  7412. * @static
  7413. * @method _onShow
  7414. * @private
  7415. */
  7416. Html5Audio._onShow = function () {
  7417. this.fadeIn(0.5);
  7418. };
  7419.  
  7420. /**
  7421. * Clears the audio data.
  7422. *
  7423. * @static
  7424. * @method clear
  7425. */
  7426. Html5Audio.clear = function () {
  7427. this.stop();
  7428. this._volume = 1;
  7429. this._loadListeners = [];
  7430. this._hasError = false;
  7431. this._autoPlay = false;
  7432. this._isLoading = false;
  7433. this._buffered = false;
  7434. };
  7435.  
  7436. /**
  7437. * Set the URL of static se.
  7438. *
  7439. * @static
  7440. * @param {String} url
  7441. */
  7442. Html5Audio.setStaticSe = function (url) {
  7443. if (!this._initialized) {
  7444. this.initialize();
  7445. this.clear();
  7446. }
  7447. this._staticSePath = url;
  7448. };
  7449.  
  7450. /**
  7451. * [read-only] The url of the audio file.
  7452. *
  7453. * @property url
  7454. * @type String
  7455. */
  7456. Object.defineProperty(Html5Audio, 'url', {
  7457. get: function () {
  7458. return Html5Audio._url;
  7459. },
  7460. configurable: true
  7461. });
  7462.  
  7463. /**
  7464. * The volume of the audio.
  7465. *
  7466. * @property volume
  7467. * @type Number
  7468. */
  7469. Object.defineProperty(Html5Audio, 'volume', {
  7470. get: function () {
  7471. return Html5Audio._volume;
  7472. }.bind(this),
  7473. set: function (value) {
  7474. Html5Audio._volume = value;
  7475. if (Html5Audio._audioElement) {
  7476. Html5Audio._audioElement.volume = this._volume;
  7477. }
  7478. },
  7479. configurable: true
  7480. });
  7481.  
  7482. /**
  7483. * Checks whether the audio data is ready to play.
  7484. *
  7485. * @static
  7486. * @method isReady
  7487. * @return {Boolean} True if the audio data is ready to play
  7488. */
  7489. Html5Audio.isReady = function () {
  7490. return this._buffered;
  7491. };
  7492.  
  7493. /**
  7494. * Checks whether a loading error has occurred.
  7495. *
  7496. * @static
  7497. * @method isError
  7498. * @return {Boolean} True if a loading error has occurred
  7499. */
  7500. Html5Audio.isError = function () {
  7501. return this._hasError;
  7502. };
  7503.  
  7504. /**
  7505. * Checks whether the audio is playing.
  7506. *
  7507. * @static
  7508. * @method isPlaying
  7509. * @return {Boolean} True if the audio is playing
  7510. */
  7511. Html5Audio.isPlaying = function () {
  7512. return !this._audioElement.paused;
  7513. };
  7514.  
  7515. /**
  7516. * Plays the audio.
  7517. *
  7518. * @static
  7519. * @method play
  7520. * @param {Boolean} loop Whether the audio data play in a loop
  7521. * @param {Number} offset The start position to play in seconds
  7522. */
  7523. Html5Audio.play = function (loop, offset) {
  7524. if (this.isReady()) {
  7525. offset = offset || 0;
  7526. this._startPlaying(loop, offset);
  7527. } else if (Html5Audio._audioElement) {
  7528. this._autoPlay = true;
  7529. this.addLoadListener(function () {
  7530. if (this._autoPlay) {
  7531. this.play(loop, offset);
  7532. if (this._gainTweenInterval) {
  7533. clearInterval(this._gainTweenInterval);
  7534. this._gainTweenInterval = null;
  7535. }
  7536. }
  7537. }.bind(this));
  7538. if (!this._isLoading) this._load(this._url);
  7539. }
  7540. };
  7541.  
  7542. /**
  7543. * Stops the audio.
  7544. *
  7545. * @static
  7546. * @method stop
  7547. */
  7548. Html5Audio.stop = function () {
  7549. if (this._audioElement) this._audioElement.pause();
  7550. this._autoPlay = false;
  7551. if (this._tweenInterval) {
  7552. clearInterval(this._tweenInterval);
  7553. this._tweenInterval = null;
  7554. this._audioElement.volume = 0;
  7555. }
  7556. };
  7557.  
  7558. /**
  7559. * Performs the audio fade-in.
  7560. *
  7561. * @static
  7562. * @method fadeIn
  7563. * @param {Number} duration Fade-in time in seconds
  7564. */
  7565. Html5Audio.fadeIn = function (duration) {
  7566. if (this.isReady()) {
  7567. if (this._audioElement) {
  7568. this._tweenTargetGain = this._volume;
  7569. this._tweenGain = 0;
  7570. this._startGainTween(duration);
  7571. }
  7572. } else if (this._autoPlay) {
  7573. this.addLoadListener(function () {
  7574. this.fadeIn(duration);
  7575. }.bind(this));
  7576. }
  7577. };
  7578.  
  7579. /**
  7580. * Performs the audio fade-out.
  7581. *
  7582. * @static
  7583. * @method fadeOut
  7584. * @param {Number} duration Fade-out time in seconds
  7585. */
  7586. Html5Audio.fadeOut = function (duration) {
  7587. if (this._audioElement) {
  7588. this._tweenTargetGain = 0;
  7589. this._tweenGain = this._volume;
  7590. this._startGainTween(duration);
  7591. }
  7592. };
  7593.  
  7594. /**
  7595. * Gets the seek position of the audio.
  7596. *
  7597. * @static
  7598. * @method seek
  7599. */
  7600. Html5Audio.seek = function () {
  7601. if (this._audioElement) {
  7602. return this._audioElement.currentTime;
  7603. } else {
  7604. return 0;
  7605. }
  7606. };
  7607.  
  7608. /**
  7609. * Add a callback function that will be called when the audio data is loaded.
  7610. *
  7611. * @static
  7612. * @method addLoadListener
  7613. * @param {Function} listner The callback function
  7614. */
  7615. Html5Audio.addLoadListener = function (listner) {
  7616. this._loadListeners.push(listner);
  7617. };
  7618.  
  7619. /**
  7620. * @static
  7621. * @method _load
  7622. * @param {String} url
  7623. * @private
  7624. */
  7625. Html5Audio._load = function (url) {
  7626. if (this._audioElement) {
  7627. this._isLoading = true;
  7628. this._audioElement.src = url;
  7629. this._audioElement.load();
  7630. }
  7631. };
  7632.  
  7633. /**
  7634. * @static
  7635. * @method _startPlaying
  7636. * @param {Boolean} loop
  7637. * @param {Number} offset
  7638. * @private
  7639. */
  7640. Html5Audio._startPlaying = function (loop, offset) {
  7641. this._audioElement.loop = loop;
  7642. if (this._gainTweenInterval) {
  7643. clearInterval(this._gainTweenInterval);
  7644. this._gainTweenInterval = null;
  7645. }
  7646. if (this._audioElement) {
  7647. this._audioElement.volume = this._volume;
  7648. this._audioElement.currentTime = offset;
  7649. this._audioElement.play();
  7650. }
  7651. };
  7652.  
  7653. /**
  7654. * @static
  7655. * @method _onLoad
  7656. * @private
  7657. */
  7658. Html5Audio._onLoad = function () {
  7659. this._isLoading = false;
  7660. while (this._loadListeners.length > 0) {
  7661. var listener = this._loadListeners.shift();
  7662. listener();
  7663. }
  7664. };
  7665.  
  7666. /**
  7667. * @static
  7668. * @method _startGainTween
  7669. * @params {Number} duration
  7670. * @private
  7671. */
  7672. Html5Audio._startGainTween = function (duration) {
  7673. this._audioElement.volume = this._tweenGain;
  7674. if (this._gainTweenInterval) {
  7675. clearInterval(this._gainTweenInterval);
  7676. this._gainTweenInterval = null;
  7677. }
  7678. this._tweenGainStep = (this._tweenTargetGain - this._tweenGain) / (60 * duration);
  7679. this._gainTweenInterval = setInterval(function () {
  7680. Html5Audio._applyTweenValue(Html5Audio._tweenTargetGain);
  7681. }, 1000 / 60);
  7682. };
  7683.  
  7684. /**
  7685. * @static
  7686. * @method _applyTweenValue
  7687. * @param {Number} volume
  7688. * @private
  7689. */
  7690. Html5Audio._applyTweenValue = function (volume) {
  7691. Html5Audio._tweenGain += Html5Audio._tweenGainStep;
  7692. if (Html5Audio._tweenGain < 0 && Html5Audio._tweenGainStep < 0) {
  7693. Html5Audio._tweenGain = 0;
  7694. }
  7695. else if (Html5Audio._tweenGain > volume && Html5Audio._tweenGainStep > 0) {
  7696. Html5Audio._tweenGain = volume;
  7697. }
  7698.  
  7699. if (Math.abs(Html5Audio._tweenTargetGain - Html5Audio._tweenGain) < 0.01) {
  7700. Html5Audio._tweenGain = Html5Audio._tweenTargetGain;
  7701. clearInterval(Html5Audio._gainTweenInterval);
  7702. Html5Audio._gainTweenInterval = null;
  7703. }
  7704.  
  7705. Html5Audio._audioElement.volume = Html5Audio._tweenGain;
  7706. };
  7707.  
  7708. //-----------------------------------------------------------------------------
  7709. /**
  7710. * The static class that handles JSON with object information.
  7711. *
  7712. * @class JsonEx
  7713. */
  7714. function JsonEx() {
  7715. throw new Error('This is a static class');
  7716. }
  7717.  
  7718. /**
  7719. * The maximum depth of objects.
  7720. *
  7721. * @static
  7722. * @property maxDepth
  7723. * @type Number
  7724. * @default 100
  7725. */
  7726. JsonEx.maxDepth = 100;
  7727.  
  7728. /**
  7729. * Converts an object to a JSON string with object information.
  7730. *
  7731. * @static
  7732. * @method stringify
  7733. * @param {Object} object The object to be converted
  7734. * @return {String} The JSON string
  7735. */
  7736. JsonEx.stringify = function(object) {
  7737. return JSON.stringify(this._encode(object));
  7738. };
  7739.  
  7740. /**
  7741. * Parses a JSON string and reconstructs the corresponding object.
  7742. *
  7743. * @static
  7744. * @method parse
  7745. * @param {String} json The JSON string
  7746. * @return {Object} The reconstructed object
  7747. */
  7748. JsonEx.parse = function(json) {
  7749. return this._decode(JSON.parse(json));
  7750. };
  7751.  
  7752. /**
  7753. * Makes a deep copy of the specified object.
  7754. *
  7755. * @static
  7756. * @method makeDeepCopy
  7757. * @param {Object} object The object to be copied
  7758. * @return {Object} The copied object
  7759. */
  7760. JsonEx.makeDeepCopy = function(object) {
  7761. return this.parse(this.stringify(object));
  7762. };
  7763.  
  7764. /**
  7765. * @static
  7766. * @method _encode
  7767. * @param {Object} value
  7768. * @param {Number} depth
  7769. * @return {Object}
  7770. * @private
  7771. */
  7772. JsonEx._encode = function(value, depth) {
  7773. depth = depth || 0;
  7774. if (++depth >= this.maxDepth) {
  7775. throw new Error('Object too deep');
  7776. }
  7777. var type = Object.prototype.toString.call(value);
  7778. if (type === '[object Object]' || type === '[object Array]') {
  7779. var constructorName = this._getConstructorName(value);
  7780. if (constructorName !== 'Object' && constructorName !== 'Array') {
  7781. value['@'] = constructorName;
  7782. }
  7783. for (var key in value) {
  7784. if (value.hasOwnProperty(key)) {
  7785. value[key] = this._encode(value[key], depth + 1);
  7786. }
  7787. }
  7788. }
  7789. depth--;
  7790. return value;
  7791. };
  7792.  
  7793. /**
  7794. * @static
  7795. * @method _decode
  7796. * @param {Object} value
  7797. * @return {Object}
  7798. * @private
  7799. */
  7800. JsonEx._decode = function(value) {
  7801. var type = Object.prototype.toString.call(value);
  7802. if (type === '[object Object]' || type === '[object Array]') {
  7803. if (value['@']) {
  7804. var constructor = window[value['@']];
  7805. if (constructor) {
  7806. value = this._resetPrototype(value, constructor.prototype);
  7807. }
  7808. }
  7809. for (var key in value) {
  7810. if (value.hasOwnProperty(key)) {
  7811. value[key] = this._decode(value[key]);
  7812. }
  7813. }
  7814. }
  7815. return value;
  7816. };
  7817.  
  7818. /**
  7819. * @static
  7820. * @method _getConstructorName
  7821. * @param {Object} value
  7822. * @return {String}
  7823. * @private
  7824. */
  7825. JsonEx._getConstructorName = function(value) {
  7826. var name = value.constructor.name;
  7827. if (name === undefined) {
  7828. var func = /^\s*function\s*([A-Za-z0-9_$]*)/;
  7829. name = func.exec(value.constructor)[1];
  7830. }
  7831. return name;
  7832. };
  7833.  
  7834. /**
  7835. * @static
  7836. * @method _resetPrototype
  7837. * @param {Object} value
  7838. * @param {Object} prototype
  7839. * @return {Object}
  7840. * @private
  7841. */
  7842. JsonEx._resetPrototype = function(value, prototype) {
  7843. if (Object.setPrototypeOf !== undefined) {
  7844. Object.setPrototypeOf(value, prototype);
  7845. } else if ('__proto__' in value) {
  7846. value.__proto__ = prototype;
  7847. } else {
  7848. var newValue = Object.create(prototype);
  7849. for (var key in value) {
  7850. if (value.hasOwnProperty(key)) {
  7851. newValue[key] = value[key];
  7852. }
  7853. }
  7854. value = newValue;
  7855. }
  7856. return value;
  7857. };
Advertisement
Add Comment
Please, Sign In to add comment