1 /** 2 * @fileOverview 3 * ui.enchant.js v2 (2012/11/05) 4 * ui parts support 5 * @require enchant.js v0.5.2 or later 6 * @require image files for gamepad, icons (default: pad.png, apad.png, icon0.png, font0.png) 7 * 8 * @features 9 * - D-Pad (left, right, up, down) 10 * - Analog Pad 11 * - Button (3 built-in themes and can be customized) 12 * - MutableText 13 * - ScoreLabel 14 * - TimeLabel 15 * - LifeLabel 16 * - Bar 17 * - VirtualMap 18 * 19 * @usage 20 * [D-Pad] 21 * var pad = new Pad(); 22 * pad.x = 0; 23 * pad.y = 220; 24 * core.rootScene.addChild(pad); 25 * (input of X direction can be detected from "Xbuttonup" "Xbuttondown" events 26 * or enchant.Core.instance.input.X) 27 * 28 * [A-Pad] 29 * var pad = new APad(); 30 * pad.x = 0; 31 * pad.y = 220; 32 * core.rootScene.addChild(pad); 33 * (input can be detected from pad.vx/vy and pad.touched) 34 * 35 * [Button] 36 * var button = new Button("Press me"); 37 * button.addEventListener("touchstart", function(){ ... }) 38 * core.rootScene.addEventListener(button); 39 * 40 * var button_light = new Button("Press me", "light"); 41 * core.rootScene.addEventListener(button); 42 * 43 * var button_blue = new Button("Press me", "blue"); 44 * core.rootScene.addEventListener(button); 45 */ 46 47 /** 48 * @type {Object} 49 */ 50 enchant.ui = { assets: ['pad.png', 'apad.png', 'icon0.png', 'font0.png'] }; 51 52 /** 53 * 方向キーパッドのクラス: Pad 54 * @scope enchant.ui.Pad 55 */ 56 enchant.ui.Pad = enchant.Class.create(enchant.Sprite, { 57 /** 58 * 方向キーパッドオブジェクトを作成する。 59 * @constructs 60 * @extends enchant.Sprite 61 */ 62 initialize: function() { 63 var core = enchant.Core.instance; 64 var image = core.assets['pad.png']; 65 enchant.Sprite.call(this, image.width / 2, image.height); 66 this.image = image; 67 this.input = { left: false, right: false, up: false, down: false }; 68 this.addEventListener('touchstart', function(e) { 69 this._updateInput(this._detectInput(e.localX, e.localY)); 70 }); 71 this.addEventListener('touchmove', function(e) { 72 this._updateInput(this._detectInput(e.localX, e.localY)); 73 }); 74 this.addEventListener('touchend', function(e) { 75 this._updateInput({ left: false, right: false, up: false, down: false }); 76 }); 77 }, 78 _detectInput: function(x, y) { 79 x -= this.width * 0.5; 80 y -= this.height * 0.5; 81 var input = { left: false, right: false, up: false, down: false }; 82 if (x * x + y * y <= 2500 && x * x + y * y > 200) { 83 if (x < 0 && y < x * x * 0.1 && y > x * x * -0.1) { 84 input.left = true; 85 } 86 if (x > 0 && y < x * x * 0.1 && y > x * x * -0.1) { 87 input.right = true; 88 } 89 if (y < 0 && x < y * y * 0.1 && x > y * y * -0.1) { 90 input.up = true; 91 } 92 if (y > 0 && x < y * y * 0.1 && x > y * y * -0.1) { 93 input.down = true; 94 } 95 } 96 return input; 97 }, 98 _updateInput: function(input) { 99 var core = enchant.Core.instance; 100 ['left', 'right', 'up', 'down'].forEach(function(type) { 101 if (this.input[type] && !input[type]) { 102 core.changeButtonState(type, false); 103 } 104 if (!this.input[type] && input[type]) { 105 core.changeButtonState(type, true); 106 } 107 }, this); 108 this.input = input; 109 } 110 }); 111 112 /** 113 * アナログパッドのクラス: APad 114 * @scope enchant.ui.APad 115 */ 116 enchant.ui.APad = enchant.Class.create(enchant.Group, { 117 /** 118 * アナログパッドオブジェクトを作成する。 119 * @constructs 120 * @extends enchant.Group 121 * @param mode 122 * 'direct': 入力ベクトルは正規化されない (大きさは 0~1 の間) 123 * 'normal': 入力ベクトルを常に正規化する (大きさは常に1となる) 124 */ 125 initialize: function(mode) { 126 var core = enchant.Core.instance; 127 var image = core.assets['apad.png']; 128 var w = this.width = image.width; 129 var h = this.height = image.height; 130 enchant.Group.call(this); 131 132 this.outside = new enchant.Sprite(w, h); 133 var outsideImage = new enchant.Surface(w, h); 134 outsideImage.draw(image, 0, 0, w, h / 4, 0, 0, w, h / 4); 135 outsideImage.draw(image, 0, h / 4 * 3, w, h / 4, 0, h / 4 * 3, w, h / 4); 136 outsideImage.draw(image, 0, h / 4, w / 4, h / 2, 0, h / 4, w / 4, h / 2); 137 outsideImage.draw(image, w / 4 * 3, h / 4, w / 4, h / 2, w / 4 * 3, h / 4, w / 4, h / 2); 138 this.outside.image = outsideImage; 139 this.inside = new enchant.Sprite(w / 2, h / 2); 140 var insideImage = new enchant.Surface(w / 2, h / 2); 141 insideImage.draw(image, w / 4, h / 4, w / 2, h / 2, 0, 0, w / 2, h / 2); 142 this.inside.image = insideImage; 143 this.r = w / 2; 144 145 /** 146 * isTouched 147 * @type {Boolean} 148 * タッチされているかどうか 149 */ 150 this.isTouched = false; 151 152 /** 153 * vx, vy 154 * @type {Number} 155 * 入力ベクトルの(x, y)方向の大きさ 156 */ 157 this.vx = 0; 158 this.vy = 0; 159 160 /** 161 * rad, dist 162 * @type {Number} 163 * 入力ベクトルの極座標表示 164 * radは角度、distはベクトルの大きさを示す 165 */ 166 this.rad = 0; 167 this.dist = 0; 168 169 if (mode === 'direct') { 170 this.mode = 'direct'; 171 } else { 172 this.mode = 'normal'; 173 } 174 this._updateImage(); 175 this.addChild(this.inside); 176 this.addChild(this.outside); 177 this.addEventListener('touchstart', function(e) { 178 this._detectInput(e.localX, e.localY); 179 this._calcPolar(e.localX, e.localY); 180 this._updateImage(e.localX, e.localY); 181 this._dispatchPadEvent('apadstart'); 182 this.isTouched = true; 183 }); 184 this.addEventListener('touchmove', function(e) { 185 this._detectInput(e.localX, e.localY); 186 this._calcPolar(e.localX, e.localY); 187 this._updateImage(e.localX, e.localY); 188 this._dispatchPadEvent('apadmove'); 189 }); 190 this.addEventListener('touchend', function(e) { 191 this._detectInput(this.width / 2, this.height / 2); 192 this._calcPolar(this.width / 2, this.height / 2); 193 this._updateImage(this.width / 2, this.height / 2); 194 this._dispatchPadEvent('apadend'); 195 this.isTouched = false; 196 }); 197 }, 198 _dispatchPadEvent: function(type) { 199 var e = new enchant.Event(type); 200 e.vx = this.vx; 201 e.vy = this.vy; 202 e.rad = this.rad; 203 e.dist = this.dist; 204 this.dispatchEvent(e); 205 }, 206 _updateImage: function(x, y) { 207 x -= this.width / 2; 208 y -= this.height / 2; 209 this.inside.x = this.vx * (this.r - 10) + 25; 210 this.inside.y = this.vy * (this.r - 10) + 25; 211 }, 212 _detectInput: function(x, y) { 213 x -= this.width / 2; 214 y -= this.height / 2; 215 var distance = Math.sqrt(x * x + y * y); 216 var tan = y / x; 217 var rad = Math.atan(tan); 218 var dir = x / Math.abs(x); 219 if (distance === 0) { 220 this.vx = 0; 221 this.vy = 0; 222 } else if (x === 0) { 223 this.vx = 0; 224 if (this.mode === 'direct') { 225 this.vy = (y / this.r); 226 } else { 227 dir = y / Math.abs(y); 228 this.vy = Math.pow((y / this.r), 2) * dir; 229 } 230 } else if (distance < this.r) { 231 if (this.mode === 'direct') { 232 this.vx = (x / this.r); 233 this.vy = (y / this.r); 234 } else { 235 this.vx = Math.pow((distance / this.r), 2) * Math.cos(rad) * dir; 236 this.vy = Math.pow((distance / this.r), 2) * Math.sin(rad) * dir; 237 } 238 } else { 239 this.vx = Math.cos(rad) * dir; 240 this.vy = Math.sin(rad) * dir; 241 } 242 }, 243 _calcPolar: function(x, y) { 244 x -= this.width / 2; 245 y -= this.height / 2; 246 var add = 0; 247 var rad = 0; 248 var dist = Math.sqrt(x * x + y * y); 249 if (dist > this.r) { 250 dist = this.r; 251 } 252 dist /= this.r; 253 if (this.mode === 'normal') { 254 dist *= dist; 255 } 256 if (x >= 0 && y < 0) { 257 add = Math.PI / 2 * 3; 258 rad = x / y; 259 } else if (x < 0 && y <= 0) { 260 add = Math.PI; 261 rad = y / x; 262 } else if (x <= 0 && y > 0) { 263 add = Math.PI / 2; 264 rad = x / y; 265 } else if (x > 0 && y >= 0) { 266 add = 0; 267 rad = y / x; 268 } 269 if (x === 0 || y === 0) { 270 rad = 0; 271 } 272 this.rad = Math.abs(Math.atan(rad)) + add; 273 this.dist = dist; 274 } 275 }); 276 277 /** 278 * ボタンオブジェクトのクラス: Button 279 * available in only DOMGroup 280 * 281 * @scope enchant.ui.Button.prototype 282 * @deprecated 283 * @classes 284 */ 285 enchant.ui.Button = enchant.Class.create(enchant.Entity, { 286 /** 287 * ボタンオブジェクトを作成する。 288 * @constructs 289 * @extends enchant.Entity 290 */ 291 initialize: function(text, theme, height, width) { 292 enchant.Entity.call(this); 293 294 if (enchant.CanvasLayer) { 295 this._element = 'div'; 296 } 297 298 this.width = width || null; 299 this.height = height || null; 300 this.text = text; 301 this.pressed = false; 302 303 // デフォルトのスタイル (テーマで上書き可能) 304 var style = this._style; 305 style["display"] = "inline-block"; 306 style["font-size"] = "12px"; 307 style["height"] = "2em"; 308 style["line-height"] = "2em"; 309 style["min-width"] = "2em"; 310 style["padding"] = "2px 10px"; 311 style["text-align"] = "center"; 312 style["font-weight"] = "bold"; 313 style["border-radius"] = "0.5em"; 314 315 // テーマの指定がなければ "dark" を使う 316 theme = theme || "dark"; 317 318 if (typeof theme === "string") { 319 // theme 引数が string なら、その名前のデフォルトテーマを使う 320 this.theme = enchant.ui.Button.DEFAULT_THEME[theme]; 321 } else { 322 // theme 引数が object なら、その引数をテーマとして扱う 323 this.theme = theme; 324 } 325 326 // テーマを適用する 327 this._applyTheme(this.theme.normal); 328 329 // タッチしたときの挙動 330 this.addEventListener("touchstart", function() { 331 this._applyTheme(this.theme.active); 332 this.pressed = true; 333 this.y++; 334 }); 335 336 // タッチが離されたときの挙動 337 this.addEventListener("touchend", function() { 338 this._applyTheme(this.theme.normal); 339 this.pressed = false; 340 this.y--; 341 }); 342 }, 343 _applyTheme: function(theme) { 344 var style = this._style; 345 var css = enchant.ui.Button.theme2css(theme); 346 for (var i in css) { 347 if (css.hasOwnProperty(i)) { 348 style[i] = css[i]; 349 } 350 } 351 }, 352 /** 353 * 表示するテキスト 354 * @type {String} 355 */ 356 text: { 357 get: function() { 358 return this._text; 359 }, 360 set: function(text) { 361 this._text = text; 362 if (!enchant.CanvasLayer) { 363 this._element.innerHTML = text; 364 } 365 } 366 }, 367 /** 368 * フォントサイズ 369 */ 370 size: { 371 get: function() { 372 return this._style.fontSize; 373 }, 374 set: function(size) { 375 this._style.fontSize = size; 376 } 377 }, 378 /** 379 * フォントの指定 380 * @type {String} 381 */ 382 font: { 383 get: function() { 384 return this._style.font; 385 }, 386 set: function(font) { 387 this._style.font = font; 388 } 389 }, 390 /** 391 * Text color settings. 392 * CSS 'color' can be set to same format as properties. 393 * @type {String} 394 */ 395 color: { 396 get: function() { 397 return this._style.color; 398 }, 399 set: function(color) { 400 this._style.color = color; 401 } 402 }, 403 cvsRender: function() { 404 // not available now 405 }, 406 domRender: function() { 407 var element = this._domManager.element; 408 element.innerHTML = this._text; 409 element.style.font = this._font; 410 element.style.color = this._color; 411 element.style.textAlign = this._textAlign; 412 } 413 }); 414 415 enchant.ui.Button.theme2css = function(theme) { 416 var prefix = '-' + enchant.ENV.VENDOR_PREFIX.toLowerCase() + '-'; 417 var obj = {}; 418 var bg = theme.background; 419 var bd = theme.border; 420 var ts = theme.textShadow; 421 var bs = theme.boxShadow; 422 if (prefix === '-ms-') { 423 obj['background'] = bg.start; 424 } else { 425 obj['background-image'] = prefix + bg.type + '('+ [ 'top', bg.start, bg.end ] + ')'; 426 } 427 obj['color'] = theme.color; 428 obj['border'] = bd.color + ' ' + bd.width + ' ' + bd.type; 429 obj['text-shadow'] = ts.offsetX + 'px ' + ts.offsetY + 'px ' + ts.blur + ' ' + ts.color; 430 obj['box-shadow'] = bs.offsetX + 'px ' + bs.offsetY + 'px ' + bs.blur + ' ' + bs.color; 431 return obj; 432 }; 433 434 enchant.ui.Button.DEFAULT_THEME = { 435 dark: { 436 normal: { 437 color: '#fff', 438 background: { type: 'linear-gradient', start: '#666', end: '#333' }, 439 border: { color: '#333', width: 1, type: 'solid' }, 440 textShadow: { offsetX: 0, offsetY: 1, blur: 0, color: '#666' }, 441 boxShadow: { offsetX: 0, offsetY: 1, blur: 0, color: 'rgba(255, 255, 255, 0.3)' } 442 }, 443 active: { 444 color: '#ccc', 445 background: { type: 'linear-gradient', start: '#333', end: '#000' }, 446 border: { color: '#333', width: 1, type: 'solid' }, 447 textShadow: { offsetX: 0, offsetY: 1, blur: 0, color: '#000' }, 448 boxShadow: { offsetX: 0, offsetY: 1, blur: 0, color: 'rgba(255, 255, 255, 0.3)' } 449 } 450 }, 451 light: { 452 normal: { 453 color: '#333', 454 background: { type: 'linear-gradient', start: '#fff', end:'#ccc' }, 455 border: { color: '#999', width: 1, type: 'solid' }, 456 textShadow: { offsetX: 0, offsetY: 1, blur: 0, color: '#fff' }, 457 boxShadow: { offsetX: 0, offsetY: 1, blur: 0, color: 'rgba(0, 0, 0, 1)' }, 458 }, 459 active: { 460 color: '#333', 461 background: { type: 'linear-gradient', start: '#ccc', end: '#999' }, 462 border: { color: '#666', width: 1, type: 'solid' }, 463 textShadow: { offsetX: 0, offsetY: 1, blur: 0, color: '#ccc' }, 464 boxShadow: { offsetX: 0, offsetY: 1, blur: 0, color: 'rgba(255, 255, 255, 0.3)' } 465 } 466 }, 467 blue: { 468 normal: { 469 color: '#fff', 470 background: { type: 'linear-gradient', start: '#04f', end: '#04c' }, 471 border: { color: '#026', width: 1, type: 'solid' }, 472 textShadow: { offsetX: 0, offsetY: 1, blur: 0, color: '#666' }, 473 boxShadow: { offsetX: 0, offsetY: 1, blur: 0, color: 'rgba(0, 0, 0, 0.5)' } 474 }, 475 active: { 476 color: '#ccc', 477 background: { type: 'linear-gradient', start: '#029', end: '#026' }, 478 border: { color: '#026', width: 1, type: 'solid' }, 479 textShadow: { offsetX: 0, offsetY: 1, blur: 0, color: '#000' }, 480 boxShadow: 'none' 481 } 482 } 483 }; 484 485 /** 486 * @scope enchant.ui.MutableText.prototype 487 * @type {*} 488 */ 489 enchant.ui.MutableText = enchant.Class.create(enchant.Sprite, { 490 /** 491 * ビットマップフォントを用いたラベルクラス 492 * (参考: draw.text.js http://d.hatena.ne.jp/nakamura001/20110430/1304181043) 493 * enchant.js 添付素材の font*.png が利用可能。 494 * 495 * @usage 496 * var text = new MutableText(0, 0); 497 * game.text = 'Hello, world!'; 498 * game.rootScene.addChild(text); 499 * 500 * @constructs 501 * @param posX 502 * @param posY 503 * @param width 504 */ 505 initialize: function(x, y, width) { 506 enchant.Sprite.call(this, 0, 0); 507 this.fontSize = 16; 508 this.widthItemNum = 16; 509 this.x = x; 510 this.y = y; 511 this._imageAge = Number.MAX_VALUE; 512 this.text = ''; 513 if (arguments[2]) { 514 this.row = Math.floor(arguments[2] / this.fontSize); 515 } 516 }, 517 /** 518 * ラベルの内容を書き換える関数 519 * @param txt 520 */ 521 setText: function(txt) { 522 var i, x, y, wNum, charCode, charPos; 523 this._text = txt; 524 var newWidth; 525 if (!this.returnLength) { 526 this.width = Math.min(this.fontSize * this._text.length, enchant.Game.instance.width); 527 } else { 528 this.width = Math.min(this.returnLength * this.fontSize, enchant.Game.instance.width); 529 } 530 this.height = this.fontSize * (Math.ceil(this._text.length / this.row) || 1); 531 // if image is to small or was to big for a long time create new image 532 if(!this.image || this.width > this.image.width || this.height > this.image.height || this._imageAge > 300) { 533 this.image = new enchant.Surface(this.width, this.height); 534 this._imageAge = 0; 535 } else if(this.width < this.image.width || this.height < this.image.height) { 536 this._imageAge++; 537 } else { 538 this._imageAge = 0; 539 } 540 this.image.context.clearRect(0, 0, this.width, this.height); 541 for (i = 0; i < txt.length; i++) { 542 charCode = txt.charCodeAt(i); 543 if (charCode >= 32 && charCode <= 127) { 544 charPos = charCode - 32; 545 } else { 546 charPos = 0; 547 } 548 x = charPos % this.widthItemNum; 549 y = (charPos / this.widthItemNum) | 0; 550 this.image.draw(enchant.Game.instance.assets['font0.png'], 551 x * this.fontSize, y * this.fontSize, this.fontSize, this.fontSize, 552 (i % this.row) * this.fontSize, ((i / this.row) | 0) * this.fontSize, this.fontSize, this.fontSize); 553 } 554 }, 555 /** 556 * ラベルの内容 557 * @type {String} 558 */ 559 text: { 560 get: function() { 561 return this._text; 562 }, 563 set: function(txt) { 564 this.setText(txt); 565 } 566 }, 567 /** 568 * @type {Number} 569 */ 570 row: { 571 get: function() { 572 return this.returnLength || this.width / this.fontSize; 573 }, 574 set: function(row) { 575 this.returnLength = row; 576 this.text = this.text; 577 } 578 } 579 }); 580 581 /** 582 * @scope enchant.ui.ScoreLabel.prototype 583 * @type {*} 584 */ 585 enchant.ui.ScoreLabel = enchant.Class.create(enchant.ui.MutableText, { 586 /** 587 * スコアを表示するラベル。 588 * 画像フォントクラス (MutableText) を使って表示する。 589 * @constructs 590 * @param x 591 * @param y 592 */ 593 initialize: function(x, y) { 594 enchant.ui.MutableText.call(this, 0, 0); 595 switch (arguments.length) { 596 case 2: 597 this.y = y; 598 this.x = x; 599 break; 600 case 1: 601 this.x = x; 602 break; 603 default: 604 break; 605 } 606 this._score = 0; 607 this._current = 0; 608 this.easing = 2.5; 609 this.text = this.label = 'SCORE:'; 610 this.addEventListener('enterframe', function() { 611 if (this.easing === 0) { 612 this.text = this.label + (this._current = this._score); 613 } else { 614 var dist = this._score - this._current; 615 if (0 < dist) { 616 this._current += Math.ceil(dist / this.easing); 617 } else if (dist < 0) { 618 this._current += Math.floor(dist / this.easing); 619 } 620 this.text = this.label + this._current; 621 } 622 }); 623 }, 624 /** 625 * スコア 626 * @type {Number} 627 */ 628 score: { 629 get: function() { 630 return this._score; 631 }, 632 set: function(newscore) { 633 this._score = newscore; 634 } 635 } 636 }); 637 638 /** 639 * @type {*} 640 * @scope enchant.ui.TimeLabel.prototype 641 */ 642 enchant.ui.TimeLabel = enchant.Class.create(enchant.ui.MutableText, { 643 /** 644 * 残り時間などのタイムを表示するラベル 645 * @constructs 646 * @param x 647 * @param y 648 * @param counttype 649 */ 650 initialize: function(x, y, counttype) { 651 enchant.ui.MutableText.call(this, 0, 0); 652 switch (arguments.length) { 653 case 3: 654 case 2: 655 this.y = y; 656 this.x = x; 657 break; 658 case 1: 659 this.x = x; 660 break; 661 default: 662 break; 663 } 664 this._time = 0; 665 this._count = 1;// この数を毎フレーム每に足して上げ下げを制御する 666 if (counttype === 'countdown') { 667 this._count = -1; 668 } 669 this.text = this.label = 'TIME:'; 670 this.addEventListener('enterframe', function() { 671 this._time += this._count; 672 this.text = this.label + (this._time / enchant.Game.instance.fps).toFixed(2); 673 }); 674 }, 675 /** 676 * 残り時間 677 * @type {Number} 678 */ 679 time: { 680 get: function() { 681 return Math.floor(this._time / enchant.Game.instance.fps); 682 }, 683 set: function(newtime) { 684 this._time = newtime * enchant.Game.instance.fps; 685 } 686 } 687 }); 688 689 /** 690 * @type {*} 691 * @scope enchant.ui.LifeLabel.prototype 692 */ 693 enchant.ui.LifeLabel = enchant.Class.create(enchant.Group, { 694 /** 695 * ライフを表示する専用のラベル 696 * icon0.png 内のハートの画像を用いる 697 * @constructs 698 * @param x 699 * @param y 700 * @param maxlife 701 */ 702 initialize: function(x, y, maxlife) { 703 enchant.Group.call(this); 704 this.x = x || 0; 705 this.y = y || 0; 706 this._maxlife = maxlife || 9; 707 this._life = 0; 708 this.label = new enchant.ui.MutableText(0, 0, 80); 709 this.label.text = 'LIFE:'; 710 this.addChild(this.label); 711 this.heart = []; 712 for (var i = 0; i < this._maxlife; i++) { 713 this.heart[i] = new enchant.Sprite(16, 16); 714 this.heart[i].image = enchant.Game.instance.assets['icon0.png']; 715 this.heart[i].x = this.label.width + i * 16; 716 this.heart[i].y = -3; 717 this.heart[i].frame = 10; 718 this.addChild(this.heart[i]); 719 } 720 }, 721 /** 722 * 残りライフの数 723 * @type {Number} 724 */ 725 life: { 726 get: function() { 727 return this._life; 728 }, 729 set: function(newlife) { 730 this._life = newlife; 731 if (this._maxlife < newlife) { 732 this._life = this._maxlife; 733 } 734 for (var i = 0; i < this._maxlife; i++) { 735 this.heart[i].visible = (i <= newlife - 1); 736 } 737 } 738 } 739 }); 740 741 /** 742 * @scope enchant.ui.Bar 743 * @type {*} 744 */ 745 enchant.ui.Bar = enchant.Class.create(enchant.Sprite, { 746 /** 747 * イージング付きのバークラス 748 * @constructs 749 * @param x 750 * @param y 751 */ 752 initialize: function(x, y) { 753 enchant.Sprite.call(this, 1, 16); 754 this.image = new enchant.Surface(1, 16);// Null用 755 this.image.context.fillColor = 'RGB(0, 0, 256)'; 756 this.image.context.fillRect(0, 0, 1, 16); 757 this._direction = 'right'; 758 this._origin = 0; 759 this._maxvalue = enchant.Game.instance.width; 760 this._lastvalue = 0; 761 this.value = 0; 762 this.easing = 5; 763 switch (arguments.length) { 764 case 2: 765 this.y = y; 766 this.x = x; 767 this._origin = x; 768 break; 769 case 1: 770 this.x = x; 771 this._origin = x; 772 break; 773 default: 774 break; 775 } 776 this.addEventListener('enterframe', function() { 777 if (this.value < 0) { 778 this.value = 0; 779 } 780 this._lastvalue += (this.value - this._lastvalue) / this.easing; 781 if (Math.abs(this._lastvalue - this.value) < 1.3) { 782 this._lastvalue = this.value; 783 } 784 this.width = (this._lastvalue) | 0; 785 if (this.width > this._maxvalue) { 786 this.width = this._maxvalue; 787 } 788 if (this._direction === 'left') { 789 this._x = this._origin - this.width; 790 } else { 791 this._x = this._origin; 792 } 793 this._updateCoordinate(); 794 }); 795 }, 796 /** 797 * バーの向き ('right' or 'left') 798 * @default 'right' 799 * @type {String} 800 */ 801 direction: { 802 get: function() { 803 return this._direction; 804 }, 805 set: function(newdirection) { 806 if (newdirection !== 'right' && newdirection !== 'left') { 807 // ignore 808 } else { 809 this._direction = newdirection; 810 } 811 } 812 }, 813 /** 814 * x 座標 815 * @type {Number} 816 */ 817 x: { 818 get: function() { 819 return this._origin; 820 }, 821 set: function(x) { 822 this._x = x; 823 this._origin = x; 824 this._dirty = true; 825 } 826 }, 827 /** 828 * @type {Number} 829 */ 830 maxvalue: { 831 get: function() { 832 return this._maxvalue; 833 }, 834 set: function(val) { 835 this._maxvalue = val; 836 } 837 } 838 }); 839 840 /** 841 * @scope enchant.ui.VirtualMap.prototype 842 */ 843 enchant.ui.VirtualMap = enchant.Class.create(enchant.Group, { 844 /** 845 * マップライクな Group 846 * addChildで Sprite 等を追加すると、自動的に mx, my プロパティが追加され、 847 * VirtualMap内での座標で Sprite を操作できる 848 * 849 * 使い方 850 * //20 x 20 メッシュの縦横320ピクセルの盤を作り、その上に16 x 16の駒を8つ並べる 851 * var board = new VirtualMap(20, 20); 852 * board.width = 320; 853 * board.height = 320; 854 * for(var i=0; i<8; i++){ 855 * var piece = new Sprite(16, 16); 856 * piece.image = game.assets['icon0.gif']; 857 * board.addChild(piece); 858 * piece.mx = i + 3; 859 * piece.my = 16; 860 * } 861 * game.rootScene.addChild(board); 862 * 863 * @param meshWidth 864 * @param meshHeight 865 * @constructs 866 */ 867 initialize: function(meshWidth, meshHeight) { 868 enchant.Group.call(this); 869 this.meshWidth = meshWidth || 16; 870 this.meshHeight = meshHeight || 16; 871 }, 872 /** 873 * VirtualMap にオブジェクトを追加する (自動的にバインドされる) 874 * @param obj 875 */ 876 addChild: function(obj) { 877 enchant.Group.prototype.addChild.call(this, obj); 878 this.bind(obj); 879 }, 880 /** 881 * VirtualMap にオブジェクトを追加する 882 * reference で指定したオブジェクトより前に追加される (自動的にバインドされる)。 883 * @param obj 884 * @param reference 885 */ 886 insertBefore: function(obj, reference) { 887 enchant.Group.prototype.insertBefore.call(this, obj, reference); 888 this.bind(obj); 889 }, 890 /** 891 * オブジェクトを VirtualMap にバインドする。 892 * バインドされたオブジェクトはメッシュ座標 mx, my プロパティを持ち、これを操作することで 893 * VirtualMap の中を移動させることができる。 894 * @param obj 895 */ 896 bind: function(obj) { 897 Object.defineProperties(obj, { 898 "mx": { 899 get: function() { 900 return Math.floor(this.x / this.parentNode.meshWidth); 901 }, 902 set: function(arg) { 903 this.x = Math.floor(arg * this.parentNode.meshWidth); 904 } 905 }, 906 "my": { 907 get: function() { 908 return Math.floor(this.y / this.parentNode.meshHeight); 909 }, 910 set: function(arg) { 911 this.y = Math.floor(arg * this.parentNode.meshWidth); 912 } 913 } 914 }); 915 obj.mx = 0; 916 obj.my = 0; 917 } 918 }); 919 920 function rand(num) { 921 return Math.floor(Math.random() * num); 922 } 923