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'; } Slap.prototype = { loadResources: function () { var self = this; var loading = new Image(); loading.onload = function () { 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(); } } for (var i in resources) { if (resources.hasOwnProperty(i)) { resources[i].onload = onload; } } 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'; } resources.sound.load(); } loading.src = 'load.png'; }, 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 () { 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; } if ((/iphone/).test(this.ua)) { height += 60; } else if ((/android/).test(this.ua)) { height += 10; } 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()); }, submitScore: function () { var score = this.score; if (score > 0) { var tt = ""; if (score < 1000) { tt = "用力用力,抽得太少了!!"; } else if (score > 1000 && score < 2500) { tt = "多ktn?"; } dp_share(score, this.hitNum); } }, 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) { this.timer.pause(); var date = new Date(); this.endTime = date.getTime(); this.over = true; if (submit) { this.submitScore(); } var self = this; setTimeout(function () { self.switchPage(self.PAGE_MAIN); }, 1500); }, switchPage: function (index) { 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; } this.canvas.setAttribute('class', page.pageName); this.currentPage = page; this.switchEventDispatcher(page.pageIndex); page.onPageChange(); page.animate(timer.getTime()); timer.pause(); }, switchEventDispatcher: function (index) { this.eventHandler.dispatcherIndex = index; } } 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); } } 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(); } } 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); } } 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(); } } 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); } } GamePage.prototype = { 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) { 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; } if (game.lastHitTime && timestamp > game.lastHitTime + game.hitDuration) { this.couple.hasHit = false; this.drawBody(ctx); game.lastHitTime = null; } 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(); } }, onExitButtonClick: function (evt) { var game = this.game; if (!game.over) { game.stopGame(false); } game.switchPage(game.PAGE_MAIN); return false; }, 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); } } 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; } Button.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); }, draw: function (ctx) { ctx.save(); ctx.translate(this.x, this.y); if (this.isSelected) { this.selectedImg.draw(ctx); } else { this.buttonImg.draw(ctx); } ctx.restore(); } } 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); } Combo.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); }, draw: function (ctx) { var hitNum = this.game.hitNum.toString().split(''), fontImg = this.lFontImg, comboImg = this.comboImg; if (hitNum < 2) { return; } 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); } comboImg.setPosition(this.width - comboImg.width, 0); comboImg.draw(ctx); ctx.restore(); } } 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; } Couple.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); }, 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) { 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; } this.drawHitScore(ctx); }, 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) { 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); } } ctx.restore(); } } 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; } HitBar.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); }, 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 () { 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; } } game.score += hitScore; game.hitScore = hitScore; if (hitScore === 0) { game.stopGame(true); } 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; } }, animate: function (ctx, timestamp) { 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) { 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; } if (timestamp >= this.htime) { var date = new Date(); this.htime = date.getTime() + (this.hitShadowDuration / 10); this.hitShadowAlpha -= 0.1; } ctx.save(); if (this.hitShadowAlpha > 0) { ctx.globalAlpha = this.hitShadowAlpha; this.hitShadowImg.draw(ctx); } else { this.showShadow = false; this.game.hitShadowAlpha = 1.0; } ctx.restore(); } ctx.restore(); }, calTrack: function (handImg) { 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 }); } for (var j = frameNum - 1; j >= 0; j--) { track.push(track[j]); } return track; }, isMissed: function () { 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]; } } return result; }, round: function () { if (this.handImg.currentFrame % this.frameNum === 0) { this.hasHit = false; } if (this.isMissed()) { this.game.over || this.game.stopGame(true); } } } 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; } 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(); } } 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; } } Bounds.prototype = { constructor: this, getWidth: function () { return this.right - this.left; }, getHeight: function () { return this.bottom - this.top; }, contains: function (xy, inclusive) { 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; } return result; } } function EventDispatcher() { this.recieversMap = {}; this.scaleX = 1; this.scaleY = 1; } EventDispatcher.prototype = { constructor: this, setScales: function (scaleX, scaleY) { this.scaleX = scaleX; this.scaleY = scaleY; }, addReciever: function (type, target, func, scope) { var recieversMap = this.recieversMap, scope = (scope) ? scope : target; if (!(type in recieversMap)) { recieversMap[type] = []; } recieversMap[type].push({ target: target, func: func, scope: scope }); }, 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) { var result = false, bounds = null, x = evt.offsetX * this.scaleX, y = evt.offsetY * this.scaleY; if (target.getBounds) { bounds = target.getBounds(); } if (bounds instanceof Bounds) { result = bounds.contains({ x: x, y: y }); } return result; } } function EventHandler(target) { this.target = target; this.dispatchers = []; this.dispatcherIndex = -1; this.EventTypes = {}; } EventHandler.prototype = { constructor: this, setScales: function (scaleX, scaleY, index) { index = (index) ? index : this.dispatcherIndex; var dispatchers = this.dispatchers, dispatcher = dispatchers[index]; if (!dispatcher) { dispatcher = new EventDispatcher(); dispatchers[index] = dispatcher; } dispatcher.setScales(scaleX, scaleY); }, 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) { if (!(type in this.EventTypes)) { this.addEventType(type); } var dispatchers = this.dispatchers, dispatcher = dispatchers[index]; if (!dispatcher) { dispatcher = new EventDispatcher(); dispatchers[index] = dispatcher; } dispatcher.addReciever(type, target, func, scope); }, 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 () { 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; } return new Bounds(offsetLeft, offsetTop, offsetWidth, offsetHeight); }, onTarget: function (evt) { var bounds = this.getTargetBounds(), offsetX = 0, offsetY = 0, touches = evt.changedTouches; if (!evt.offsetX) { 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; } evt.offsetX = offsetX; evt.offsetY = offsetY; } } } function Sprite(spritesheet, width, height, offsetX, offsetY, duration, frames, onFrameChanged) { if (spritesheet instanceof Image) { this.spritesheet = spritesheet; } else { this.spritesheet = new Image(); this.spritesheet.src = spritesheet; } 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; } 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; } this.onFrameChanged = onFrameChanged; } Sprite.prototype = { 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) { if (timestamp >= this.ftime) { this.nextFrame(); } this.draw(ctx); }, nextFrame: function () { 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; } if (this.frameIndexes) { this.offsetX = this.frameIndexes[this.currentFrame] * this.width; } else { this.offsetX = this.originX + this.currentFrame * this.width; } this.currentFrame = (this.currentFrame + steps) % this.frameNum; this.fire(); }, toFrame: function (n) { 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; } this.fire(); }, 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); } } } function Timer() { this.date = new Date(); this.pauseDate = null; } 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(); } } function TrackSprite(sprite, duration, track, onFrameChanged) { 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; } var date = new Date(); if (this.frameNum > 0 && this.duration > 0) { this.ftime = date.getTime() + (this.duration / this.frameNum); } else { this.ftime = 0; } this.onFrameChanged = onFrameChanged; } TrackSprite.prototype = { constructor: this, getSize: function () { return this.sprite.getSize(); }, getOffset: function () { return this.sprite.getOffset(); }, getPosition: function () { return this.sprite.getPosition(); }, animate: function (ctx, timestamp) { if (timestamp >= this.ftime) { this.nextFrame(); } this.sprite.animate(ctx, timestamp); }, nextFrame: function () { 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; } 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; } this.sprite.setPosition(newX, newY); this.currentFrame = (this.currentFrame + steps) % this.frameNum; this.fire(); }, fire: function () { if (this.onFrameChanged) { this.onFrameChanged.func.apply(this.onFrameChanged.scope); } } }