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