├── bosu.mp3
├── hakai.mp3
├── mogura.png
├── index.html
├── main.js
└── enchant.js
/bosu.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ixkaito/moguratataki/master/bosu.mp3
--------------------------------------------------------------------------------
/hakai.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ixkaito/moguratataki/master/hakai.mp3
--------------------------------------------------------------------------------
/mogura.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ixkaito/moguratataki/master/mogura.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | enchant();
2 | //ドロイド君の出現数
3 | maxDroid = 30;
4 |
5 |
6 |
7 | //穴クラスの定義
8 | Pit = Class.create(Sprite,{ //Spriteクラスを継承する
9 | initialize:function(x,y){
10 | enchant.Sprite.call(this,48,48); //Spriteクラスのコンストラクタ呼び出し
11 | this.image = game.assets['mogura.png'];
12 | this.x = x;
13 | this.y = y;
14 | this.addEventListener('enterframe',this.tick); //イベントリスナーを定義
15 | this.addEventListener('touchstart',this.hit); //叩いた場合のイベントリスナーを定義
16 | this.mode = 2; //ドロイド君の出現モードを待つ、からに設定
17 | this.nextMode = 0;
18 | this.waitFor = game.frame+Math.floor(Math.random()*100);
19 | },
20 | tick:function(){ //ドロイド君が出るアニメーションを繰り返す
21 | if(game.frame%2!=0)return; //4フレームごとに実行する
22 | switch(this.mode){
23 | case 0: //穴からドロイド君がでてくる
24 | this.frame++;
25 | if(this.frame>=4){
26 | this.mode=2; //出切ったら、待つモードへ
27 | this.nextMode=1;//待った後に遷移するモードは1(隠れる)
28 | this.waitFor = game.frame+Math.floor(Math.random()*30);
29 | }
30 | break;
31 | case 1://ドロイド君が穴に隠れる
32 | this.frame--;
33 | if(this.frame<=0){
34 | this.mode=2; //出切ったら、待つモードへ
35 | this.nextMode=0;//待った後に遷移するモードは0(出現)
36 | this.waitFor = game.frame+Math.floor(Math.random()*200);
37 |
38 | //ドロイド君の最大数を減らす
39 | maxDroid--;
40 | //もしこれ以上ドロイド君は出現しないなら、穴を塞ぐ
41 | if(maxDroid<=0)this.mode=3;
42 | }
43 | break;
44 | case 2://待つ
45 | if(game.frame>this.waitFor){
46 | this.mode = this.nextMode;
47 | }
48 | break;
49 | case 3://なにもしない(この穴からもうドロイド君は出ない)
50 | break;
51 | }
52 | },
53 | hit:function(){ //ドロイド君を殴る
54 | if(this.frame==5)return;//既に殴れた状態だったらなにもしない
55 | if(this.frame>=2){ // ドロイド君が半分以上出ていた場合
56 | this.frame=5; //殴れたドロイド君
57 | this.mode=2; //待ちモードに入る
58 | this.nextMode=1;
59 | this.waitFor = game.frame+10; //待つフレーム数は10で一定
60 | scoreLabel.add(1); //スコアに追加
61 | var sound1 = game.assets['hakai.mp3'].clone();
62 | sound1.play();
63 | }
64 | }
65 | });
66 | //ScoreLabelクラスの定義
67 | ScoreLabel = Class.create(Label,{ //Labelクラスを継承する
68 | initialize:function(x,y){
69 | enchant.Label.call(this,"SCORE:0"); //Labelクラスのコンストラクタ呼び出し
70 | this.x=x;
71 | this.y=y;
72 | this.score = 0;
73 | },
74 | add:function(pts){ //スコアを加算
75 | this.score+=pts;
76 | this.text="SCORE:"+this.score; //表示を修正
77 | }
78 | });
79 |
80 | window.onload = function(){//初期化
81 |
82 | setTimeout(function() {
83 |
84 | enchant.Sound.enabledInMobileSafari = true;
85 | game = new Game(320, 320);
86 | game.preload('mogura.png');//ドロイド君画像を読み込み
87 | game.preload('hakai.mp3');
88 | game.preload('bosu.mp3');
89 | game.onload = function(){
90 |
91 | var sound2 = game.assets['bosu.mp3'].clone();
92 | sound2.play();
93 |
94 | //スコアラベルを表示
95 | scoreLabel=new ScoreLabel(5,5);
96 | game.rootScene.addChild(scoreLabel);
97 |
98 | //穴を4x4に並べる
99 | for(y=0;y<4;y++){
100 | for(x=0;x<4;x++){
101 | var pit = new Pit(x*48+20,y*48+20);
102 | game.rootScene.addChild(pit);
103 | }
104 | }
105 | }
106 | game.start();
107 |
108 | }, 500);
109 | }
110 |
--------------------------------------------------------------------------------
/enchant.js:
--------------------------------------------------------------------------------
1 | /**
2 | * enchant.js v0.4.0
3 | *
4 | * Copyright (c) Ubiquitous Entertainment Inc.
5 | * Dual licensed under the MIT or GPL Version 3 licenses
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | * This program is free software: you can redistribute it and/or modify
26 | * it under the terms of the GNU General Public License as published by
27 | * the Free Software Foundation, either version 3 of the License, or
28 | * (at your option) any later version.
29 | *
30 | * This program is distributed in the hope that it will be useful,
31 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | * GNU General Public License for more details.
34 | *
35 | * You should have received a copy of the GNU General Public License
36 | * along with this program. If not, see .
37 | */
38 |
39 | if (typeof Object.defineProperty != 'function') {
40 | Object.defineProperty = function(obj, prop, desc) {
41 | if ('value' in desc) obj[prop] = desc.value;
42 | if ('get' in desc) obj.__defineGetter__(prop, desc.get);
43 | if ('set' in desc) obj.__defineSetter__(prop, desc.set);
44 | return obj;
45 | };
46 | }
47 | if (typeof Object.defineProperties != 'function') {
48 | Object.defineProperties = function(obj, descs) {
49 | for (var prop in descs) if (descs.hasOwnProperty(prop)) {
50 | Object.defineProperty(obj, prop, descs[prop]);
51 | }
52 | return obj;
53 | };
54 | }
55 | if (typeof Object.create != 'function') {
56 | Object.create = function(prototype, descs) {
57 | function F() {};
58 | F.prototype = prototype;
59 | var obj = new F();
60 | if (descs != null) Object.defineProperties(obj, descs);
61 | return obj;
62 | };
63 | }
64 | if (typeof Object.getPrototypeOf != 'function') {
65 | Object.getPrototypeOf = function(obj) {
66 | return obj.__proto__;
67 | };
68 | }
69 |
70 | /**
71 | * グローバルにライブラリのクラスをエクスポートする.
72 | *
73 | * 引数に何も渡さない場合enchant.jsで定義されたクラス及びプラグインで定義されたクラス
74 | * 全てがエクスポートされる. 引数が一つ以上の場合はenchant.jsで定義されたクラスのみ
75 | * がデフォルトでエクスポートされ, プラグインのクラスをエクスポートしたい場合は明示的に
76 | * プラグインの識別子を引数として渡す必要がある.
77 | *
78 | * @example
79 | * enchant(); // 全てのクラスがエクスポートされる
80 | * enchant(''); // enchant.js本体のクラスのみがエクスポートされる
81 | * enchant('ui'); // enchant.js本体のクラスとui.enchant.jsのクラスがエクスポートされる
82 | *
83 | * @param {...String} [modules] エクスポートするモジュール. 複数指定できる.
84 | */
85 | var enchant = function(modules) {
86 | if (modules != null) {
87 | if (!(modules instanceof Array)) {
88 | modules = Array.prototype.slice.call(arguments);
89 | }
90 | modules = modules.filter(function(module) {
91 | return [module].join();
92 | });
93 | }
94 |
95 | (function include(module, prefix) {
96 | var submodules = [];
97 | for (var prop in module) if (module.hasOwnProperty(prop)) {
98 | if (typeof module[prop] == 'function') {
99 | window[prop] = module[prop];
100 | } else if (Object.getPrototypeOf(module[prop]) == Object.prototype) {
101 | if (modules == null) {
102 | submodules.push(prop);
103 | } else {
104 | i = modules.indexOf(prefix + prop);
105 | if (i != -1) {
106 | submodules.push(prop);
107 | modules.splice(i, 1);
108 | }
109 | }
110 | }
111 | }
112 | for (var i = 0, len = submodules.length; i < len; i++) {
113 | include(module[submodules[i]], prefix + submodules[i] + '.');
114 | }
115 | })(enchant, '');
116 |
117 | if (modules != null && modules.length) {
118 | throw new Error('Cannot load module: ' + modules.join(', '));
119 | }
120 | };
121 |
122 | (function() {
123 |
124 | "use strict";
125 |
126 | var VENDER_PREFIX = (function() {
127 | var ua = navigator.userAgent;
128 | if (ua.indexOf('Opera') != -1) {
129 | return 'O';
130 | } else if (ua.indexOf('MSIE') != -1) {
131 | return 'ms';
132 | } else if (ua.indexOf('WebKit') != -1) {
133 | return 'webkit';
134 | } else if (navigator.product == 'Gecko') {
135 | return 'Moz';
136 | } else {
137 | return '';
138 | }
139 | })();
140 | var TOUCH_ENABLED = (function() {
141 | var div = document.createElement('div');
142 | div.setAttribute('ontouchstart', 'return');
143 | return typeof div.ontouchstart == 'function';
144 | })();
145 | var RETINA_DISPLAY = (function() {
146 | if (navigator.userAgent.indexOf('iPhone') != -1 && window.devicePixelRatio == 2) {
147 | var viewport = document.querySelector('meta[name="viewport"]');
148 | if (viewport == null) {
149 | viewport = document.createElement('meta');
150 | document.head.appendChild(viewport);
151 | }
152 | viewport.setAttribute('content', 'width=640px');
153 | return true;
154 | } else {
155 | return false;
156 | }
157 | })();
158 |
159 | // the running instance
160 | var game;
161 |
162 | /**
163 | * クラスのクラス.
164 | *
165 | * @param {Function} [superclass] 継承するクラス.
166 | * @param {*} definition クラス定義.
167 | * @constructor
168 | */
169 | enchant.Class = function(superclass, definition) {
170 | return enchant.Class.create(superclass, definition);
171 | };
172 |
173 | /**
174 | * クラスを作成する.
175 | *
176 | * ほかのクラスを継承したクラスを作成する場合, コンストラクタはデフォルトで
177 | * 継承元のクラスのものが使われる. コンストラクタをオーバーライドする場合継承元の
178 | * コンストラクタを適用するには明示的に呼び出す必要がある.
179 | *
180 | * @example
181 | * var Ball = Class.create({ // 何も継承しないクラスを作成する
182 | * initialize: function(radius) { ... }, // メソッド定義
183 | * fall: function() { ... }
184 | * });
185 | *
186 | * var Ball = Class.create(Sprite); // Spriteを継承したクラスを作成する
187 | * var Ball = Class.create(Sprite, { // Spriteを継承したクラスを作成する
188 | * initialize: function(radius) { // コンストラクタを上書きする
189 | * Sprite.call(this, radius*2, radius*2); // 継承元のコンストラクタを適用する
190 | * this.image = game.assets['ball.gif'];
191 | * }
192 | * });
193 | *
194 | * @param {Function} [superclass] 継承するクラス.
195 | * @param {*} [definition] クラス定義.
196 | * @static
197 | */
198 | enchant.Class.create = function(superclass, definition) {
199 | if (arguments.length == 0) {
200 | return enchant.Class.create(Object, definition);
201 | } else if (arguments.length == 1 && typeof arguments[0] != 'function') {
202 | return enchant.Class.create(Object, arguments[0]);
203 | }
204 |
205 | for (var prop in definition) if (definition.hasOwnProperty(prop)) {
206 | if (Object.getPrototypeOf(definition[prop]) == Object.prototype) {
207 | if (!('enumerable' in definition[prop])) definition[prop].enumerable = true;
208 | } else {
209 | definition[prop] = { value: definition[prop], enumerable: true, writable: true };
210 | }
211 | }
212 | var constructor = function() {
213 | if (this instanceof constructor) {
214 | constructor.prototype.initialize.apply(this, arguments);
215 | } else {
216 | return new constructor();
217 | }
218 | };
219 | constructor.prototype = Object.create(superclass.prototype, definition);
220 | constructor.prototype.constructor = constructor;
221 | if (constructor.prototype.initialize == null) {
222 | constructor.prototype.initialize = function() {
223 | superclass.apply(this, arguments);
224 | };
225 | }
226 | return constructor;
227 | };
228 |
229 | /**
230 | * @scope enchant.Event.prototype
231 | */
232 | enchant.Event = enchant.Class.create({
233 | /**
234 | * DOM Event風味の独自イベント実装を行ったクラス.
235 | * ただしフェーズの概念はなし.
236 | * @param {String} type Eventのタイプ
237 | * @constructs
238 | */
239 | initialize: function(type) {
240 | /**
241 | * イベントのタイプ.
242 | * @type {String}
243 | */
244 | this.type = type;
245 | /**
246 | * イベントのターゲット.
247 | * @type {*}
248 | */
249 | this.target = null;
250 | /**
251 | * イベント発生位置のx座標.
252 | * @type {Number}
253 | */
254 | this.x = 0;
255 | /**
256 | * イベント発生位置のy座標.
257 | * @type {Number}
258 | */
259 | this.y = 0;
260 | /**
261 | * イベントを発行したオブジェクトを基準とするイベント発生位置のx座標.
262 | * @type {Number}
263 | */
264 | this.localX = 0;
265 | /**
266 | * イベントを発行したオブジェクトを基準とするイベント発生位置のy座標.
267 | * @type {Number}
268 | */
269 | this.localY = 0;
270 | },
271 | _initPosition: function(pageX, pageY) {
272 | this.x = this.localX = (pageX - game._pageX) / game.scale;
273 | this.y = this.localY = (pageY - game._pageY) / game.scale;
274 | }
275 | });
276 |
277 | /**
278 | * Gameのロード完了時に発生するイベント.
279 | *
280 | * 画像のプリロードを行う場合ロードが完了するのを待ってゲーム開始時の処理を行う必要がある.
281 | * 発行するオブジェクト: enchant.Game
282 | *
283 | * @example
284 | * var game = new Game(320, 320);
285 | * game.preload('player.gif');
286 | * game.onload = function() {
287 | * ... // ゲーム開始時の処理を記述
288 | * };
289 | * game.start();
290 | *
291 | * @type {String}
292 | */
293 | enchant.Event.LOAD = 'load';
294 |
295 | /**
296 | * Gameのロード進行中に発生するイベント.
297 | * プリロードする画像が一枚ロードされる度に発行される. 発行するオブジェクト: enchant.Game
298 | * @type {String}
299 | */
300 | enchant.Event.PROGRESS = 'progress';
301 |
302 | /**
303 | * フレーム開始時に発生するイベント.
304 | * 発行するオブジェクト: enchant.Game, enchant.Node
305 | * @type {String}
306 | */
307 | enchant.Event.ENTER_FRAME = 'enterframe';
308 |
309 | /**
310 | * フレーム終了時に発生するイベント.
311 | * 発行するオブジェクト: enchant.Game
312 | * @type {String}
313 | */
314 | enchant.Event.EXIT_FRAME = 'exitframe';
315 |
316 | /**
317 | * Sceneが開始したとき発生するイベント.
318 | * 発行するオブジェクト: enchant.Scene
319 | * @type {String}
320 | */
321 | enchant.Event.ENTER = 'enter';
322 |
323 | /**
324 | * Sceneが終了したとき発生するイベント.
325 | * 発行するオブジェクト: enchant.Scene
326 | * @type {String}
327 | */
328 | enchant.Event.EXIT = 'exit';
329 |
330 | /**
331 | * NodeがGroupに追加されたとき発生するイベント.
332 | * 発行するオブジェクト: enchant.Node
333 | * @type {String}
334 | */
335 | enchant.Event.ADDED = 'added';
336 |
337 | /**
338 | * NodeがSceneに追加されたとき発生するイベント.
339 | * 発行するオブジェクト: enchant.Node
340 | * @type {String}
341 | */
342 | enchant.Event.ADDED_TO_SCENE = 'addedtoscene';
343 |
344 | /**
345 | * NodeがGroupから削除されたとき発生するイベント.
346 | * 発行するオブジェクト: enchant.Node
347 | * @type {String}
348 | */
349 | enchant.Event.REMOVED = 'removed';
350 |
351 | /**
352 | * NodeがSceneから削除されたとき発生するイベント.
353 | * 発行するオブジェクト: enchant.Node
354 | * @type {String}
355 | */
356 | enchant.Event.REMOVED_FROM_SCENE = 'removedfromscene';
357 |
358 | /**
359 | * Nodeに対するタッチが始まったとき発生するイベント.
360 | * クリックもタッチとして扱われる. 発行するオブジェクト: enchant.Node
361 | * @type {String}
362 | */
363 | enchant.Event.TOUCH_START = 'touchstart';
364 |
365 | /**
366 | * Nodeに対するタッチが移動したとき発生するイベント.
367 | * クリックもタッチとして扱われる. 発行するオブジェクト: enchant.Node
368 | * @type {String}
369 | */
370 | enchant.Event.TOUCH_MOVE = 'touchmove';
371 |
372 | /**
373 | * Nodeに対するタッチが終了したとき発生するイベント.
374 | * クリックもタッチとして扱われる. 発行するオブジェクト: enchant.Node
375 | * @type {String}
376 | */
377 | enchant.Event.TOUCH_END = 'touchend';
378 |
379 | /**
380 | * Entityがレンダリングされるときに発生するイベント.
381 | * 発行するオブジェクト: enchant.Entity
382 | * @type {String}
383 | */
384 | enchant.Event.RENDER = 'render';
385 |
386 | /**
387 | * ボタン入力が始まったとき発生するイベント.
388 | * 発行するオブジェクト: enchant.Game, enchant.Scene
389 | * @type {String}
390 | */
391 | enchant.Event.INPUT_START = 'inputstart';
392 |
393 | /**
394 | * ボタン入力が変化したとき発生するイベント.
395 | * 発行するオブジェクト: enchant.Game, enchant.Scene
396 | * @type {String}
397 | */
398 | enchant.Event.INPUT_CHANGE = 'inputchange';
399 |
400 | /**
401 | * ボタン入力が終了したとき発生するイベント.
402 | * 発行するオブジェクト: enchant.Game, enchant.Scene
403 | * @type {String}
404 | */
405 | enchant.Event.INPUT_END = 'inputend';
406 |
407 | /**
408 | * leftボタンが押された発生するイベント.
409 | * 発行するオブジェクト: enchant.Game, enchant.Scene
410 | * @type {String}
411 | */
412 | enchant.Event.LEFT_BUTTON_DOWN = 'leftbuttondown';
413 |
414 | /**
415 | * leftボタンが離された発生するイベント.
416 | * 発行するオブジェクト: enchant.Game, enchant.Scene
417 | * @type {String}
418 | */
419 | enchant.Event.LEFT_BUTTON_UP = 'leftbuttonup';
420 |
421 | /**
422 | * rightボタンが押された発生するイベント.
423 | * 発行するオブジェクト: enchant.Game, enchant.Scene
424 | * @type {String}
425 | */
426 | enchant.Event.RIGHT_BUTTON_DOWN = 'rightbuttondown';
427 |
428 | /**
429 | * rightボタンが離された発生するイベント.
430 | * 発行するオブジェクト: enchant.Game, enchant.Scene
431 | * @type {String}
432 | */
433 | enchant.Event.RIGHT_BUTTON_UP = 'rightbuttonup';
434 |
435 | /**
436 | * upボタンが押された発生するイベント.
437 | * 発行するオブジェクト: enchant.Game, enchant.Scene
438 | * @type {String}
439 | */
440 | enchant.Event.UP_BUTTON_DOWN = 'upbuttondown';
441 |
442 | /**
443 | * upボタンが離された発生するイベント.
444 | * 発行するオブジェクト: enchant.Game, enchant.Scene
445 | * @type {String}
446 | */
447 | enchant.Event.UP_BUTTON_UP = 'upbuttonup';
448 |
449 | /**
450 | * downボタンが離された発生するイベント.
451 | * 発行するオブジェクト: enchant.Game, enchant.Scene
452 | * @type {String}
453 | */
454 | enchant.Event.DOWN_BUTTON_DOWN = 'downbuttondown';
455 |
456 | /**
457 | * downボタンが離された発生するイベント.
458 | * 発行するオブジェクト: enchant.Game, enchant.Scene
459 | * @type {String}
460 | */
461 | enchant.Event.DOWN_BUTTON_UP = 'downbuttonup';
462 |
463 | /**
464 | * aボタンが押された発生するイベント.
465 | * 発行するオブジェクト: enchant.Game, enchant.Scene
466 | * @type {String}
467 | */
468 | enchant.Event.A_BUTTON_DOWN = 'abuttondown';
469 |
470 | /**
471 | * aボタンが離された発生するイベント.
472 | * 発行するオブジェクト: enchant.Game, enchant.Scene
473 | * @type {String}
474 | */
475 | enchant.Event.A_BUTTON_UP = 'abuttonup';
476 |
477 | /**
478 | * bボタンが押された発生するイベント.
479 | * 発行するオブジェクト: enchant.Game, enchant.Scene
480 | * @type {String}
481 | */
482 | enchant.Event.B_BUTTON_DOWN = 'bbuttondown';
483 |
484 | /**
485 | * bボタンが離された発生するイベント.
486 | * 発行するオブジェクト: enchant.Game, enchant.Scene
487 | * @type {String}
488 | */
489 | enchant.Event.B_BUTTON_UP = 'bbuttonup';
490 |
491 |
492 | /**
493 | * @scope enchant.EventTarget.prototype
494 | */
495 | enchant.EventTarget = enchant.Class.create({
496 | /**
497 | * DOM Event風味の独自イベント実装を行ったクラス.
498 | * ただしフェーズの概念はなし.
499 | * @constructs
500 | */
501 | initialize: function() {
502 | this._listeners = {};
503 | },
504 | /**
505 | * イベントリスナを追加する.
506 | * @param {String} type イベントのタイプ.
507 | * @param {function(e:enchant.Event)} listener 追加するイベントリスナ.
508 | */
509 | addEventListener: function(type, listener) {
510 | var listeners = this._listeners[type];
511 | if (listeners == null) {
512 | this._listeners[type] = [listener];
513 | } else if (listeners.indexOf(listener) == -1) {
514 | listeners.unshift(listener);
515 | }
516 | },
517 | /**
518 | * イベントリスナを削除する.
519 | * @param {String} type イベントのタイプ.
520 | * @param {function(e:enchant.Event)} listener 削除するイベントリスナ.
521 | */
522 | removeEventListener: function(type, listener) {
523 | var listeners = this._listeners[type];
524 | if (listeners != null) {
525 | var i = listeners.indexOf(listener);
526 | if (i != -1) {
527 | listeners.splice(i, 1);
528 | }
529 | }
530 | },
531 | /**
532 | * イベントを発行する.
533 | * @param {enchant.Event} e 発行するイベント.
534 | */
535 | dispatchEvent: function(e) {
536 | e.target = this;
537 | e.localX = e.x - this._offsetX;
538 | e.localY = e.y - this._offsetY;
539 | if (this['on' + e.type] != null) this['on' + e.type]();
540 | var listeners = this._listeners[e.type];
541 | if (listeners != null) {
542 | listeners = listeners.slice();
543 | for (var i = 0, len = listeners.length; i < len; i++) {
544 | listeners[i].call(this, e);
545 | }
546 | }
547 | }
548 | });
549 |
550 | /**
551 | * @scope enchant.Game.prototype
552 | */
553 | enchant.Game = enchant.Class.create(enchant.EventTarget, {
554 | /**
555 | * ゲームのメインループ, シーンを管理するクラス.
556 | *
557 | * インスタンスは一つしか存在することができず, すでにインスタンスが存在する状態で
558 | * コンストラクタを実行した場合既存のものが上書きされる. 存在するインスタンスには
559 | * enchant.Game.instanceからアクセスできる.
560 | *
561 | * @param {Number} width ゲーム画面の横幅.
562 | * @param {Number} height ゲーム画面の高さ.
563 | * @constructs
564 | * @extends enchant.EventTarget
565 | */
566 | initialize: function(width, height) {
567 | enchant.EventTarget.call(this);
568 |
569 | var initial = true;
570 | if (game) {
571 | initial = false;
572 | game.stop();
573 | }
574 | game = enchant.Game.instance = this;
575 |
576 | /**
577 | * ゲーム画面の横幅.
578 | * @type {Number}
579 | */
580 | this.width = width || 320;
581 | /**
582 | * ゲーム画面の高さ.
583 | * @type {Number}
584 | */
585 | this.height = height || 320;
586 | /**
587 | * ゲームの表示倍率.
588 | * @type {Number}
589 | */
590 | this.scale = 1;
591 |
592 | var stage = document.getElementById('enchant-stage');
593 | if (!stage) {
594 | stage = document.createElement('div');
595 | stage.id = 'enchant-stage';
596 | stage.style.width = window.innerWidth + 'px';
597 | stage.style.height = window.innerHeight + 'px';
598 | stage.style.position = 'absolute';
599 | if (document.body.firstChild) {
600 | document.body.insertBefore(stage, document.body.firstChild);
601 | } else {
602 | document.body.appendChild(stage);
603 | }
604 | this.scale = Math.min(
605 | window.innerWidth / this.width,
606 | window.innerHeight / this.height
607 | );
608 | this._pageX = 0;
609 | this._pageY = 0;
610 | } else {
611 | var style = window.getComputedStyle(stage);
612 | width = parseInt(style.width);
613 | height = parseInt(style.height);
614 | if (width && height) {
615 | this.scale = Math.min(
616 | width / this.width,
617 | height / this.height
618 | );
619 | } else {
620 | stage.style.width = this.width + 'px';
621 | stage.style.height = this.height + 'px';
622 | }
623 | while (stage.firstChild) {
624 | stage.removeChild(stage.firstChild);
625 | }
626 | stage.style.position = 'relative';
627 | var bounding = stage.getBoundingClientRect();
628 | this._pageX = Math.round(window.scrollX + bounding.left);
629 | this._pageY = Math.round(window.scrollY + bounding.top);
630 | }
631 | if (!this.scale) this.scale = 1;
632 | stage.style.fontSize = '12px';
633 | stage.style.webkitTextSizeAdjust = 'none';
634 | this._element = stage;
635 |
636 | /**
637 | * ゲームのフレームレート.
638 | * @type {Number}
639 | */
640 | this.fps = 30;
641 | /**
642 | * ゲーム開始からのフレーム数.
643 | * @type {Number}
644 | */
645 | this.frame = 0;
646 | /**
647 | * ゲームが実行可能な状態かどうか.
648 | * @type {Boolean}
649 | */
650 | this.ready = null;
651 | /**
652 | * ゲームが実行状態かどうか.
653 | * @type {Boolean}
654 | */
655 | this.running = false;
656 | /**
657 | * ロードされた画像をパスをキーとして保存するオブジェクト.
658 | * @type {Object.}
659 | */
660 | this.assets = {};
661 | var assets = this._assets = [];
662 | (function detectAssets(module) {
663 | if (module.assets instanceof Array) {
664 | [].push.apply(assets, module.assets);
665 | }
666 | for (var prop in module) if (module.hasOwnProperty(prop)) {
667 | if (Object.getPrototypeOf(module[prop]) == Object.prototype) {
668 | detectAssets(module[prop]);
669 | }
670 | }
671 | })(enchant);
672 |
673 | this._scenes = [];
674 | /**
675 | * 現在のScene. Sceneスタック中の一番上のScene.
676 | * @type {enchant.Scene}
677 | */
678 | this.currentScene = null;
679 | /**
680 | * ルートScene. Sceneスタック中の一番下のScene.
681 | * @type {enchant.Scene}
682 | */
683 | this.rootScene = new enchant.Scene();
684 | this.pushScene(this.rootScene);
685 | /**
686 | * ローディング時に表示されるScene.
687 | * @type {enchant.Scene}
688 | */
689 | this.loadingScene = new enchant.Scene();
690 | this.loadingScene.backgroundColor = '#000';
691 | var barWidth = this.width * 0.9 | 0;
692 | var barHeight = this.width * 0.3 | 0;
693 | var border = barWidth * 0.05 | 0;
694 | var bar = new enchant.Sprite(barWidth, barHeight);
695 | bar.x = (this.width - barWidth) / 2;
696 | bar.y = (this.height - barHeight) / 2;
697 | var image = new enchant.Surface(barWidth, barHeight);
698 | image.context.fillStyle = '#fff';
699 | image.context.fillRect(0, 0, barWidth, barHeight);
700 | image.context.fillStyle = '#000';
701 | image.context.fillRect(border, border, barWidth - border*2, barHeight - border*2);
702 | bar.image = image;
703 | var progress = 0, _progress = 0;
704 | this.addEventListener('progress', function(e) {
705 | progress = e.loaded / e.total;
706 | });
707 | bar.addEventListener('enterframe', function() {
708 | _progress *= 0.9;
709 | _progress += progress * 0.1;
710 | image.context.fillStyle = '#fff';
711 | image.context.fillRect(border, 0, (barWidth - border*2) * _progress, barHeight);
712 | });
713 | this.loadingScene.addChild(bar);
714 |
715 | this._mousedownID = 0;
716 | this._surfaceID = 0;
717 | this._soundID = 0;
718 | this._intervalID = null;
719 |
720 | /**
721 | * ゲームに対する入力状態を保存するオブジェクト.
722 | * @type {Object.}
723 | */
724 | this.input = {};
725 | this._keybind = {};
726 | this.keybind(37, 'left'); // Left Arrow
727 | this.keybind(38, 'up'); // Up Arrow
728 | this.keybind(39, 'right'); // Right Arrow
729 | this.keybind(40, 'down'); // Down Arrow
730 |
731 | var c = 0;
732 | ['left', 'right', 'up', 'down', 'a', 'b'].forEach(function(type) {
733 | this.addEventListener(type + 'buttondown', function(e) {
734 | if (!this.input[type]) {
735 | this.input[type] = true;
736 | this.dispatchEvent(new enchant.Event((c++) ? 'inputchange' : 'inputstart'));
737 | }
738 | this.currentScene.dispatchEvent(e);
739 | });
740 | this.addEventListener(type + 'buttonup', function(e) {
741 | if (this.input[type]) {
742 | this.input[type] = false;
743 | this.dispatchEvent(new enchant.Event((--c) ? 'inputchange' : 'inputend'));
744 | }
745 | this.currentScene.dispatchEvent(e);
746 | });
747 | }, this);
748 |
749 | if (initial) {
750 | document.addEventListener('keydown', function(e) {
751 | game.dispatchEvent(new enchant.Event('keydown'));
752 | if ((37 <= e.keyCode && e.keyCode <= 40) || e.keyCode == 32) {
753 | e.preventDefault();
754 | e.stopPropagation();
755 | }
756 |
757 | if (!game.running) return;
758 | var button = game._keybind[e.keyCode];
759 | if (button) {
760 | var e = new enchant.Event(button + 'buttondown');
761 | game.dispatchEvent(e);
762 | }
763 | }, true);
764 | document.addEventListener('keyup', function(e) {
765 | if (!game.running) return;
766 | var button = game._keybind[e.keyCode];
767 | if (button) {
768 | var e = new enchant.Event(button + 'buttonup');
769 | game.dispatchEvent(e);
770 | }
771 | }, true);
772 | if (TOUCH_ENABLED) {
773 | document.addEventListener('touchstart', function(e) {
774 | e.preventDefault();
775 | }, true);
776 | document.addEventListener('touchmove', function(e) {
777 | e.preventDefault();
778 | if (!game.running) e.stopPropagation();
779 | }, true);
780 | document.addEventListener('touchend', function(e) {
781 | e.preventDefault();
782 | if (!game.running) e.stopPropagation();
783 | }, true);
784 | } else {
785 | document.addEventListener('mousedown', function(e) {
786 | e.preventDefault();
787 | game._mousedownID++;
788 | if (!game.running) e.stopPropagation();
789 | }, true);
790 | document.addEventListener('mousemove', function(e) {
791 | e.preventDefault();
792 | if (!game.running) e.stopPropagation();
793 | }, true);
794 | document.addEventListener('mouseup', function(e) {
795 | e.preventDefault();
796 | if (!game.running) e.stopPropagation();
797 | }, true);
798 | }
799 | }
800 | },
801 | /**
802 | * ファイルのプリロードを行う.
803 | *
804 | * プリロードを行うよう設定されたファイルはenchant.Game#startが実行されるとき
805 | * ロードが行われる. 全てのファイルのロードが完了したときはGameオブジェクトからload
806 | * イベントが発行され, Gameオブジェクトのassetsプロパティから画像ファイルの場合は
807 | * Surfaceオブジェクトとして, 音声ファイルの場合はSoundオブジェクトとして,
808 | * その他の場合は文字列としてアクセスできるようになる.
809 | *
810 | * なおこのSurfaceオブジェクトはenchant.Surface.loadを使って作成されたものである
811 | * ため直接画像操作を行うことはできない. enchant.Surface.loadの項を参照.
812 | *
813 | * @example
814 | * game.preload('player.gif');
815 | * game.onload = function() {
816 | * var sprite = new Sprite(32, 32);
817 | * sprite.image = game.assets['player.gif']; // パス名でアクセス
818 | * ...
819 | * };
820 | * game.start();
821 | *
822 | * @param {...String} assets プリロードする画像のパス. 複数指定できる.
823 | */
824 | preload: function(assets) {
825 | if (!(assets instanceof Array)) {
826 | assets = Array.prototype.slice.call(arguments);
827 | }
828 | [].push.apply(this._assets, assets);
829 | },
830 | /**
831 | * ファイルのロードを行う.
832 | *
833 | * @param {String} asset ロードするファイルのパス.
834 | * @param {Function} [callback] ファイルのロードが完了したときに呼び出される関数.
835 | */
836 | load: function(src, callback) {
837 | if (callback == null) callback = function() {};
838 |
839 | var ext = src.match(/\.\w+$/)[0];
840 | if (ext) ext = ext.slice(1).toLowerCase();
841 | switch (ext) {
842 | case 'jpg':
843 | case 'gif':
844 | case 'png':
845 | game.assets[src] = enchant.Surface.load(src);
846 | game.assets[src].addEventListener('load', callback);
847 | break;
848 | case 'mp3':
849 | case 'aac':
850 | case 'm4a':
851 | case 'wav':
852 | case 'ogg':
853 | game.assets[src] = enchant.Sound.load(src, 'audio/' + ext);
854 | game.assets[src].addEventListener('load', callback);
855 | break;
856 | default:
857 | var req = new XMLHttpRequest();
858 | req.open('GET', src, true);
859 | req.onreadystatechange = function(e) {
860 | if (req.readyState == 4) {
861 | if (req.status != 200) {
862 | throw new Error('Cannot load an asset: ' + src);
863 | }
864 |
865 | var type = req.getResponseHeader('Content-Type') || '';
866 | if (type.match(/^image/)) {
867 | game.assets[src] = enchant.Surface.load(src);
868 | game.assets[src].addEventListener('load', callback);
869 | } else if (type.match(/^audio/)) {
870 | game.assets[src] = enchant.Sound.load(src, type);
871 | game.assets[src].addEventListener('load', callback);
872 | } else {
873 | game.assets[asset] = req.responseText;
874 | callback();
875 | }
876 | }
877 | };
878 | req.send(null);
879 | }
880 | },
881 | /**
882 | * ゲームを開始する.
883 | *
884 | * enchant.Game#fpsで設定されたフレームレートに従ってenchant.Game#currentSceneの
885 | * フレームの更新が行われるようになる. プリロードする画像が存在する場合はロードが
886 | * 始まりローディング画面が表示される.
887 | */
888 | start: function() {
889 | if (this._intervalID) {
890 | window.clearInterval(this._intervalID);
891 | } else if (this._assets.length) {
892 | if (enchant.Sound.enabledInMobileSafari && !game._touched &&
893 | VENDER_PREFIX == 'webkit' && TOUCH_ENABLED) {
894 | var scene = new Scene();
895 | scene.backgroundColor = '#000';
896 | var size = Math.round(game.width / 10);
897 | var sprite = new Sprite(game.width, size);
898 | sprite.y = (game.height - size) / 2;
899 | sprite.image = new Surface(game.width, size);
900 | sprite.image.context.fillStyle = '#fff';
901 | sprite.image.context.font = (size-1) + 'px bold Helvetica,Arial,sans-serif';
902 | var width = sprite.image.context.measureText('Touch to Start').width;
903 | sprite.image.context.fillText('Touch to Start', (game.width - width) / 2, size-1);
904 | scene.addChild(sprite);
905 | document.addEventListener('touchstart', function() {
906 | game._touched = true;
907 | game.removeScene(scene);
908 | game.start();
909 | }, true);
910 | game.pushScene(scene);
911 | return;
912 | }
913 |
914 | var o = {};
915 | var assets = this._assets.filter(function(asset) {
916 | return asset in o ? false : o[asset] = true;
917 | });
918 | var loaded = 0;
919 | for (var i = 0, len = assets.length; i < len; i++) {
920 | this.load(assets[i], function() {
921 | var e = new enchant.Event('progress');
922 | e.loaded = ++loaded;
923 | e.total = len;
924 | game.dispatchEvent(e);
925 | if (loaded == len) {
926 | game.removeScene(game.loadingScene);
927 | game.dispatchEvent(new enchant.Event('load'));
928 | }
929 | });
930 | }
931 | this.pushScene(this.loadingScene);
932 | } else {
933 | this.dispatchEvent(new enchant.Event('load'));
934 | }
935 | this.currentTime = Date.now();
936 | this._intervalID = window.setInterval(function() {
937 | game._tick()
938 | }, 1000 / this.fps);
939 | this.running = true;
940 | },
941 | _tick: function() {
942 | var now = Date.now();
943 | var e = new enchant.Event('enterframe');
944 | e.elapsed = now - this.currentTime;
945 | this.currentTime = now;
946 |
947 | var nodes = this.currentScene.childNodes.slice();
948 | var push = Array.prototype.push;
949 | while (nodes.length) {
950 | var node = nodes.pop();
951 | node.dispatchEvent(e);
952 | if (node.childNodes) {
953 | push.apply(nodes, node.childNodes);
954 | }
955 | }
956 |
957 | this.currentScene.dispatchEvent(e);
958 | this.dispatchEvent(e);
959 |
960 | this.dispatchEvent(new enchant.Event('exitframe'));
961 | this.frame++;
962 | },
963 | /**
964 | * ゲームを停止する.
965 | *
966 | * フレームは更新されず, プレイヤーの入力も受け付けなくなる.
967 | * enchant.Game#startで再開できる.
968 | */
969 | stop: function() {
970 | if (this._intervalID) {
971 | window.clearInterval(this._intervalID);
972 | this._intervalID = null;
973 | }
974 | this.running = false;
975 | },
976 | /**
977 | * ゲームを一時停止する.
978 | *
979 | * フレームは更新されず, プレイヤーの入力は受け付ける.
980 | * enchant.Game#startで再開できる.
981 | */
982 | pause: function() {
983 | if (this._intervalID) {
984 | window.clearInterval(this._intervalID);
985 | this._intervalID = null;
986 | }
987 | },
988 | /**
989 | * 新しいSceneに移行する.
990 | *
991 | * Sceneはスタック状に管理されており, 表示順序もスタックに積み上げられた順に従う.
992 | * enchant.Game#pushSceneを行うとSceneをスタックの一番上に積むことができる. スタックの
993 | * 一番上のSceneに対してはフレームの更新が行われる.
994 | *
995 | * @param {enchant.Scene} scene 移行する新しいScene.
996 | * @return {enchant.Scene} 新しいScene.
997 | */
998 | pushScene: function(scene) {
999 | this._element.appendChild(scene._element);
1000 | if (this.currentScene) {
1001 | this.currentScene.dispatchEvent(new enchant.Event('exit'));
1002 | }
1003 | this.currentScene = scene;
1004 | this.currentScene.dispatchEvent(new enchant.Event('enter'));
1005 | return this._scenes.push(scene);
1006 | },
1007 | /**
1008 | * 現在のSceneを終了させ前のSceneに戻る.
1009 | *
1010 | * Sceneはスタック状に管理されており, 表示順序もスタックに積み上げられた順に従う.
1011 | * enchant.Game#popSceneを行うとスタックの一番上のSceneを取り出すことができる.
1012 | *
1013 | * @return {enchant.Scene} 終了させたScene.
1014 | */
1015 | popScene: function() {
1016 | if (this.currentScene == this.rootScene) {
1017 | return;
1018 | }
1019 | this._element.removeChild(this.currentScene._element);
1020 | this.currentScene.dispatchEvent(new enchant.Event('exit'));
1021 | this.currentScene = this._scenes[this._scenes.length-2];
1022 | this.currentScene.dispatchEvent(new enchant.Event('enter'));
1023 | return this._scenes.pop();
1024 | },
1025 | /**
1026 | * 現在のSceneを別のSceneにおきかえる.
1027 | *
1028 | * enchant.Game#popScene, enchant.Game#pushSceneを同時に行う.
1029 | *
1030 | * @param {enchant.Scene} scene おきかえるScene.
1031 | * @return {enchant.Scene} 新しいScene.
1032 | */
1033 | replaceScene: function(scene) {
1034 | this.popScene();
1035 | return this.pushScene(scene);
1036 | },
1037 | /**
1038 | * Scene削除する.
1039 | *
1040 | * Sceneスタック中からSceneを削除する.
1041 | *
1042 | * @param {enchant.Scene} scene 削除するScene.
1043 | * @return {enchant.Scene} 削除したScene.
1044 | */
1045 | removeScene: function(scene) {
1046 | if (this.currentScene == scene) {
1047 | return this.popScene();
1048 | } else {
1049 | var i = this._scenes.indexOf(scene);
1050 | if (i != -1) {
1051 | this._scenes.splice(i, 1);
1052 | this._element.removeChild(scene._element);
1053 | return scene;
1054 | }
1055 | }
1056 | },
1057 | /**
1058 | * キーバインドを設定する.
1059 | *
1060 | * キー入力をleft, right, up, down, a, bいずれかのボタン入力として割り当てる.
1061 | *
1062 | * @param {Number} key キーバインドを設定するキーコード.
1063 | * @param {String} button 割り当てるボタン.
1064 | */
1065 | keybind: function(key, button) {
1066 | this._keybind[key] = button;
1067 | }
1068 | });
1069 |
1070 | /**
1071 | * 現在のGameインスタンス.
1072 | * @type {enchant.Game}
1073 | * @static
1074 | */
1075 | enchant.Game.instance = null;
1076 |
1077 | /**
1078 | * @scope enchant.Node.prototype
1079 | */
1080 | enchant.Node = enchant.Class.create(enchant.EventTarget, {
1081 | /**
1082 | * Sceneをルートとした表示オブジェクトツリーに属するオブジェクトの基底クラス.
1083 | * 直接使用することはない.
1084 | * @constructs
1085 | * @extends enchant.EventTarget
1086 | */
1087 | initialize: function() {
1088 | enchant.EventTarget.call(this);
1089 |
1090 | this._x = 0;
1091 | this._y = 0;
1092 | this._offsetX = 0;
1093 | this._offsetY = 0;
1094 |
1095 | /**
1096 | * Nodeの親Node.
1097 | * @type {enchant.Group}
1098 | */
1099 | this.parentNode = null;
1100 | /**
1101 | * Nodeが属しているScene.
1102 | * @type {enchant.Scene}
1103 | */
1104 | this.scene = null;
1105 |
1106 | this.addEventListener('touchstart', function(e) {
1107 | if (this.parentNode && this.parentNode != this.scene) {
1108 | this.parentNode.dispatchEvent(e);
1109 | }
1110 | });
1111 | this.addEventListener('touchmove', function(e) {
1112 | if (this.parentNode && this.parentNode != this.scene) {
1113 | this.parentNode.dispatchEvent(e);
1114 | }
1115 | });
1116 | this.addEventListener('touchend', function(e) {
1117 | if (this.parentNode && this.parentNode != this.scene) {
1118 | this.parentNode.dispatchEvent(e);
1119 | }
1120 | });
1121 | },
1122 | /**
1123 | * Nodeを移動する.
1124 | * @param {Number} x 移動先のx座標.
1125 | * @param {Number} y 移動先のy座標.
1126 | */
1127 | moveTo: function(x, y) {
1128 | this._x = x;
1129 | this._y = y;
1130 | this._updateCoordinate();
1131 | },
1132 | /**
1133 | * Nodeを移動する.
1134 | * @param {Number} x 移動するx軸方向の距離.
1135 | * @param {Number} y 移動するy軸方向の距離.
1136 | */
1137 | moveBy: function(x, y) {
1138 | this._x += x;
1139 | this._y += y;
1140 | this._updateCoordinate();
1141 | },
1142 | /**
1143 | * Nodeのx座標.
1144 | * @type {Number}
1145 | */
1146 | x: {
1147 | get: function() {
1148 | return this._x;
1149 | },
1150 | set: function(x) {
1151 | this._x = x;
1152 | this._updateCoordinate();
1153 | }
1154 | },
1155 | /**
1156 | * Nodeのy座標.
1157 | * @type {Number}
1158 | */
1159 | y: {
1160 | get: function() {
1161 | return this._y;
1162 | },
1163 | set: function(y) {
1164 | this._y = y;
1165 | this._updateCoordinate();
1166 | }
1167 | },
1168 | _updateCoordinate: function() {
1169 | if (this.parentNode) {
1170 | this._offsetX = this.parentNode._offsetX + this._x;
1171 | this._offsetY = this.parentNode._offsetY + this._y;
1172 | } else {
1173 | this._offsetX = this._x;
1174 | this._offsetY = this._y;
1175 | }
1176 | }
1177 | });
1178 |
1179 | /**
1180 | * @scope enchant.Entity.prototype
1181 | */
1182 | enchant.Entity = enchant.Class.create(enchant.Node, {
1183 | /**
1184 | * DOM上で表示する実体を持ったクラス.直接使用することはない.
1185 | * @constructs
1186 | * @extends enchant.Node
1187 | */
1188 | initialize: function() {
1189 | enchant.Node.call(this);
1190 |
1191 | this._element = document.createElement('div');
1192 | this._style = this._element.style;
1193 | this._style.position = 'absolute';
1194 |
1195 | this._width = 0;
1196 | this._height = 0;
1197 | this._backgroundColor = null;
1198 | this._opacity = 1;
1199 | this._visible = true;
1200 | this._buttonMode = null;
1201 |
1202 | /**
1203 | * Entityにボタンの機能を設定する.
1204 | * Entityに対するタッチ, クリックをleft, right, up, down, a, bいずれかの
1205 | * ボタン入力として割り当てる.
1206 | * @type {String}
1207 | */
1208 | this.buttonMode = null;
1209 | /**
1210 | * Entityが押されているかどうか.
1211 | * buttonModeが設定されているときだけ機能する.
1212 | * @type {Boolean}
1213 | */
1214 | this.buttonPressed = false;
1215 | this.addEventListener('touchstart', function() {
1216 | if (!this.buttonMode) return;
1217 | this.buttonPressed = true;
1218 | var e = new Event(button + 'buttondown');
1219 | this.dispatchEvent(e);
1220 | game.dispatchEvent(e);
1221 | });
1222 | this.addEventListener('touchend', function() {
1223 | if (!this.buttonMode) return;
1224 | this.buttonPressed = false;
1225 | var e = new Event(button + 'buttonup');
1226 | this.dispatchEvent(e);
1227 | game.dispatchEvent(e);
1228 | });
1229 |
1230 | var that = this;
1231 | var render = function() {
1232 | that.dispatchEvent(new enchant.Event('render'));
1233 | };
1234 | this.addEventListener('addedtoscene', function() {
1235 | render();
1236 | game.addEventListener('exitframe', render);
1237 | });
1238 | this.addEventListener('removedfromscene', function() {
1239 | game.removeEventListener('exitframe', render);
1240 | });
1241 | this.addEventListener('render', function() {
1242 | if (this._offsetX != this._previousOffsetX) {
1243 | this._style.left = this._offsetX + 'px';
1244 | }
1245 | if (this._offsetY != this._previousOffsetY) {
1246 | this._style.top = this._offsetY + 'px';
1247 | }
1248 | this._previousOffsetX = this._offsetX;
1249 | this._previousOffsetY = this._offsetY;
1250 | });
1251 |
1252 | var that = this;
1253 | if (TOUCH_ENABLED) {
1254 | this._element.addEventListener('touchstart', function(e) {
1255 | var touches = e.touches;
1256 | for (var i = 0, len = touches.length; i < len; i++) {
1257 | e = new enchant.Event('touchstart');
1258 | e.identifier = touches[i].identifier;
1259 | e._initPosition(touches[i].pageX, touches[i].pageY);
1260 | that.dispatchEvent(e);
1261 | }
1262 | }, false);
1263 | this._element.addEventListener('touchmove', function(e) {
1264 | var touches = e.touches;
1265 | for (var i = 0, len = touches.length; i < len; i++) {
1266 | e = new enchant.Event('touchmove');
1267 | e.identifier = touches[i].identifier;
1268 | e._initPosition(touches[i].pageX, touches[i].pageY);
1269 | that.dispatchEvent(e);
1270 | }
1271 | }, false);
1272 | this._element.addEventListener('touchend', function(e) {
1273 | var touches = e.changedTouches;
1274 | for (var i = 0, len = touches.length; i < len; i++) {
1275 | e = new enchant.Event('touchend');
1276 | e.identifier = touches[i].identifier;
1277 | e._initPosition(touches[i].pageX, touches[i].pageY);
1278 | that.dispatchEvent(e);
1279 | }
1280 | }, false);
1281 | } else {
1282 | this._element.addEventListener('mousedown', function(e) {
1283 | var x = e.pageX;
1284 | var y = e.pageY;
1285 | e = new enchant.Event('touchstart');
1286 | e.identifier = game._mousedownID;
1287 | e._initPosition(x, y);
1288 | that.dispatchEvent(e);
1289 | that._mousedown = true;
1290 | }, false);
1291 | game._element.addEventListener('mousemove', function(e) {
1292 | if (!that._mousedown) return;
1293 | var x = e.pageX;
1294 | var y = e.pageY;
1295 | e = new enchant.Event('touchmove');
1296 | e.identifier = game._mousedownID;
1297 | e._initPosition(x, y);
1298 | that.dispatchEvent(e);
1299 | }, false);
1300 | game._element.addEventListener('mouseup', function(e) {
1301 | if (!that._mousedown) return;
1302 | var x = e.pageX;
1303 | var y = e.pageY;
1304 | e = new enchant.Event('touchend');
1305 | e.identifier = game._mousedownID;
1306 | e._initPosition(x, y);
1307 | that.dispatchEvent(e);
1308 | that._mousedown = false;
1309 | }, false);
1310 | }
1311 | },
1312 | /**
1313 | * Entityの横幅.
1314 | * @type {Number}
1315 | */
1316 | width: {
1317 | get: function() {
1318 | return this._width;
1319 | },
1320 | set: function(width) {
1321 | this._style.width = (this._width = width) + 'px';
1322 | }
1323 | },
1324 | /**
1325 | * Entityの高さ.
1326 | * @type {Number}
1327 | */
1328 | height: {
1329 | get: function() {
1330 | return this._height;
1331 | },
1332 | set: function(height) {
1333 | this._style.height = (this._height = height) + 'px';
1334 | }
1335 | },
1336 | /**
1337 | * Entityの背景色.
1338 | * CSSの'color'プロパティと同様の形式で指定できる.
1339 | * @type {String}
1340 | */
1341 | backgroundColor: {
1342 | get: function() {
1343 | return this._backgroundColor;
1344 | },
1345 | set: function(color) {
1346 | this._element.style.backgroundColor = this._backgroundColor = color;
1347 | }
1348 | },
1349 | /**
1350 | * Entityの透明度.
1351 | * 0から1までの値を設定する(0が完全な透明, 1が完全な不透明).
1352 | * @type {Number}
1353 | */
1354 | opacity: {
1355 | get: function() {
1356 | return this._opacity;
1357 | },
1358 | set: function(opacity) {
1359 | this._style.opacity = this._opacity = opacity;
1360 | }
1361 | },
1362 | /**
1363 | * Entityを表示するかどうかを指定する.
1364 | * @type {Boolean}
1365 | */
1366 | visible: {
1367 | get: function() {
1368 | return this._visible;
1369 | },
1370 | set: function(visible) {
1371 | if (this._visible = visible) {
1372 | this._style.display = 'block';
1373 | } else {
1374 | this._style.display = 'none';
1375 | }
1376 | }
1377 | },
1378 | /**
1379 | * Entityのタッチを有効にするかどうかを指定する.
1380 | * @type {Boolean}
1381 | */
1382 | touchEnabled: {
1383 | get: function() {
1384 | return this._touchEnabled;
1385 | },
1386 | set: function(enabled) {
1387 | if (this._touchEnabled = enabled) {
1388 | this._style.pointerEvents = 'all';
1389 | } else {
1390 | this._style.pointerEvents = 'none';
1391 | }
1392 | }
1393 | },
1394 | /**
1395 | * Entityの矩形が交差しているかどうかにより衝突判定を行う.
1396 | * @param {*} other 衝突判定を行うEntityなどx, y, width, heightプロパティを持ったObject.
1397 | * @return {Boolean} 衝突判定の結果.
1398 | */
1399 | intersect: function(other) {
1400 | return this.x < other.x + other.width && other.x < this.x + this.width &&
1401 | this.y < other.y + other.height && other.y < this.y + this.height;
1402 | },
1403 | /**
1404 | * Entityの中心点どうしの距離により衝突判定を行う.
1405 | * @param {*} other 衝突判定を行うEntityなどx, y, width, heightプロパティを持ったObject.
1406 | * @param {Number} [distance] 衝突したと見なす最大の距離. デフォルト値は二つのEntityの横幅と高さの平均.
1407 | * @return {Boolean} 衝突判定の結果.
1408 | */
1409 | within: function(other, distance) {
1410 | if (distance == null) {
1411 | distance = (this.width + this.height + other.width + other.height) / 4;
1412 | }
1413 | var _;
1414 | return (_ = this.x - other.x + (this.width*this.scaleX - other.width*other.scaleY) / 2) * _ +
1415 | (_ = this.y - other.y + (this.height*this.scaleY - other.height*other.scaleY) / 2) * _ < distance * distance;
1416 | }
1417 | });
1418 |
1419 | /**
1420 | * @scope enchant.Sprite.prototype
1421 | */
1422 | enchant.Sprite = enchant.Class.create(enchant.Entity, {
1423 | /**
1424 | * 画像表示機能を持ったクラス.
1425 | *
1426 | * @example
1427 | * var bear = new Sprite(32, 32);
1428 | * bear.image = game.assets['chara1.gif'];
1429 | *
1430 | * @param {Number} [width] Spriteの横幅.
1431 | * @param {Number} [height] Spriteの高さ.
1432 | * @constructs
1433 | * @extends enchant.Entity
1434 | */
1435 | initialize: function(width, height) {
1436 | enchant.Entity.call(this);
1437 |
1438 | this.width = width;
1439 | this.height = height;
1440 | this._scaleX = 1;
1441 | this._scaleY = 1;
1442 | this._rotation = 0;
1443 | this._dirty = false;
1444 | this._image = null;
1445 | this._frame = 0;
1446 |
1447 | this._style.overflow = 'hidden';
1448 |
1449 | this.addEventListener('render', function() {
1450 | if (this._dirty) {
1451 | this._style[VENDER_PREFIX + 'Transform'] = [
1452 | 'rotate(', this._rotation, 'deg)',
1453 | 'scale(', this._scaleX, ',', this._scaleY, ')'
1454 | ].join('');
1455 | this._dirty = false;
1456 | }
1457 | });
1458 | },
1459 | /**
1460 | * Spriteで表示する画像.
1461 | * @type {enchant.Surface}
1462 | */
1463 | image: {
1464 | get: function() {
1465 | return this._image;
1466 | },
1467 | set: function(image) {
1468 | if (image == this._image) return;
1469 |
1470 | if (this._image != null) {
1471 | if (this._image.css) {
1472 | this._style.backgroundImage = '';
1473 | } else if (this._element.firstChild) {
1474 | this._element.removeChild(this._element.firstChild);
1475 | if (this._dirtyListener) {
1476 | this.removeEventListener('render', this._dirtyListener);
1477 | this._dirtyListener = null;
1478 | } else {
1479 | this._image._parent = null;
1480 | }
1481 | }
1482 | }
1483 |
1484 | if (image != null) {
1485 | if (image._css) {
1486 | this._style.backgroundImage = image._css;
1487 | } else if (image._parent) {
1488 | var canvas = document.createElement('canvas');
1489 | var context = canvas.getContext('2d');
1490 | canvas.width = image.width;
1491 | canvas.height = image.height;
1492 | context.drawImage(image._element, 0, 0);
1493 | this._dirtyListener = function() {
1494 | if (image._dirty) {
1495 | context.drawImage(image._element);
1496 | image._dirty = false;
1497 | }
1498 | };
1499 | this.addEventListener('render', this._dirtyListener);
1500 | this._element.appendChild(canvas);
1501 | } else {
1502 | image._parent = this;
1503 | this._element.appendChild(image._element);
1504 | }
1505 | }
1506 |
1507 | this._image = image;
1508 | }
1509 | },
1510 | /**
1511 | * 表示するフレームのインデックス.
1512 | * Spriteと同じ横幅と高さを持ったフレームがimageプロパティの画像に左上から順に
1513 | * 配列されていると見て, 0から始まるインデックスを指定することでフレームを切り替える.
1514 | * @type {Number}
1515 | */
1516 | frame: {
1517 | get: function() {
1518 | return this._frame;
1519 | },
1520 | set: function(frame) {
1521 | this._frame = frame;
1522 | var row = this._image.width / this._width | 0;
1523 | if (this._image._css) {
1524 | this._style.backgroundPosition = [
1525 | -(frame % row) * this._width, 'px ',
1526 | -(frame / row | 0) * this._height, 'px'
1527 | ].join('');
1528 | } else if (this._element.firstChild) {
1529 | var style = this._element.firstChild.style;
1530 | style.left = -(frame % row) * this._width + 'px';
1531 | style.top = -(frame / row | 0) * this._height + 'px';
1532 | }
1533 | }
1534 | },
1535 | /**
1536 | * Spriteを拡大縮小する.
1537 | * @param {Number} x 拡大するx軸方向の倍率.
1538 | * @param {Number} [y] 拡大するy軸方向の倍率.
1539 | */
1540 | scale: function(x, y) {
1541 | if (y == null) y = x;
1542 | this._scaleX *= x;
1543 | this._scaleY *= y;
1544 | this._dirty = true;
1545 | },
1546 | /**
1547 | * Spriteを回転する.
1548 | * @param {Number} deg 回転する角度 (度数法).
1549 | */
1550 | rotate: function(deg) {
1551 | this._rotation += deg;
1552 | this._dirty = true;
1553 | },
1554 | /**
1555 | * Spriteのx軸方向の倍率.
1556 | * @type {Number}
1557 | */
1558 | scaleX: {
1559 | get: function() {
1560 | return this._scaleX;
1561 | },
1562 | set: function(scaleX) {
1563 | this._scaleX = scaleX;
1564 | this._dirty = true;
1565 | }
1566 | },
1567 | /**
1568 | * Spriteのy軸方向の倍率.
1569 | * @type {Number}
1570 | */
1571 | scaleY: {
1572 | get: function() {
1573 | return this._scaleY;
1574 | },
1575 | set: function(scaleY) {
1576 | this._scaleY = scaleY;
1577 | this._dirty = true;
1578 | }
1579 | },
1580 | /**
1581 | * Spriteの回転角 (度数法).
1582 | * @type {Number}
1583 | */
1584 | rotation: {
1585 | get: function() {
1586 | return this._rotation;
1587 | },
1588 | set: function(rotation) {
1589 | this._rotation = rotation;
1590 | this._dirty = true;
1591 | }
1592 | }
1593 | });
1594 |
1595 | /**
1596 | * @scope enchant.Label.prototype
1597 | */
1598 | enchant.Label = enchant.Class.create(enchant.Entity, {
1599 | /**
1600 | * Labelオブジェクトを作成する.
1601 | * @constructs
1602 | * @extends enchant.Entity
1603 | */
1604 | initialize: function(text) {
1605 | enchant.Entity.call(this);
1606 |
1607 | this.width = 300;
1608 | this.text = text;
1609 | },
1610 | /**
1611 | * 表示するテキスト.
1612 | * @type {String}
1613 | */
1614 | text: {
1615 | get: function() {
1616 | return this._element.innerHTML;
1617 | },
1618 | set: function(text) {
1619 | this._element.innerHTML = text;
1620 | }
1621 | },
1622 | /**
1623 | * フォントの指定.
1624 | * CSSの'font'プロパティと同様の形式で指定できる.
1625 | * @type {String}
1626 | */
1627 | font: {
1628 | get: function() {
1629 | return this._style.font;
1630 | },
1631 | set: function(font) {
1632 | this._style.font = font;
1633 | }
1634 | },
1635 | /**
1636 | * 文字色の指定.
1637 | * CSSの'color'プロパティと同様の形式で指定できる.
1638 | * @type {String}
1639 | */
1640 | color: {
1641 | get: function() {
1642 | return this._style.color;
1643 | },
1644 | set: function(color) {
1645 | this._style.color = color;
1646 | }
1647 | }
1648 | });
1649 |
1650 | /**
1651 | * @scope enchant.Map.prototype
1652 | */
1653 | enchant.Map = enchant.Class.create(enchant.Entity, {
1654 | /**
1655 | * タイルセットからマップを生成して表示するクラス.
1656 | *
1657 | * @param {Number} tileWidth タイルの横幅.
1658 | * @param {Number} tileHeight タイルの高さ.
1659 | * @constructs
1660 | * @extends enchant.Entity
1661 | */
1662 | initialize: function(tileWidth, tileHeight) {
1663 | enchant.Entity.call(this);
1664 |
1665 | var canvas = document.createElement('canvas');
1666 | if (RETINA_DISPLAY && game.scale == 2) {
1667 | canvas.width = game.width * 2;
1668 | canvas.height = game.height * 2;
1669 | this._style.webkitTransformOrigin = '0 0';
1670 | this._style.webkitTransform = 'scale(0.5)';
1671 | } else {
1672 | canvas.width = game.width;
1673 | canvas.height = game.height;
1674 | }
1675 | this._element.appendChild(canvas);
1676 | this._context = canvas.getContext('2d');
1677 |
1678 | this._tileWidth = tileWidth || 0;
1679 | this._tileHeight = tileHeight || 0;
1680 | this._image = null;
1681 | this._data = [[[]]];
1682 | this._dirty = false;
1683 | this._tight = false;
1684 |
1685 | this.touchEnabled = false;
1686 |
1687 | /**
1688 | * タイルが衝突判定を持つかを表す値の二元配列.
1689 | * @type {Array.>}
1690 | */
1691 | this.collisionData = null;
1692 |
1693 | this._listeners['render'] = null;
1694 | this.addEventListener('render', function() {
1695 | if (this._dirty || this._previousOffsetX == null) {
1696 | this._dirty = false;
1697 | this.redraw(0, 0, game.width, game.height);
1698 | } else if (this._offsetX != this._previousOffsetX ||
1699 | this._offsetY != this._previousOffsetY) {
1700 | if (this._tight) {
1701 | var x = -this._offsetX;
1702 | var y = -this._offsetY;
1703 | var px = -this._previousOffsetX;
1704 | var py = -this._previousOffsetY;
1705 | var w1 = x - px + game.width;
1706 | var w2 = px - x + game.width;
1707 | var h1 = y - py + game.height;
1708 | var h2 = py - y + game.height;
1709 | if (w1 > this._tileWidth && w2 > this._tileWidth &&
1710 | h1 > this._tileHeight && h2 > this._tileHeight) {
1711 | var sx, sy, dx, dy, sw, sh;
1712 | if (w1 < w2) {
1713 | sx = 0;
1714 | dx = px - x;
1715 | sw = w1;
1716 | } else {
1717 | sx = x - px;
1718 | dx = 0;
1719 | sw = w2;
1720 | }
1721 | if (h1 < h2) {
1722 | sy = 0;
1723 | dy = py - y;
1724 | sh = h1;
1725 | } else {
1726 | sy = y - py;
1727 | dy = 0;
1728 | sh = h2;
1729 | }
1730 |
1731 | if (game._buffer == null) {
1732 | game._buffer = document.createElement('canvas');
1733 | game._buffer.width = this._context.canvas.width;
1734 | game._buffer.height = this._context.canvas.height;
1735 | }
1736 | var context = game._buffer.getContext('2d');
1737 | if (this._doubledImage) {
1738 | context.clearRect(0, 0, sw*2, sh*2);
1739 | context.drawImage(this._context.canvas,
1740 | sx*2, sy*2, sw*2, sh*2, 0, 0, sw*2, sh*2);
1741 | context = this._context;
1742 | context.clearRect(dx*2, dy*2, sw*2, sh*2);
1743 | context.drawImage(game._buffer,
1744 | 0, 0, sw*2, sh*2, dx*2, dy*2, sw*2, sh*2);
1745 | } else {
1746 | context.clearRect(0, 0, sw, sh);
1747 | context.drawImage(this._context.canvas,
1748 | sx, sy, sw, sh, 0, 0, sw, sh);
1749 | context = this._context;
1750 | context.clearRect(dx, dy, sw, sh);
1751 | context.drawImage(game._buffer,
1752 | 0, 0, sw, sh, dx, dy, sw, sh);
1753 | }
1754 |
1755 | if (dx == 0) {
1756 | this.redraw(sw, 0, game.width - sw, game.height);
1757 | } else {
1758 | this.redraw(0, 0, game.width - sw, game.height);
1759 | }
1760 | if (dy == 0) {
1761 | this.redraw(0, sh, game.width, game.height - sh);
1762 | } else {
1763 | this.redraw(0, 0, game.width, game.height - sh);
1764 | }
1765 | } else {
1766 | this.redraw(0, 0, game.width, game.height);
1767 | }
1768 | } else {
1769 | this.redraw(0, 0, game.width, game.height);
1770 | }
1771 | }
1772 | this._previousOffsetX = this._offsetX;
1773 | this._previousOffsetY = this._offsetY;
1774 | });
1775 | },
1776 | /**
1777 | * データを設定する.
1778 | * タイルががimageプロパティの画像に左上から順に配列されていると見て, 0から始まる
1779 | * インデックスの二元配列を設定する.複数指定された場合は後のものから順に表示される.
1780 | * @param {...Array>} data タイルのインデックスの二元配列. 複数指定できる.
1781 | */
1782 | loadData: function(data) {
1783 | this._data = Array.prototype.slice.apply(arguments);
1784 | this._dirty = true;
1785 |
1786 | this._tight = false;
1787 | for (var i = 0, len = this._data.length; i < len; i++) {
1788 | var c = 0;
1789 | var data = this._data[i];
1790 | for (var y = 0, l = data.length; y < l; y++) {
1791 | for (var x = 0, ll = data[y].length; x < ll; x++) {
1792 | if (data[y][x] >= 0) c++;
1793 | }
1794 | }
1795 | if (c / (data.length * data[0].length) > 0.2) {
1796 | this._tight = true;
1797 | break;
1798 | }
1799 | }
1800 | },
1801 | /**
1802 | * Map上に障害物があるかどうかを判定する.
1803 | * @param {Number} x 判定を行うマップ上の点のx座標.
1804 | * @param {Number} y 判定を行うマップ上の点のy座標.
1805 | * @return {Boolean} 障害物があるかどうか.
1806 | */
1807 | hitTest: function(x, y) {
1808 | if (x < 0 || this.width <= x || y < 0 || this.height <= y) {
1809 | return false;
1810 | }
1811 | var width = this._image.width;
1812 | var height = this._image.height;
1813 | var tileWidth = this._tileWidth || width;
1814 | var tileHeight = this._tileHeight || height;
1815 | x = x / tileWidth | 0;
1816 | y = y / tileHeight | 0;
1817 | if (this.collisionData != null) {
1818 | return this.collisionData[y] && !!this.collisionData[y][x];
1819 | } else {
1820 | for (var i = 0, len = this._data.length; i < len; i++) {
1821 | var data = this._data[i];
1822 | var n;
1823 | if (data[y] != null && (n = data[y][x]) != null &&
1824 | 0 <= n && n < (width / tileWidth | 0) * (height / tileHeight | 0)) {
1825 | return true;
1826 | }
1827 | }
1828 | return false;
1829 | }
1830 | },
1831 | /**
1832 | * Mapで表示するタイルセット画像.
1833 | * @type {enchant.Surface}
1834 | */
1835 | image: {
1836 | get: function() {
1837 | return this._image;
1838 | },
1839 | set: function(image) {
1840 | this._image = image;
1841 | if (RETINA_DISPLAY && game.scale == 2) {
1842 | var img = new Surface(image.width * 2, image.height * 2);
1843 | var tileWidth = this._tileWidth || image.width;
1844 | var tileHeight = this._tileHeight || image.height;
1845 | var row = image.width / tileWidth | 0;
1846 | var col = image.height / tileHeight | 0;
1847 | for (var y = 0; y < col; y++) {
1848 | for (var x = 0; x < row; x++) {
1849 | img.draw(image, x * tileWidth, y * tileHeight, tileWidth, tileHeight,
1850 | x * tileWidth * 2, y * tileHeight * 2, tileWidth * 2, tileHeight * 2);
1851 | }
1852 | }
1853 | this._doubledImage = img;
1854 | }
1855 | this._dirty = true;
1856 | }
1857 | },
1858 | /**
1859 | * Mapのタイルの横幅.
1860 | * @type {Number}
1861 | */
1862 | tileWidth: {
1863 | get: function() {
1864 | return this._tileWidth;
1865 | },
1866 | set: function(tileWidth) {
1867 | this._tileWidth = tileWidth;
1868 | this._dirty = true;
1869 | }
1870 | },
1871 | /**
1872 | * Mapのタイルの高さ.
1873 | * @type {Number}
1874 | */
1875 | tileHeight: {
1876 | get: function() {
1877 | return this._tileHeight;
1878 | },
1879 | set: function(tileHeight) {
1880 | this._tileHeight = tileHeight;
1881 | this._dirty = true;
1882 | }
1883 | },
1884 | /**
1885 | * @private
1886 | */
1887 | width: {
1888 | get: function() {
1889 | return this._tileWidth * this._data[0][0].length
1890 | }
1891 | },
1892 | /**
1893 | * @private
1894 | */
1895 | height: {
1896 | get: function() {
1897 | return this._tileHeight * this._data[0].length
1898 | }
1899 | },
1900 | /**
1901 | * @private
1902 | */
1903 | redraw: function(x, y, width, height) {
1904 | if (this._image == null) {
1905 | return;
1906 | }
1907 |
1908 | var image, tileWidth, tileHeight, dx, dy;
1909 | if (this._doubledImage) {
1910 | image = this._doubledImage;
1911 | tileWidth = this._tileWidth * 2;
1912 | tileHeight = this._tileHeight * 2;
1913 | dx = -this._offsetX * 2;
1914 | dy = -this._offsetY * 2;
1915 | x *= 2;
1916 | y *= 2;
1917 | width *= 2;
1918 | height *= 2;
1919 | } else {
1920 | image = this._image;
1921 | tileWidth = this._tileWidth;
1922 | tileHeight = this._tileHeight;
1923 | dx = -this._offsetX;
1924 | dy = -this._offsetY;
1925 | }
1926 | var row = image.width / tileWidth | 0;
1927 | var col = image.height / tileHeight | 0;
1928 | var left = Math.max((x + dx) / tileWidth | 0, 0);
1929 | var top = Math.max((y + dy) / tileHeight | 0, 0);
1930 | var right = Math.ceil((x + dx + width) / tileWidth);
1931 | var bottom = Math.ceil((y + dy + height) / tileHeight);
1932 |
1933 | var source = image._element;
1934 | var context = this._context;
1935 | var canvas = context.canvas;
1936 | context.clearRect(x, y, width, height);
1937 | for (var i = 0, len = this._data.length; i < len; i++) {
1938 | var data = this._data[i];
1939 | var r = Math.min(right, data[0].length);
1940 | var b = Math.min(bottom, data.length);
1941 | for (y = top; y < b; y++) {
1942 | for (x = left; x < r; x++) {
1943 | var n = data[y][x];
1944 | if (0 <= n && n < row * col) {
1945 | var sx = (n % row) * tileWidth;
1946 | var sy = (n / row | 0) * tileHeight;
1947 | context.drawImage(source, sx, sy, tileWidth, tileHeight,
1948 | x * tileWidth - dx, y * tileHeight - dy, tileWidth, tileHeight);
1949 | }
1950 | }
1951 | }
1952 | }
1953 | }
1954 | });
1955 |
1956 | /**
1957 | * @scope enchant.Group.prototype
1958 | */
1959 | enchant.Group = enchant.Class.create(enchant.Node, {
1960 | /**
1961 | * 複数のNodeを子に持つことができるクラス.
1962 | *
1963 | * @example
1964 | * var stage = new Group();
1965 | * stage.addChild(player);
1966 | * stage.addChild(enemy);
1967 | * stage.addChild(map);
1968 | * stage.addEventListener('enterframe', function() {
1969 | * // playerの座標に従って全体をスクロールする
1970 | * if (this.x > 64 - player.x) {
1971 | * this.x = 64 - player.x;
1972 | * }
1973 | * });
1974 | *
1975 | * @constructs
1976 | * @extends enchant.Node
1977 | */
1978 | initialize: function() {
1979 | enchant.Node.call(this);
1980 |
1981 | /**
1982 | * 子のNode.
1983 | * @type {Array.}
1984 | */
1985 | this.childNodes = [];
1986 |
1987 | this._x = 0;
1988 | this._y = 0;
1989 | },
1990 | /**
1991 | * GroupにNodeを追加する.
1992 | * @param {enchant.Node} node 追加するNode.
1993 | */
1994 | addChild: function(node) {
1995 | this.childNodes.push(node);
1996 | node.parentNode = this;
1997 | node.dispatchEvent(new enchant.Event('added'));
1998 | if (this.scene) {
1999 | var e = new enchant.Event('addedtoscene');
2000 | node.scene = this.scene;
2001 | node.dispatchEvent(e);
2002 | node._updateCoordinate();
2003 |
2004 | var fragment = document.createDocumentFragment();
2005 | var nodes;
2006 | var push = Array.prototype.push;
2007 | if (node._element) {
2008 | fragment.appendChild(node._element);
2009 | } else if (node.childNodes) {
2010 | nodes = node.childNodes.slice().reverse();
2011 | while (nodes.length) {
2012 | node = nodes.pop();
2013 | node.scene = this.scene;
2014 | node.dispatchEvent(e);
2015 | if (node._element) {
2016 | fragment.appendChild(node._element);
2017 | } else if (node.childNodes) {
2018 | push.apply(nodes, node.childNodes.reverse());
2019 | }
2020 | }
2021 | }
2022 | if (!fragment.childNodes.length) return;
2023 |
2024 | var nextSibling, thisNode = this;
2025 | while (thisNode.parentNode) {
2026 | nodes = thisNode.parentNode.childNodes;
2027 | nodes = nodes.slice(nodes.indexOf(thisNode) + 1).reverse();
2028 | while (nodes.length) {
2029 | node = nodes.pop();
2030 | if (node._element) {
2031 | nextSibling = node._element;
2032 | break;
2033 | } else if (node.childNodes) {
2034 | push.apply(nodes, node.childNodes.slice().reverse());
2035 | }
2036 | }
2037 | thisNode = thisNode.parentNode;
2038 | }
2039 | if (nextSibling) {
2040 | this.scene._element.insertBefore(fragment, nextSibling);
2041 | } else {
2042 | this.scene._element.appendChild(fragment);
2043 | }
2044 | }
2045 | },
2046 | /**
2047 | * GroupにNodeを挿入する.
2048 | * @param {enchant.Node} node 挿入するNode.
2049 | * @param {enchant.Node} reference 挿入位置の前にあるNode.
2050 | */
2051 | insertBefore: function(node, reference) {
2052 | var i = this.childNodes.indexOf(reference);
2053 | if (i != -1) {
2054 | this.childNodes.splice(i, 0, node);
2055 | node.parentNode = this;
2056 | node.dispatchEvent(new enchant.Event('added'));
2057 | if (this.scene) {
2058 | var e = new enchant.Event('addedtoscene');
2059 | node.scene = this.scene;
2060 | node.dispatchEvent(e);
2061 | node._updateCoordinate();
2062 |
2063 | var fragment = document.createDocumentFragment();
2064 | var nodes;
2065 | var push = Array.prototype.push;
2066 | if (node._element) {
2067 | fragment.appendChild(node._element);
2068 | } else if (node.childNodes) {
2069 | nodes = node.childNodes.slice().reverse();
2070 | while (nodes.length) {
2071 | node = nodes.pop();
2072 | node.scene = this.scene;
2073 | node.dispatchEvent(e);
2074 | if (node._element) {
2075 | fragment.appendChild(node._element);
2076 | } else if (node.childNodes) {
2077 | push.apply(nodes, node.childNodes.reverse());
2078 | }
2079 | }
2080 | }
2081 | if (!fragment.childNodes.length) return;
2082 |
2083 | var nextSibling, thisNode = reference;
2084 | while (thisNode.parentNode) {
2085 | if (i != null) {
2086 | nodes = this.childNodes.slice(i+1).reverse();
2087 | i = null;
2088 | } else {
2089 | nodes = thisNode.parentNode.childNodes;
2090 | nodes = nodes.slice(nodes.indexOf(thisNode) + 1).reverse();
2091 | }
2092 | while (nodes.length) {
2093 | node = nodes.pop();
2094 | if (node._element) {
2095 | nextSibling = node._element;
2096 | break;
2097 | } else if (node.childNodes) {
2098 | push.apply(nodes, node.childNodes.slice().reverse());
2099 | }
2100 | }
2101 | thisNode = thisNode.parentNode;
2102 | }
2103 | if (nextSibling) {
2104 | this.scene._element.insertBefore(fragment, nextSibling);
2105 | } else {
2106 | this.scene._element.appendChild(fragment);
2107 | }
2108 | }
2109 | } else {
2110 | this.addChild(node);
2111 | }
2112 | },
2113 | /**
2114 | * GroupからNodeを削除する.
2115 | * @param {enchant.Node} node 削除するNode.
2116 | */
2117 | removeChild: function(node) {
2118 | var i = this.childNodes.indexOf(node);
2119 | if (i != -1) {
2120 | this.childNodes.splice(i, 1);
2121 | } else {
2122 | return;
2123 | }
2124 | node.parentNode = null;
2125 | node.dispatchEvent(new enchant.Event('removed'));
2126 | if (this.scene) {
2127 | var e = new enchant.Event('removedfromscene');
2128 | node.scene = null;
2129 | node.dispatchEvent(e);
2130 | if (node._element) {
2131 | this.scene._element.removeChild(node._element);
2132 | } else if (node.childNodes) {
2133 | var nodes = node.childNodes.slice();
2134 | var push = Array.prototype.push;
2135 | while (nodes.length) {
2136 | node = nodes.pop();
2137 | node.scene = null;
2138 | node.dispatchEvent(e);
2139 | if (node._element) {
2140 | this.scene._element.removeChild(node._element);
2141 | } else if (node.childNodes) {
2142 | push.apply(nodes, node.childNodes);
2143 | }
2144 | }
2145 | }
2146 | }
2147 | },
2148 | /**
2149 | * 最初の子Node.
2150 | * @type {enchant.Node}
2151 | */
2152 | firstChild: {
2153 | get: function() {
2154 | return this.childNodes[0];
2155 | }
2156 | },
2157 | /**
2158 | * 最後の子Node.
2159 | * @type {enchant.Node}
2160 | */
2161 | lastChild: {
2162 | get: function() {
2163 | return this.childNodes[this.childNodes.length-1];
2164 | }
2165 | },
2166 | _updateCoordinate: function() {
2167 | if (this.parentNode) {
2168 | this._offsetX = this.parentNode._offsetX + this._x;
2169 | this._offsetY = this.parentNode._offsetY + this._y;
2170 | } else {
2171 | this._offsetX = this._x;
2172 | this._offsetY = this._y;
2173 | }
2174 | for (var i = 0, len = this.childNodes.length; i < len; i++) {
2175 | this.childNodes[i]._updateCoordinate();
2176 | }
2177 | }
2178 | });
2179 |
2180 | /**
2181 | * @scope enchant.Scene.prototype
2182 | */
2183 | enchant.Scene = enchant.Class.create(enchant.Group, {
2184 | /**
2185 | * 表示オブジェクトツリーのルートになるクラス.
2186 | *
2187 | * @example
2188 | * var scene = new Scene();
2189 | * scene.addChild(player);
2190 | * scene.addChild(enemy);
2191 | * game.pushScene(scene);
2192 | *
2193 | * @constructs
2194 | * @extends enchant.Group
2195 | */
2196 | initialize: function() {
2197 | enchant.Group.call(this);
2198 |
2199 | this._element = document.createElement('div');
2200 | this._element.style.position = 'absolute';
2201 | this._element.style.overflow = 'hidden';
2202 | this._element.style.width = (this.width = game.width) + 'px';
2203 | this._element.style.height = (this.height = game.height) + 'px';
2204 | this._element.style[VENDER_PREFIX + 'TransformOrigin'] = '0 0';
2205 | this._element.style[VENDER_PREFIX + 'Transform'] = 'scale(' + game.scale + ')';
2206 |
2207 | this.scene = this;
2208 |
2209 | var that = this;
2210 | if (TOUCH_ENABLED) {
2211 | this._element.addEventListener('touchstart', function(e) {
2212 | var touches = e.touches;
2213 | for (var i = 0, len = touches.length; i < len; i++) {
2214 | e = new enchant.Event('touchstart');
2215 | e.identifier = touches[i].identifier;
2216 | e._initPosition(touches[i].pageX, touches[i].pageY);
2217 | that.dispatchEvent(e);
2218 | }
2219 | }, false);
2220 | this._element.addEventListener('touchmove', function(e) {
2221 | var touches = e.touches;
2222 | for (var i = 0, len = touches.length; i < len; i++) {
2223 | e = new enchant.Event('touchmove');
2224 | e.identifier = touches[i].identifier;
2225 | e._initPosition(touches[i].pageX, touches[i].pageY);
2226 | that.dispatchEvent(e);
2227 | }
2228 | }, false);
2229 | this._element.addEventListener('touchend', function(e) {
2230 | var touches = e.changedTouches;
2231 | for (var i = 0, len = touches.length; i < len; i++) {
2232 | e = new enchant.Event('touchend');
2233 | e.identifier = touches[i].identifier;
2234 | e._initPosition(touches[i].pageX, touches[i].pageY);
2235 | that.dispatchEvent(e);
2236 | }
2237 | }, false);
2238 | } else {
2239 | this._element.addEventListener('mousedown', function(e) {
2240 | var x = e.pageX;
2241 | var y = e.pageY;
2242 | e = new enchant.Event('touchstart');
2243 | e.identifier = game._mousedownID;
2244 | e._initPosition(x, y);
2245 | that.dispatchEvent(e);
2246 | that._mousedown = true;
2247 | }, false);
2248 | game._element.addEventListener('mousemove', function(e) {
2249 | if (!that._mousedown) return;
2250 | var x = e.pageX;
2251 | var y = e.pageY;
2252 | e = new enchant.Event('touchmove');
2253 | e.identifier = game._mousedownID;
2254 | e._initPosition(x, y);
2255 | that.dispatchEvent(e);
2256 | }, false);
2257 | game._element.addEventListener('mouseup', function(e) {
2258 | if (!that._mousedown) return;
2259 | var x = e.pageX;
2260 | var y = e.pageY;
2261 | e = new enchant.Event('touchend');
2262 | e.identifier = game._mousedownID;
2263 | e._initPosition(x, y);
2264 | that.dispatchEvent(e);
2265 | that._mousedown = false;
2266 | }, false);
2267 | }
2268 | },
2269 | /**
2270 | * Sceneの背景色.
2271 | * CSSの'color'プロパティと同様の形式で指定できる.
2272 | * @type {String}
2273 | */
2274 | backgroundColor: {
2275 | get: function() {
2276 | return this._backgroundColor;
2277 | },
2278 | set: function(color) {
2279 | this._element.style.backgroundColor = this._backgroundColor = color;
2280 | }
2281 | },
2282 | _updateCoordinate: function() {
2283 | this._offsetX = this._x;
2284 | this._offsetY = this._y;
2285 | for (var i = 0, len = this.childNodes.length; i < len; i++) {
2286 | this.childNodes[i]._updateCoordinate();
2287 | }
2288 | }
2289 | });
2290 |
2291 | var CANVAS_DRAWING_METHODS = [
2292 | 'putImageData', 'drawImage', 'drawFocusRing', 'fill', 'stroke',
2293 | 'clearRect', 'fillRect', 'strokeRect', 'fillText', 'strokeText'
2294 | ];
2295 |
2296 | /**
2297 | * @scope enchant.Surface.prototype
2298 | */
2299 | enchant.Surface = enchant.Class.create(enchant.EventTarget, {
2300 | /**
2301 | * canvas要素をラップしたクラス.
2302 | *
2303 | * SpriteやMapのimageプロパティに設定して表示させることができる.
2304 | * Canvas APIにアクセスしたいときはcontextプロパティを用いる.
2305 | *
2306 | * @example
2307 | * // 円を表示するSpriteを作成する
2308 | * var ball = new Sprite(50, 50);
2309 | * var surface = new Surface(50, 50);
2310 | * surface.context.beginPath();
2311 | * surface.context.arc(25, 25, 25, 0, Math.PI*2, true);
2312 | * surface.context.fill();
2313 | * ball.image = surface;
2314 | *
2315 | * @param {Number} width Surfaceの横幅.
2316 | * @param {Number} height Surfaceの高さ.
2317 | * @constructs
2318 | */
2319 | initialize: function(width, height) {
2320 | enchant.EventTarget.call(this);
2321 |
2322 | /**
2323 | * Surfaceの横幅.
2324 | * @type {Number}
2325 | */
2326 | this.width = width;
2327 | /**
2328 | * Surfaceの高さ.
2329 | * @type {Number}
2330 | */
2331 | this.height = height;
2332 | /**
2333 | * Surfaceの描画コンテクスト.
2334 | * @type {CanvasRenderingContext2D}
2335 | */
2336 | this.context = null;
2337 |
2338 | var id = 'enchant-surface' + game._surfaceID++;
2339 | if (document.getCSSCanvasContext) {
2340 | this.context = document.getCSSCanvasContext('2d', id, width, height);
2341 | this._element = this.context.canvas;
2342 | this._css = '-webkit-canvas(' + id + ')';
2343 | var context = this.context;
2344 | } else if (document.mozSetImageElement) {
2345 | this._element = document.createElement('canvas');
2346 | this._element.width = width;
2347 | this._element.height = height;
2348 | this._css = '-moz-element(#' + id + ')';
2349 | this.context = this._element.getContext('2d');
2350 | document.mozSetImageElement(id, this._element)
2351 | } else {
2352 | this._element = document.createElement('canvas');
2353 | this._element.width = width;
2354 | this._element.height = height;
2355 | this._element.style.position = 'absolute';
2356 | this.context = this._element.getContext('2d');
2357 |
2358 | CANVAS_DRAWING_METHODS.forEach(function(name) {
2359 | var method = this.context[name];
2360 | this.context[name] = function() {
2361 | method.apply(this, arguments);
2362 | this._dirty = true;
2363 | }
2364 | }, this);
2365 | }
2366 | },
2367 | /**
2368 | * Surfaceから1ピクセル取得する.
2369 | * @param {Number} x 取得するピクセルのx座標.
2370 | * @param {Number} y 取得するピクセルのy座標.
2371 | * @return {Array.} ピクセルの情報を[r, g, b, a]の形式で持つ配列.
2372 | */
2373 | getPixel: function(x, y) {
2374 | return this.context.getImageData(x, y, 1, 1).data;
2375 | },
2376 | /**
2377 | * Surfaceに1ピクセル設定する.
2378 | * @param {Number} x 設定するピクセルのx座標.
2379 | * @param {Number} y 設定するピクセルのy座標.
2380 | * @param {Number} r 設定するピクセルのrの値.
2381 | * @param {Number} g 設定するピクセルのgの値.
2382 | * @param {Number} b 設定するピクセルのbの値.
2383 | * @param {Number} a 設定するピクセルの透明度.
2384 | */
2385 | setPixel: function(x, y, r, g, b, a) {
2386 | var pixel = this.context.createImageData(1, 1);
2387 | pixel.data[0] = r;
2388 | pixel.data[1] = g;
2389 | pixel.data[2] = b;
2390 | pixel.data[3] = a;
2391 | this.context.putImageData(pixel, x, y, 1, 1);
2392 | },
2393 | /**
2394 | * Surfaceの全ピクセルをクリアし透明度0の黒に設定する.
2395 | */
2396 | clear: function() {
2397 | this.context.clearRect(0, 0, this.width, this.height);
2398 | },
2399 | /**
2400 | * Surfaceに対して引数で指定されたSurfaceを描画する.
2401 | *
2402 | * Canvas APIのdrawImageをラップしており, 描画する矩形を同様の形式で指定できる.
2403 | *
2404 | * @example
2405 | * var src = game.assets['src.gif'];
2406 | * var dst = new Surface(100, 100);
2407 | * dst.draw(src); // ソースを(0, 0)に描画
2408 | * dst.draw(src, 50, 50); // ソースを(50, 50)に描画
2409 | * // ソースを(50, 50)に縦横30ピクセル分だけ描画
2410 | * dst.draw(src, 50, 50, 30, 30);
2411 | * // ソースの(10, 10)から縦横40ピクセルの領域を(50, 50)に縦横30ピクセルに縮小して描画
2412 | * dst.draw(src, 10, 10, 40, 40, 50, 50, 30, 30);
2413 | *
2414 | * @param {enchant.Surface} image 描画に用いるSurface.
2415 | */
2416 | draw: function(image) {
2417 | arguments[0] = image = image._element;
2418 | if (arguments.length == 1) {
2419 | this.context.drawImage(image, 0, 0);
2420 | } else {
2421 | this.context.drawImage.apply(this.context, arguments);
2422 | }
2423 | },
2424 | /**
2425 | * Surfaceを複製する.
2426 | * @return {enchant.Surface} 複製されたSurface.
2427 | */
2428 | clone: function() {
2429 | var clone = new enchant.Surface(this.width, this.height);
2430 | clone.draw(this);
2431 | return clone;
2432 | }
2433 | });
2434 |
2435 | /**
2436 | * 画像ファイルを読み込んでSurfaceオブジェクトを作成する.
2437 | *
2438 | * このメソッドによって作成されたSurfaceはimg要素のラップしておりcontextプロパティに
2439 | * アクセスしたりdraw, clear, getPixel, setPixelメソッドなどの呼び出しでCanvas API
2440 | * を使った画像操作を行うことはできない. ただしdrawメソッドの引数とすることはでき,
2441 | * ほかのSurfaceに描画した上で画像操作を行うことはできる(クロスドメインでロードした
2442 | * 場合はピクセルを取得するなど画像操作の一部が制限される).
2443 | *
2444 | * @param {String} src ロードする画像ファイルのパス.
2445 | * @static
2446 | */
2447 | enchant.Surface.load = function(src) {
2448 | var image = new Image();
2449 | var surface = Object.create(Surface.prototype, {
2450 | context: { value: null },
2451 | _css: { value: 'url(' + src + ')' },
2452 | _element: { value: image }
2453 | });
2454 | enchant.EventTarget.call(surface);
2455 | image.src = src;
2456 | image.onerror = function() {
2457 | throw new Error('Cannot load an asset: ' + image.src);
2458 | };
2459 | image.onload = function() {
2460 | surface.width = image.width;
2461 | surface.height = image.height;
2462 | surface.dispatchEvent(new enchant.Event('load'));
2463 | };
2464 | return surface;
2465 | };
2466 |
2467 | /**
2468 | * @scope enchant.Sound.prototype
2469 | */
2470 | enchant.Sound = enchant.Class.create(enchant.EventTarget, {
2471 | /**
2472 | * audio要素をラップしたクラス.
2473 | *
2474 | * MP3ファイルの再生はSafari, Chrome, Firefox, Opera, IEが対応
2475 | * (Firefox, OperaではFlashを経由して再生). WAVEファイルの再生は
2476 | * Safari, Chrome, Firefox, Operaが対応している. ブラウザが音声ファイル
2477 | * のコーデックに対応していない場合は再生されない.
2478 | *
2479 | * コンストラクタではなくenchant.Sound.loadを通じてインスタンスを作成する.
2480 | *
2481 | * @constructs
2482 | */
2483 | initialize: function() {
2484 | enchant.EventTarget.call(this);
2485 | throw new Error("Illegal Constructor");
2486 |
2487 | /**
2488 | * Soundの再生時間 (秒).
2489 | * @type {Number}
2490 | */
2491 | this.duration = 0;
2492 | },
2493 | /**
2494 | * 再生を開始する.
2495 | */
2496 | play: function() {
2497 | if (this._element) this._element.play();
2498 | },
2499 | /**
2500 | * 再生を中断する.
2501 | */
2502 | pause: function() {
2503 | if (this._element) this._element.pause();
2504 | },
2505 | /**
2506 | * 再生を停止する.
2507 | */
2508 | stop: function() {
2509 | this.pause();
2510 | this.currentTime = 0;
2511 | },
2512 | /**
2513 | * Soundを複製する.
2514 | * @return {enchant.Sound} 複製されたSound.
2515 | */
2516 | clone: function() {
2517 | var clone;
2518 | if (this._element instanceof Audio) {
2519 | clone = Object.create(enchant.Sound.prototype, {
2520 | _element: { value: this._element.cloneNode(false) },
2521 | duration: { value: this.duration }
2522 | });
2523 | } else {
2524 | clone = Object.create(enchant.Sound.prototype);
2525 | }
2526 | enchant.EventTarget.call(clone);
2527 | return clone;
2528 | },
2529 | /**
2530 | * 現在の再生位置 (秒).
2531 | * @type {Number}
2532 | */
2533 | currentTime: {
2534 | get: function() {
2535 | return this._element ? this._element.currentTime : 0;
2536 | },
2537 | set: function(time) {
2538 | if (this._element) this._element.currentTime = time;
2539 | }
2540 | },
2541 | /**
2542 | * ボリューム. 0 (無音) ~ 1 (フルボリューム).
2543 | * @type {Number}
2544 | */
2545 | volume: {
2546 | get: function() {
2547 | return this._element ? this._element.volume : 1;
2548 | },
2549 | set: function(volume) {
2550 | if (this._element) this._element.volume = volume;
2551 | }
2552 | }
2553 | });
2554 |
2555 | /**
2556 | * 音声ファイルを読み込んでSurfaceオブジェクトを作成する.
2557 | *
2558 | * @param {String} src ロードする音声ファイルのパス.
2559 | * @param {String} [type] 音声ファイルのMIME Type.
2560 | * @static
2561 | */
2562 | enchant.Sound.load = function(src, type) {
2563 | if (type == null) {
2564 | var ext = src.match(/\.\w+$/)[0];
2565 | if (ext) {
2566 | type = 'audio/' + ext.slice(1).toLowerCase();
2567 | } else {
2568 | type = '';
2569 | }
2570 | }
2571 | type = type.replace('mp3', 'mpeg');
2572 |
2573 | var sound = Object.create(enchant.Sound.prototype);
2574 | enchant.EventTarget.call(sound);
2575 | var audio = new Audio();
2576 | if (!enchant.Sound.enabledInMobileSafari &&
2577 | VENDER_PREFIX == 'webkit' && TOUCH_ENABLED) {
2578 | window.setTimeout(function() {
2579 | sound.dispatchEvent(new enchant.Event('load'));
2580 | }, 0);
2581 | } else {
2582 | if (audio.canPlayType(type)) {
2583 | audio.src = src;
2584 | audio.load();
2585 | audio.autoplay = false;
2586 | audio.onerror = function() {
2587 | throw new Error('Cannot load an asset: ' + audio.src);
2588 | };
2589 | audio.addEventListener('canplaythrough', function() {
2590 | sound.duration = audio.duration;
2591 | sound.dispatchEvent(new enchant.Event('load'));
2592 | }, false);
2593 | sound._element = audio;
2594 | } else if (type == 'audio/mpeg') {
2595 | var embed = document.createElement('embed');
2596 | var id = 'enchant-audio' + game._soundID++;
2597 | embed.width = embed.height = 1;
2598 | embed.name = id;
2599 | embed.src = 'sound.swf?id=' + id + '&src=' + src;
2600 | embed.allowscriptaccess = 'always';
2601 | embed.style.position = 'absolute';
2602 | embed.style.left = '-1px';
2603 | sound.addEventListener('load', function() {
2604 | Object.defineProperties(embed, {
2605 | currentTime: {
2606 | get: function() { return embed.getCurrentTime() },
2607 | set: function(time) { embed.setCurrentTime(time) }
2608 | },
2609 | volume: {
2610 | get: function() { return embed.getVolume() },
2611 | set: function(volume) { embed.setVolume(volume) }
2612 | }
2613 | });
2614 | sound._element = embed;
2615 | sound.duration = embed.getDuration();
2616 | });
2617 | game._element.appendChild(embed);
2618 | enchant.Sound[id] = sound;
2619 | } else {
2620 | window.setTimeout(function() {
2621 | sound.dispatchEvent(new enchant.Event('load'));
2622 | }, 0);
2623 | }
2624 | }
2625 | return sound;
2626 | };
2627 |
2628 | enchant.Sound.enabledInMobileSafari = false;
2629 |
2630 | })();
2631 |
--------------------------------------------------------------------------------