slap_min.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. function Slap(canvas) { var self = this; this.ua = navigator.userAgent.toLowerCase(); this.isMobile = (/mobile/).test(this.ua); this.canvas = canvas; this.ctx = canvas.getContext('2d'); var handler = new EventHandler(canvas); this.eventHandler = handler; this.startTime = 0; this.endTime = 0; this.score = 0; this.hitScore = 0; this.hitNum = 0; this.lastHitTime = null; this.over = false; this.startDelay = 3000; this.originDuration = 2500; this.hitBarFrameNum = (this.isMobile && !(/iphone/).test(this.ua)) ? 10 : 15; this.levelUpHitNum = 5; this.levelUpDelta = 100; this.hitDuration = 500; this.PAGE_MAIN = 1; this.PAGE_SPEC = 2; this.PAGE_GAME = 3; this.itv = null; this.itv2 = null; this.timer = new Timer(); this.isInitialized = false; this.resources = {}; this.loadResources(); this.resize(); window.addEventListener('resize', function () { self.resize(); }, false); this.gameName = 'slap'; this.backwardUrl = 'http://h.lexun.com'; }
  2. Slap.prototype = {
  3. loadResources: function () {
  4. var self = this; var loading = new Image(); loading.onload = function () {
  5. var resources = self.resources, len = 0; resources.mainBg = new Image(); len++; resources.specBg = new Image(); len++; resources.gameBg = new Image(); len++; resources.spritesheet = new Image(); len++; resources.spritesheet2 = new Image(); len++; resources.couple1 = new Image(); len++; resources.couple2 = new Image(); len++; resources.couple3 = new Image(); len++; resources.couple4 = new Image(); len++; resources.couple7 = new Image(); len++; resources.couple8 = new Image(); len++; resources.tips = new Image(); len++; var loaded = 0, ctx = self.ctx, canvas = self.canvas; function onload() { loaded++; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.save(); ctx.scale(canvas.width / 320, canvas.height / 480); ctx.fillStyle = '#2982BC'; ctx.font = 'normal bold 1em serif'; ctx.fillText(parseInt((loaded / len) * 100) + '%', 140, 305); ctx.fillText('正在努力加载中,请稍候', 76, 280); ctx.restore(); if (len === loaded) { self.createPages(); } }
  6. for (var i in resources) { if (resources.hasOwnProperty(i)) { resources[i].onload = onload; } }
  7. resources.mainBg.src = '1.jpg'; resources.specBg.src = '6.jpg'; resources.gameBg.src = 'bg.jpg'; resources.spritesheet.src = 'bg1.png'; resources.spritesheet2.src = 'bg3.png'; resources.couple1.src = 'couple1.png'; resources.couple2.src = 'couple2.png'; resources.couple3.src = 'couple3.png'; resources.couple4.src = 'couple4.png'; resources.couple7.src = 'couple7.png'; resources.couple8.src = 'couple8.png'; resources.tips.src = 's-o.png'; resources.sound = new Audio(); if (resources.sound.canPlayType('audio/mpeg') != '') { resources.sound.src = 'slap.mp3'; } else if (resources.sound.canPlayType('audio/ogg') != '') { resources.sound.src = 'slap.ogg'; }
  8. resources.sound.load();
  9. }
  10. loading.src = 'load.png';
  11. }, createPages: function () { this.mainPage = new MainPage(this); this.specPage = new SpecPage(this); this.gamePage = new GamePage(this); this.currentPage = this.mainPage; this.isInitialized = true; }, resize: function () {
  12. var canvas = this.canvas, innerWidth = window.innerWidth, innerHeight = window.innerHeight, scale = 640 / 960; var width = (innerWidth < 640) ? innerWidth : 640, height = (innerHeight < 960) ? innerHeight : 960; this.overflowX = 0, this.overflowY = 0; if (innerWidth >= innerHeight) { width = height * scale; }
  13. if ((/iphone/).test(this.ua)) { height += 60; } else if ((/android/).test(this.ua)) { height += 10; }
  14. canvas.width = width; canvas.height = height; canvas.style.left = (innerWidth > width) ? (innerWidth - width) / 2 + 'px' : 0; canvas.style.top = (innerHeight > height) ? (innerHeight - height) / 2 + 'px' : 0; this.mainPage && this.mainPage.onResize(); this.specPage && this.specPage.onResize(); this.gamePage && this.gamePage.onResize(); this.currentPage && this.currentPage.animate(this.timer.getTime());
  15. }, submitScore: function () {
  16. var score = this.score; if (score > 0) {
  17. var tt = ""; if (score < 1000) { tt = "用力用力,抽得太少了!!"; }
  18. else if (score > 1000 && score < 2500) { tt = "多ktn?"; }
  19. dp_share(score, this.hitNum);
  20. }
  21. }, run: function () { if (this.isInitialized) { var self = this, timer = this.timer; this.switchPage(this.PAGE_MAIN); this.itv = setInterval(function () { timer.update(); self.currentPage.animate(timer.getTime()); }, 30); this.ivt2 = setInterval(function () { window.scrollTo(0, 1); }, 500); } else { var self = this; setTimeout(function () { self.run() }, 500); } }, exit: function () { clearInterval(this.itv); clearInterval(this.itv2); window.location.href = this.backwardUrl; }, reset: function () { this.startTime = 0; this.endTime = 0; this.score = 0; this.hitScore = 0; this.hitNum = 0; this.lastHitTime = null; this.over = false; this.gamePage.reset(); }, startGame: function () { this.reset(); var date = new Date(); this.over = false; this.startTime = date.getTime() + this.startDelay; this.switchPage(this.PAGE_GAME); this.timer.resume(); }, stopGame: function (submit) {
  22. this.timer.pause(); var date = new Date(); this.endTime = date.getTime(); this.over = true; if (submit) { this.submitScore(); }
  23. var self = this; setTimeout(function () { self.switchPage(self.PAGE_MAIN); }, 1500);
  24. }, switchPage: function (index) {
  25. var page = this.currentPage, timer = this.timer; switch (index) { case this.PAGE_MAIN: page = this.mainPage; break; case this.PAGE_SPEC: page = this.specPage; break; case this.PAGE_GAME: page = this.gamePage; break; default: break; }
  26. this.canvas.setAttribute('class', page.pageName); this.currentPage = page; this.switchEventDispatcher(page.pageIndex); page.onPageChange(); page.animate(timer.getTime()); timer.pause();
  27. }, switchEventDispatcher: function (index) { this.eventHandler.dispatcherIndex = index; }
  28. }
  29. function MainPage(game) { this.pageName = 'MainPage'; this.game = game; this.canvas = game.canvas; this.ctx = game.canvas.getContext('2d'); var resources = game.resources; this.bgImg = new Sprite(resources.mainBg, 640, 960, 0, 0); this.width = this.bgImg.width; this.height = this.bgImg.height; this.scaleX = this.canvas.width / this.width; this.scaleY = this.canvas.height / this.height; this.pageIndex = game.PAGE_MAIN; var handler = game.eventHandler; var index = this.pageIndex; handler.setScales(1 / this.scaleX, 1 / this.scaleY, index); var startButton = new Button(this, 0, 0, Button.TYPE_START); startButton.setPosition((this.width / 2 - startButton.width) / 2, this.height / 2); this.startButton = startButton; var specButton = new Button(this, 0, 0, Button.TYPE_SPEC); specButton.setPosition(this.width / 2 + (this.width / 2 - specButton.width) / 2, this.height / 2); this.specButton = specButton; var exitButton = new Button(this, 0, 0, Button.TYPE_EXIT); exitButton.setPosition((this.width - exitButton.width) / 2, this.height / 2 + startButton.height * 2); this.exitButton = exitButton; if ('ontouchstart' in window) { handler.bind(index, 'touchstart', startButton, this.onStartButtonClick, this); handler.bind(index, 'touchstart', specButton, this.onSpecButtonClick, this); } else { handler.bind(index, 'click', startButton, this.onStartButtonClick, this); handler.bind(index, 'click', specButton, this.onSpecButtonClick, this); } }
  30. MainPage.prototype = { constuctor: this, onResize: function () { this.scaleX = this.canvas.width / this.width; this.scaleY = this.canvas.height / this.height; this.game.eventHandler.setScales(1 / this.scaleX, 1 / this.scaleY, this.pageIndex); }, drawButton: function (ctx) { this.startButton.draw(ctx); this.specButton.draw(ctx); }, animate: function (timestamp) { var ctx = this.ctx; ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.save(); ctx.scale(this.scaleX, this.scaleY); this.drawButton(ctx); ctx.restore(); }, onStartButtonClick: function (evt) { this.game.startGame(); }, onSpecButtonClick: function (evt) { var game = this.game; game.switchPage(game.PAGE_SPEC); }, onExitButtonClick: function (evt) { var game = this.game; game.exit(); }, onPageChange: function () { var ctx = this.ctx; ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.save(); ctx.scale(this.scaleX, this.scaleY); this.drawButton(ctx); ctx.restore(); } }
  31. function SpecPage(game) { this.pageName = 'SpecPage'; this.game = game; this.canvas = game.canvas; this.ctx = game.canvas.getContext('2d'); var resources = game.resources; this.bgImg = new Sprite(resources.specBg, 640, 960, 0, 0); this.width = this.bgImg.width; this.height = this.bgImg.height; this.scaleX = this.canvas.width / this.width; this.scaleY = this.canvas.height / this.height; this.pageIndex = game.PAGE_SPEC; var handler = game.eventHandler; var index = this.pageIndex; handler.setScales(1 / this.scaleX, 1 / this.scaleY, index); var startButton = new Button(this, 350, 786, Button.TYPE_START); this.startButton = startButton; var resumeButton = new Button(this, 160, 786, Button.TYPE_RESUME); this.resumeButton = resumeButton; if ('ontouchstart' in window) { handler.bind(index, 'touchstart', startButton, this.onStartButtonClick, this); handler.bind(index, 'touchstart', resumeButton, this.onResumeButtonClick, this); } else { handler.bind(index, 'click', startButton, this.onStartButtonClick, this); handler.bind(index, 'click', resumeButton, this.onResumeButtonClick, this); } }
  32. SpecPage.prototype = { constuctor: this, onResize: function () { this.scaleX = this.canvas.width / this.width; this.scaleY = this.canvas.height / this.height; this.game.eventHandler.setScales(1 / this.scaleX, 1 / this.scaleY, this.pageIndex); }, drawButton: function (ctx) { this.startButton.draw(ctx); this.resumeButton.draw(ctx); }, animate: function (timestamp) { var ctx = this.ctx; ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.save(); ctx.scale(this.scaleX, this.scaleY); this.drawButton(ctx); ctx.restore(); }, onStartButtonClick: function (evt) { this.game.startGame(); }, onResumeButtonClick: function (evt) { var game = this.game; game.switchPage(game.PAGE_MAIN); }, onPageChange: function () { var ctx = this.ctx; ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.save(); ctx.scale(this.scaleX, this.scaleY); this.drawButton(ctx); ctx.restore(); } }
  33. function GamePage(game) { this.pageName = 'GamePage'; this.game = game; this.canvas = game.canvas; this.ctx = game.canvas.getContext('2d'); var resources = game.resources; this.offsetY = 80; var bgImg = new Sprite(resources.gameBg, 640, 960, 0, 0); this.bgImg = bgImg; this.width = bgImg.width; this.height = bgImg.height; this.scaleX = this.canvas.width / this.width; this.scaleY = this.canvas.height / this.height; this.pageIndex = game.PAGE_GAME; var handler = game.eventHandler; var index = this.pageIndex; handler.setScales(1 / this.scaleX, 1 / this.scaleY, index); var hitBar = new HitBar(this); hitBar.setPosition((this.width - hitBar.width) / 2, hitBar.height / 2); this.hitBar = hitBar; this.bodyTop = hitBar.height / 2 + hitBar.height; var couple = new Couple(this); couple.setPosition((this.width - couple.width) / 2, this.height - couple.height); this.couple = couple; var scoreBar = new ScoreBar(this); scoreBar.setPosition(0, this.height - scoreBar.height - this.offsetY); this.scoreBar = scoreBar; var exitButton = new Button(this, 0, 0, Button.TYPE_EXIT); exitButton.setPosition(this.width - exitButton.width, this.height - exitButton.height - this.offsetY); this.exitButton = exitButton; var tipImg = new Sprite(resources.tips, 500, 198, 0, 0, 0, 2); tipImg.setPosition((this.width - tipImg.width) / 2, tipImg.height); this.tipImg = tipImg; var lFontImg = new Sprite(resources.spritesheet, 46, 44, 360, 252, 0, 10); lFontImg.setPosition((this.width - lFontImg.width) / 2, tipImg.height); this.lFontImg = lFontImg; var combo = new Combo(this, 0, 0); combo.setPosition(this.width - combo.width, this.height - couple.height - this.offsetY); this.combo = combo; if ('ontouchstart' in window) { handler.bind(index, 'touchstart', exitButton, this.onExitButtonClick, this); handler.bind(index, 'touchstart', couple, this.hit, this); } else { handler.bind(index, 'click', exitButton, this.onExitButtonClick, this); handler.bind(index, 'click', couple, this.hit, this); } }
  34. GamePage.prototype = {
  35. constructor: this, onResize: function () { this.scaleX = this.canvas.width / this.width; this.scaleY = this.canvas.height / this.height; this.game.eventHandler.setScales(1 / this.scaleX, 1 / this.scaleY, this.pageIndex); }, reset: function () { var date = new Date(), ctx = this.ctx, timestamp = date.getTime(); this.hitBar.reset(ctx, timestamp); this.couple.reset(ctx, timestamp); }, drawStartBox: function (ctx) { this.bgImg.draw(ctx); }, drawButton: function (ctx) { this.exitButton.draw(ctx); }, drawCountdown: function (ctx, count) { var lFontImg = this.lFontImg; lFontImg.toFrame(count); lFontImg.draw(ctx) }, hit: function () { var game = this.game; if (!game.over) { var date = new Date(); if (date.getTime() >= game.startTime) { this.hitBar.onHit(); if (game.hitScore > 0) { game.resources.sound.play(); this.couple.onHit(); var ctx = this.ctx, self = this; this.drawBody(); game.lastHitTime = date.getTime(); } } } }, drawBody: function (ctx) { var ctx = this.ctx; ctx.save(); ctx.scale(this.scaleX, this.scaleY); ctx.clearRect(0, this.bodyTop, this.width, this.height); this.couple.draw(ctx); this.scoreBar.draw(ctx); this.exitButton.draw(ctx); this.combo.draw(ctx); ctx.restore(); }, animate: function (timestamp) {
  36. var game = this.game, temp = 0, ctx = this.ctx; if (timestamp < game.startTime) { temp = Math.round((game.startTime - timestamp) / 1000); timestamp = game.startDelay; } else if (game.endTime > game.startTime) { timestamp = game.endTime; }
  37. if (game.lastHitTime && timestamp > game.lastHitTime + game.hitDuration) { this.couple.hasHit = false; this.drawBody(ctx); game.lastHitTime = null; }
  38. ctx.save(); ctx.scale(this.scaleX, this.scaleY); var bounds = this.hitBar.getBounds(); ctx.clearRect(bounds.left, bounds.top, bounds.right, bounds.bottom); this.hitBar.animate(ctx, timestamp); this.ctx.restore(); if (timestamp === game.startDelay) { this.drawBody(ctx); if (temp === 0) { ctx.save(); ctx.scale(this.scaleX, this.scaleY); this.tipImg.toFrame(1); this.tipImg.draw(ctx); ctx.restore(); } else { ctx.save(); ctx.scale(this.scaleX, this.scaleY); this.drawCountdown(ctx, temp); ctx.restore(); } } else if (timestamp === game.endTime) { this.drawBody(ctx); ctx.save(); ctx.scale(this.scaleX, this.scaleY); this.tipImg.toFrame(0); this.tipImg.draw(ctx); ctx.restore(); }
  39. }, onExitButtonClick: function (evt) {
  40. var game = this.game; if (!game.over) { game.stopGame(false); }
  41. game.switchPage(game.PAGE_MAIN); return false;
  42. }, onPageChange: function () { var ctx = this.ctx, timer = this.game.timer; ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.save(); ctx.scale(this.scaleX, this.scaleY); this.hitBar.animate(ctx, timer.getTime()); this.ctx.restore(); this.drawBody(ctx); }
  43. }
  44. function Button(container, x, y, type) { this.x = (x) ? x : 0; this.y = (y) ? y : 0; this.container = container; this.game = container.game; var resources = this.game.resources; this.buttonImg = new Sprite(resources.spritesheet2, 210, 90, type * 210, 0); this.selectedImg = new Sprite(resources.spritesheet2, 210, 90, type * 210, 90); this.width = this.buttonImg.width; this.height = this.buttonImg.height; this.isSelected = false; }
  45. Button.prototype = {
  46. constructor: this, setPosition: function (x, y) { this.x = x; this.y = y; }, getSize: function () { return { width: this.width, height: this.height }; }, getBounds: function () { return new Bounds(this.x, this.y, this.x + this.width, this.y + this.height); }, draw: function (ctx) {
  47. ctx.save(); ctx.translate(this.x, this.y); if (this.isSelected) { this.selectedImg.draw(ctx); } else { this.buttonImg.draw(ctx); }
  48. ctx.restore();
  49. }
  50. }
  51. Button.TYPE_START = 0; Button.TYPE_SPEC = 1; Button.TYPE_EXIT = 2; Button.TYPE_RESUME = 3; function Combo(container, x, y) { this.x = (x) ? x : 0; this.y = (y) ? y : 0; this.container = container; this.game = container.game; var resources = this.game.resources; this.lFontImg = new Sprite(resources.spritesheet, 46, 44, 360, 252, 0, 10); this.comboImg = new Sprite(resources.spritesheet2, 86, 44, 474, 208); this.width = this.lFontImg.width * 3 + this.comboImg.width; this.height = Math.max(this.lFontImg.height, this.comboImg.height); }
  52. Combo.prototype = {
  53. constructor: this, setPosition: function (x, y) { this.x = x; this.y = y; }, getSize: function () { return { width: this.width, height: this.height }; }, getBounds: function () { return new Bounds(this.x, this.y, this.x + this.width, this.y + this.height); }, draw: function (ctx) {
  54. var hitNum = this.game.hitNum.toString().split(''), fontImg = this.lFontImg, comboImg = this.comboImg; if (hitNum < 2) { return; }
  55. ctx.save(); ctx.translate(this.x, this.y); for (var len = hitNum.length, i = 0; i < len; i++) { fontImg.toFrame(parseInt(hitNum[i])); x = this.width - (len - i) * fontImg.width - comboImg.width; fontImg.setPosition(x, 0); fontImg.draw(ctx); }
  56. comboImg.setPosition(this.width - comboImg.width, 0); comboImg.draw(ctx); ctx.restore();
  57. }
  58. }
  59. function Couple(container, x, y) { this.x = (x) ? x : 0; this.y = (y) ? y : 0; this.container = container; this.game = container.game; var resources = this.game.resources; this.couple1Img = new Sprite(resources.couple1, 578, 600, 0, 0); this.couple2Img = new Sprite(resources.couple2, 578, 600, 0, 0); this.couple3Img = new Sprite(resources.couple3, 578, 600, 0, 0); this.couple4Img = new Sprite(resources.couple4, 578, 600, 0, 0); this.defaultImg = this.couple1Img; this.hitImg = new Sprite(resources.couple7, 589, 679, 0, 0); this.endImg = new Sprite(resources.couple8, 629, 600, 0, 0); this.width = this.couple1Img.width; this.height = this.couple1Img.height; this.tipsBoxImg = new Sprite(resources.spritesheet, 364, 264, 584, 294); this.tipsBoxImg.setPosition((this.width - this.tipsBoxImg.width) / 2, -this.container.offsetY); var tipX = this.tipsBoxImg.posX + 30, tipY = this.tipsBoxImg.posY + 50; this.greatImg = new Sprite(resources.spritesheet, 200, 76, 750, 92); this.greatImg.setPosition(tipX + 30, tipY); this.perfetImg = new Sprite(resources.spritesheet, 330, 90, 426, 158); this.perfetImg.setPosition(tipX, tipY); this.plusImg = new Sprite(resources.spritesheet, 34, 34, 316, 262); this.plusImg.setPosition(tipX + 50, tipY + 100); this.lFontImg = new Sprite(resources.spritesheet, 46, 44, 360, 252, 0, 10); this.lFontImg.setPosition(tipX, tipY + 100); this.hasHit = false; }
  60. Couple.prototype = {
  61. constructor: this, setPosition: function (x, y) { this.x = x; this.y = y; }, getSize: function () { return { width: this.width, height: this.height }; }, getBounds: function () { return new Bounds(this.x, this.y, this.x + this.width, this.y + this.height); }, reset: function (ctx, timestamp) { this.hasHit = false; this.defaultImg = this.couple1Img; }, onHit: function () { this.hasHit = true; var hitNum = this.game.hitNum; if (hitNum > 20) { this.defaultImg = this.couple4Img; } else if (hitNum > 5) { this.defaultImg = this.couple3Img; } else if (hitNum > 0) { this.defaultImg = this.couple2Img; } }, drawTips: function (ctx) {
  62. var hitScore = this.game.hitScore, tipsImg = this.tipsImg; this.tipsBoxImg.draw(ctx); switch (hitScore) { case 50: this.greatImg.draw(ctx); break; case 100: this.perfetImg.draw(ctx); break; default: break; }
  63. this.drawHitScore(ctx);
  64. }, drawHitScore: function (ctx) { var hitScore = this.game.hitScore.toString().split(''); var lFontImg = this.lFontImg, plusImg = this.plusImg, x = 0, y = lFontImg.posY; plusImg.draw(ctx); for (var len = hitScore.length, i = 0; i < len; i++) { lFontImg.toFrame(parseInt(hitScore[i])); x = (plusImg.posX + plusImg.width) + i * lFontImg.width; lFontImg.setPosition(x, y); lFontImg.draw(ctx); } }, draw: function (ctx) {
  65. ctx.save(); ctx.translate(this.x, this.y); if (this.game.over) { this.endImg.draw(ctx); } else { if (this.hasHit) { this.hitImg.draw(ctx); this.drawTips(ctx); } else { this.defaultImg.draw(ctx); } }
  66. ctx.restore();
  67. }
  68. }
  69. function HitBar(container, x, y) { this.x = (x) ? x : 0; this.y = (y) ? y : 0; this.container = container; this.game = container.game; this.duration = this.game.originDuration;; this.frameNum = this.game.hitBarFrameNum; this.hitShadowAlpha = 1.0; this.hitShadowDuration = 1000; var resources = this.game.resources; this.barImg = new Sprite(resources.spritesheet, 584, 98, 0, 324); this.barImg.setPosition(this.barImg.offsetX, 0); var handImg = new Sprite(resources.spritesheet, 64, 70, 22, 422); handImg.setPosition(handImg.offsetX, (this.barImg.height - handImg.height) / 2); this.handImg = new TrackSprite(handImg, this.duration, this.calTrack(handImg), { scope: this, func: this.round }); this.hitShadowImg = new Sprite(resources.spritesheet, 64, 70, 22, 422); this.hitShadowImg.setPosition(handImg.posX, handImg.posY); this.targetLImg = new Sprite(resources.spritesheet, 30, 98, 224, 324); this.targetLImg.setPosition(this.targetLImg.offsetX, 0); this.targetRImg = new Sprite(resources.spritesheet, 30, 98, 354, 324); this.targetRImg.setPosition(this.targetRImg.offsetX, 0); this.goodArea = [this.targetLImg.offsetX, this.targetRImg.offsetX + this.targetRImg.width]; this.perfetArea = [this.targetLImg.offsetX + this.targetLImg.width, this.targetRImg.offsetX]; this.width = this.barImg.width; this.height = this.barImg.height; this.hasHit = false; this.showShadow = false; this.hitX = 0; }
  70. HitBar.prototype = {
  71. constructor: this, setPosition: function (x, y) { this.x = x; this.y = y; }, getSize: function () { return { width: this.width, height: this.height }; }, getBounds: function () { return new Bounds(this.x, this.y, this.x + this.width, this.y + this.height); }, setDuration: function (duration) { duration = (duration > 1) ? duration : 1; this.duration = duration; this.handImg.duration = duration; }, reset: function (ctx, timestamp) { this.setDuration(this.game.originDuration); this.handImg.currentFrame = 0; this.hasHit = false; this.showShadow = false; this.animate(ctx, timestamp); }, onHit: function () {
  72. var game = this.game; this.hasHit = true; this.showShadow = true; this.hitX = this.handImg.getPosition().x; this.hitShadowAlpha = 1.0; var hitScore = 0; var hitLPosX = this.handImg.getPosition().x, hitRPosX = hitLPosX + this.handImg.getSize().width, hitCPosX = (hitLPosX + hitRPosX) / 2; if (!(hitCPosX < this.goodArea[0] || hitCPosX > this.goodArea[1])) { hitScore = 50; if (hitLPosX > this.perfetArea[0] && hitRPosX < this.perfetArea[1]) { hitScore = 100; } }
  73. game.score += hitScore; game.hitScore = hitScore; if (hitScore === 0) { game.stopGame(true); }
  74. game.hitNum++; if (game.hitNum % game.levelUpHitNum === 0) { var newDuration = Math.round(this.duration - game.levelUpDelta * (1 + Math.random())); this.setDuration(newDuration); this.handImg.duration = this.duration; }
  75. }, animate: function (ctx, timestamp) {
  76. ctx.save(); ctx.translate(this.x, this.y); this.barImg.draw(ctx); this.handImg.animate(ctx, timestamp); this.targetLImg.draw(ctx); this.targetRImg.draw(ctx); if (this.showShadow) {
  77. if (this.hitShadowAlpha === 1.0) { this.hitShadowImg.setPosition(this.hitX, this.hitShadowImg.posY); var date = new Date(); this.htime = date.getTime() + (this.hitShadowDuration / 10); this.hitShadowAlpha -= 0.1; }
  78. if (timestamp >= this.htime) { var date = new Date(); this.htime = date.getTime() + (this.hitShadowDuration / 10); this.hitShadowAlpha -= 0.1; }
  79. ctx.save(); if (this.hitShadowAlpha > 0) { ctx.globalAlpha = this.hitShadowAlpha; this.hitShadowImg.draw(ctx); } else { this.showShadow = false; this.game.hitShadowAlpha = 1.0; }
  80. ctx.restore();
  81. }
  82. ctx.restore();
  83. }, calTrack: function (handImg) {
  84. var barImg = this.barImg, disX = barImg.width - handImg.offsetX - handImg.width, frameNum = this.frameNum, deltaX = disX / frameNum, posX = handImg.offsetX, posY = (barImg.height - handImg.height) / 2, track = []; for (var i = 0; i < frameNum; i++) { track.push({ x: posX + i * deltaX, y: posY }); }
  85. for (var j = frameNum - 1; j >= 0; j--) { track.push(track[j]); }
  86. return track;
  87. }, isMissed: function () {
  88. var result = false; if (!this.hasHit) { var handImg = this.handImg, handLPosX = handImg.getPosition().x, handRPosX = handLPosX + handImg.getSize().width, goodArea = this.goodArea; if (handImg.currentFrame >= this.frameNum) { result = handRPosX < goodArea[0]; } else { result = handLPosX > goodArea[1]; } }
  89. return result;
  90. }, round: function () {
  91. if (this.handImg.currentFrame % this.frameNum === 0) { this.hasHit = false; }
  92. if (this.isMissed()) { this.game.over || this.game.stopGame(true); }
  93. }
  94. }
  95. function ScoreBar(container, x, y) { this.x = (x) ? x : 0; this.y = (y) ? y : 0; this.container = container; this.game = container.game; var resources = this.game.resources; this.barImg = new Sprite(resources.spritesheet2, 430, 76, 20, 192); this.mFontImg = new Sprite(resources.spritesheet, 27, 32, 28, 258, 0, 10); this.scoreBoxRect = new Bounds(204, 20, 366, 58); this.width = this.barImg.width; this.height = this.barImg.height; }
  96. ScoreBar.prototype = { constructor: this, setPosition: function (x, y) { this.x = x; this.y = y; }, getSize: function () { return { width: this.width, height: this.height }; }, getBounds: function () { return new Bounds(this.x, this.y, this.x + this.width, this.y + this.height); }, drawScore: function (ctx) { var score = this.game.score.toString().split(''); var fontImg = this.mFontImg, rect = this.scoreBoxRect, x = 0, y = ((rect.bottom - rect.top - fontImg.height) / 2) + rect.top; for (var len = score.length, i = 0; i < len; i++) { fontImg.toFrame(parseInt(score[i])); x = rect.right - ((len - i) * fontImg.width); fontImg.setPosition(x, y); fontImg.draw(ctx); } }, draw: function (ctx) { ctx.save(); ctx.translate(this.x, this.y); this.barImg.draw(ctx); this.drawScore(ctx); ctx.restore(); } }
  97. function Bounds(left, top, right, bottom) { if (arguments.length === 1) { var bounds = arguments[0]; if (bounds instanceof Array) { this.left = bounds[0]; this.top = bounds[1]; this.right = bounds[2]; this.bottom = bounds[3]; } else if (bounds instanceof Object) { this.left = bounds.left; this.top = bounds.top; this.right = bounds.right; this.bottom = bounds.bottom; } } else { this.left = left; this.top = top; this.right = right; this.bottom = bottom; } }
  98. Bounds.prototype = {
  99. constructor: this, getWidth: function () { return this.right - this.left; }, getHeight: function () { return this.bottom - this.top; }, contains: function (xy, inclusive) {
  100. var result = false, x = xy.x, y = xy.y; if (inclusive) { result = x >= this.left && x <= this.right && y >= this.top && y <= this.bottom; } else { result = x > this.left && x < this.right && y > this.top && y < this.bottom; }
  101. return result;
  102. }
  103. }
  104. function EventDispatcher() { this.recieversMap = {}; this.scaleX = 1; this.scaleY = 1; }
  105. EventDispatcher.prototype = {
  106. constructor: this, setScales: function (scaleX, scaleY) { this.scaleX = scaleX; this.scaleY = scaleY; }, addReciever: function (type, target, func, scope) {
  107. var recieversMap = this.recieversMap, scope = (scope) ? scope : target; if (!(type in recieversMap)) { recieversMap[type] = []; }
  108. recieversMap[type].push({ target: target, func: func, scope: scope });
  109. }, dispatch: function (type, evt) { if (type in this.recieversMap) { var recievers = this.recieversMap[type], reciever; for (var i = 0, ln = recievers.length; i < ln; i++) { reciever = recievers[i]; if (this.onTarget(reciever.target, evt)) { if (reciever.func.apply(reciever.scope, [evt]) === false) { break }; } } } }, onTarget: function (target, evt) {
  110. var result = false, bounds = null, x = evt.offsetX * this.scaleX, y = evt.offsetY * this.scaleY; if (target.getBounds) { bounds = target.getBounds(); }
  111. if (bounds instanceof Bounds) { result = bounds.contains({ x: x, y: y }); }
  112. return result;
  113. }
  114. }
  115. function EventHandler(target) { this.target = target; this.dispatchers = []; this.dispatcherIndex = -1; this.EventTypes = {}; }
  116. EventHandler.prototype = {
  117. constructor: this, setScales: function (scaleX, scaleY, index) {
  118. index = (index) ? index : this.dispatcherIndex; var dispatchers = this.dispatchers, dispatcher = dispatchers[index]; if (!dispatcher) { dispatcher = new EventDispatcher(); dispatchers[index] = dispatcher; }
  119. dispatcher.setScales(scaleX, scaleY);
  120. }, addEventType: function (type) { var target = this.target; if (target) { var handler = this; target.addEventListener(type, function (evt) { evt.preventDefault(); evt.stopPropagation(); handler.fire(type, evt); return false; }, false); this.EventTypes[type] = true; } }, bind: function (index, type, target, func, scope) {
  121. if (!(type in this.EventTypes)) { this.addEventType(type); }
  122. var dispatchers = this.dispatchers, dispatcher = dispatchers[index]; if (!dispatcher) { dispatcher = new EventDispatcher(); dispatchers[index] = dispatcher; }
  123. dispatcher.addReciever(type, target, func, scope);
  124. }, fire: function (type, evt) { if (this.target) { this.onTarget(evt); var dispatcher = this.dispatchers[this.dispatcherIndex]; if (dispatcher instanceof EventDispatcher) { dispatcher.dispatch(type, evt); } } }, getTargetBounds: function () {
  125. var el = this.target; var offsetLeft = el.offsetLeft, offsetTop = el.offsetTop, offsetHeight = el.offsetHeight, offsetWidth = el.offsetWidth; while (el = el.offsetParent) { offsetTop += el.offsetTop; offsetLeft += el.offsetLeft; }
  126. return new Bounds(offsetLeft, offsetTop, offsetWidth, offsetHeight);
  127. }, onTarget: function (evt) {
  128. var bounds = this.getTargetBounds(), offsetX = 0, offsetY = 0, touches = evt.changedTouches; if (!evt.offsetX) {
  129. if (touches) { offsetX = touches[0].pageX - bounds.left; offsetY = touches[0].pageY - bounds.top; } else if (evt.clientX) { offsetX = evt.clientX - bounds.left; offsetY = evt.clientY - bounds.top; }
  130. evt.offsetX = offsetX; evt.offsetY = offsetY;
  131. }
  132. }
  133. }
  134. function Sprite(spritesheet, width, height, offsetX, offsetY, duration, frames, onFrameChanged) {
  135. if (spritesheet instanceof Image) { this.spritesheet = spritesheet; } else { this.spritesheet = new Image(); this.spritesheet.src = spritesheet; }
  136. this.offsetX = offsetX; this.offsetY = offsetY; this.originX = offsetX; this.originY = offsetY; this.width = width; this.height = height; this.framesIndexes = null; this.frameNum = 1; if (frames instanceof Array && frames.length > 0) { this.frameNum = frames.length; this.frameIndexes = frames; } else if (frames > 0) { this.frameNum = frames; }
  137. this.currentFrame = 0; this.duration = duration; this.posX = 0; this.posY = 0; this.show = true; this.scale = 1; var date = new Date(); if (this.frameNum > 0 && this.duration > 0) { this.ftime = date.getTime() + (this.duration / this.frameNum); } else { this.ftime = 0; }
  138. this.onFrameChanged = onFrameChanged;
  139. }
  140. Sprite.prototype = {
  141. constructor: this, getSize: function () { return { width: this.width, height: this.height }; }, getOffset: function () { return { x: this.offsetX, y: this.offsetY }; }, getPosition: function () { return { x: this.posX, y: this.posY }; }, setPosition: function (x, y) { this.posX = x; this.posY = y; }, animate: function (ctx, timestamp) {
  142. if (timestamp >= this.ftime) { this.nextFrame(); }
  143. this.draw(ctx);
  144. }, nextFrame: function () {
  145. var steps = (arguments[0]) ? arguments[0] : 1; if (this.frameNum > 0 && this.duration > 0) { var date = new Date(); this.ftime = date.getTime() + (this.duration / this.frameNum); } else { this.ftime = 0; }
  146. if (this.frameIndexes) { this.offsetX = this.frameIndexes[this.currentFrame] * this.width; } else { this.offsetX = this.originX + this.currentFrame * this.width; }
  147. this.currentFrame = (this.currentFrame + steps) % this.frameNum; this.fire();
  148. }, toFrame: function (n) {
  149. this.currentFrame = n % this.frameNum; if (this.frameIndexes) { this.offsetX = this.frameIndexes[this.currentFrame] * this.width; } else { this.offsetX = this.originX + this.currentFrame * this.width; }
  150. this.fire();
  151. }, draw: function (ctx) { if (this.show) { ctx.drawImage(this.spritesheet, this.offsetX, this.offsetY, this.width, this.height, this.posX, this.posY, this.width * this.scale, this.height * this.scale); } }, fire: function () { if (this.onFrameChanged) { this.onFrameChanged.func.apply(this.onFrameChanged.scope); } }
  152. }
  153. function Timer() { this.date = new Date(); this.pauseDate = null; }
  154. Timer.prototype = { constructor: this, update: function () { if (this.pauseDate) { this.date = this.pauseDate; } else { this.date = new Date(); } }, getTime: function () { return this.date.getTime(); }, getSeconds: function () { return this.date.getTime() / 1000; }, pause: function () { this.pauseDate = new Date(); }, resume: function () { this.pauseDate = null; this.update(); } }
  155. function TrackSprite(sprite, duration, track, onFrameChanged) {
  156. this.sprite = sprite; this.originX = sprite.posX; this.originY = sprite.posY; this.duration = duration; if (track instanceof Array && track.length > 0) { this.track = track; this.frameNum = track.length; } else if (track instanceof Object) { this.disX = track.disX; this.disY = track.disY; this.frameNum = track.frameNum; this.deltaX = Math.floor(this.disX / this.frameNum); this.deltaY = Math.floor(this.disY / this.frameNum); this.currentFrame = 0; }
  157. var date = new Date(); if (this.frameNum > 0 && this.duration > 0) { this.ftime = date.getTime() + (this.duration / this.frameNum); } else { this.ftime = 0; }
  158. this.onFrameChanged = onFrameChanged;
  159. }
  160. TrackSprite.prototype = {
  161. constructor: this, getSize: function () { return this.sprite.getSize(); }, getOffset: function () { return this.sprite.getOffset(); }, getPosition: function () { return this.sprite.getPosition(); }, animate: function (ctx, timestamp) {
  162. if (timestamp >= this.ftime) { this.nextFrame(); }
  163. this.sprite.animate(ctx, timestamp);
  164. }, nextFrame: function () {
  165. var steps = (arguments[0]) ? arguments[0] : 1; var sprite = this.sprite; var currentFrame = this.currentFrame; if (this.frameNum > 0 && this.duration > 0) { var date = new Date(); this.ftime = date.getTime() + (this.duration / this.frameNum); } else { this.ftime = 0; }
  166. var newX = sprite.posX; var newY = sprite.posY; if (this.track) { newX = this.track[currentFrame].x; newY = this.track[currentFrame].y; } else { newX = (this.disX === 0) ? newX : (this.originX + this.currentFrame * this.deltaX) % this.disX; newY = (this.disY === 0) ? newY : (this.originY + this.currentFrame * this.deltaY) % this.disY; }
  167. this.sprite.setPosition(newX, newY); this.currentFrame = (this.currentFrame + steps) % this.frameNum; this.fire();
  168. }, fire: function () { if (this.onFrameChanged) { this.onFrameChanged.func.apply(this.onFrameChanged.scope); } }
  169. }