1 distancemeter.dimensions = { 2 WIDTH: 10, //每个字符的宽度 3 HEIGHT: 13, //每个字符的高 4 DEST_WIDTH: 11 //间隙 5 }; 6 DistanceMeter.config = { 7 // 初始时记录的分数上限为5位数,即99999 8 MAX_DISTANCE_UNITS: 5, 9 10 // 每隔100米距离记录器的数字出现闪动特效 11 ACHIEVEMENT_DISTANCE: 100, 12 13 // 将移动距离转化为合理的数值所用的转化系数 14 COEFFICIENT: 0.025, 15 16 // 每250ms闪动一次 17 FLASH_DURATION: 1000 / 4, 18 19 // 闪动次数 20 FLASH_ITERATIONS: 3 21 }; 22 /** 23 * 距离记录器 24 * @param {HTMLCanvasElement} canvas 25 * @param {Object} spritePos 雪碧图上的坐标. 26 * @param {number} canvaswidth 27 * @constructor 28 */ 29 function DistanceMeter(canvas, spritePos, canvasWidth) { 30 this.canvas = canvas; 31 this.canvasCtx = canvas.getContext('2d'); 32 this.image = imgSprite; 33 this.spritePos = spritePos; 34 //相对坐标 35 this.x = 0; 36 this.y = 5; 37 38 //最大分数 39 this.maxScore = 0; 40 //高分榜 41 this.highScore = 0; 42 43 this.digits = []; 44 //是否进行闪动特效 45 this.acheivement = false; 46 this.defaultString = ''; 47 //闪动特效计时器 48 this.flashTimer = 0; 49 //闪动计数器 50 this.flashIterations = 0; 51 this.invertTrigger = false; 52 53 this.config = DistanceMeter.config; 54 //最大记录为万位数 55 this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS; 56 this.init(canvasWidth); 57 } 58 59 DistanceMeter.prototype = { 60 /** 61 * 初始化距离记录器为00000 62 * @param canvasWidth canvas的宽度 63 */ 64 init: function(canvasWidth) { 65 var maxDistanceStr = ''; 66 67 this.calcXPos(canvasWidth); 68 for (var i = 0; i < this.maxScoreUnits; i++) { 69 this.draw(i, 0); 70 this.defaultString += '0'; 71 maxDistanceStr += '9'; 72 } 73 74 //99999 75 this.maxScore = parseInt(maxDistanceStr); 76 }, 77 /** 78 * 计算出xPos 79 * @param canvasWidth 80 */ 81 calcXPos: function(canvasWidth) { 82 this.x = canvasWidth - (DistanceMeter.dimensions.DEST_WIDTH * (this.maxScoreUnits + 1)); 83 }, 84 draw: function(digitPos, value, opt_highScore) { 85 var sourceWidth = DistanceMeter.dimensions.WIDTH; 86 var sourceHeight = DistanceMeter.dimensions.HEIGHT; 87 var sourceX = DistanceMeter.dimensions.WIDTH * value; 88 var sourceY = 0; 89 90 var targetX = digitPos * DistanceMeter.dimensions.DEST_WIDTH; 91 var targetY = this.y; 92 var targetWidth = DistanceMeter.dimensions.WIDTH; 93 var targetHeight = DistanceMeter.dimensions.HEIGHT; 94 95 sourceX += this.spritePos.x; 96 sourceY += this.spritePos.y; 97 98 this.canvasCtx.save(); 99 100 if (opt_highScore) { 101 // 将最高分放至当前分数的左边 102 var highScoreX = this.x - (this.maxScoreUnits * 2) * DistanceMeter.dimensions.WIDTH; 103 this.canvasCtx.translate(highScoreX, this.y); 104 } else { 105 this.canvasCtx.translate(this.x, this.y); 106 } 107 108 this.canvasCtx.drawImage(this.image, sourceX, sourceY, sourceWidth, sourceHeight, targetX, targetY, targetWidth, targetHeight); 109 110 this.canvasCtx.restore(); 111 }, 112 /** 113 * 将像素距离转化为“真实距离” 114 * @param distance 像素距离 115 * @returns {number} “真实距离” 116 */ 117 getActualDistance: function(distance) { 118 return distance ? Math.round(distance * this.config.COEFFICIENT) : 0; 119 }, 120 /** 121 * 更新距离记录器 122 * @param {number} deltaTime 123 * @param {number} distance 124 * @returns {boolean} 是否播放声音 125 */ 126 update: function(deltaTime, distance) { 127 var paint = true; 128 var playSound = false; 129 130 if (!this.acheivement) { 131 distance = this.getActualDistance(distance); 132 // 分数超过最大分数时增加至十万位999999 133 if (distance > this.maxScore && this.maxScoreUnits === this.config.MAX_DISTANCE_UNITS) { 134 this.maxScoreUnits++; 135 this.maxScore = parseInt(this.maxScore + '9'); 136 } 137 138 if (distance > 0) { 139 // 每100距离开始闪动特效并播放声音 140 if (distance % this.config.ACHIEVEMENT_DISTANCE === 0) { 141 this.acheivement = true; 142 this.flashTimer = 0; 143 playSound = true; 144 } 145 146 // 让数字以0开头 147 var distanceStr = (this.defaultString + distance).substr( - this.maxScoreUnits); 148 this.digits = distanceStr.split(''); 149 } else { 150 this.digits = this.defaultString.split(''); 151 } 152 } else { 153 // 到达目标分数时闪动分数 154 if (this.flashIterations <= this.config.FLASH_ITERATIONS) { 155 this.flashTimer += deltaTime; 156 157 if (this.flashTimer < this.config.FLASH_DURATION) { 158 paint = false; 159 } else if (this.flashTimer > this.config.FLASH_DURATION * 2) { 160 this.flashTimer = 0; 161 this.flashIterations++; 162 } 163 } else { 164 this.acheivement = false; 165 this.flashIterations = 0; 166 this.flashTimer = 0; 167 } 168 } 169 170 // 非闪动时绘制分数 171 if (paint) { 172 for (var i = this.digits.length - 1; i >= 0; i--) { 173 this.draw(i, parseInt(this.digits[i])); 174 } 175 } 176 177 this.drawHighScore(); 178 return playSound; 179 }, 180 //绘制高分榜 181 drawHighScore: function() { 182 this.canvasCtx.save(); 183 this.canvasCtx.globalAlpha = .8; //让字符看起来颜色稍浅 184 for (var i = this.highScore.length - 1; i >= 0; i--) { 185 this.draw(i, parseInt(this.highScore[i], 10), true); 186 } 187 this.canvasCtx.restore(); 188 }, 189 setHighScore: function(distance) { 190 distance = this.getActualDistance(distance); 191 var highScoreStr = (this.defaultString + distance).substr( - this.maxScoreUnits); 192 //10和11分别对应雪碧图中的H、I 193 this.highScore = ['10', '11', ''].concat(highScoreStr.split('')); 194 }, 195 //重置记录器为00000 196 reset: function() { 197 this.update(0); 198 this.acheivement = false; 199 } 200 };