这一步画靶子没有什么出格的,随机得增加dx和dy,在遇到阁下边沿时反弹。主要一点就是单词的绘制,通过typeIndex将单词一分为二,敲击过的字符置为灰色,然后通过measureText获取到敲击字符的宽度从而配置未敲击字符的x轴偏移量,将未敲击的字符配置为赤色,提示玩家这个单词是正在进攻中的方针。
3、从飞机头部发射出去,直奔仇人而去的子弹子弹是这个游戏的要害部门,在绘制子弹的时候要思量哪些方面呢?
(1)方针一直是举动的,发射出去的子弹要一直“追踪”方针,所以路径是动态变革的;
(2)一个方针需要被若干个子弹没落掉,所以什么时候子弹才从画面中抹去;
(3)当一个方针单词被敲击完了后,下一批子弹就要朝向下一个方针射击,所以子弹的路径是单独的;
(4)如何绘制出子弹的拖尾结果;
(5)假如锁定正在敲击的方针单词,使玩家敲完当前单词才气去击破下一个单词
这里先配置几个变量:
bulletArr: [], // 存放子弹工具
currentIndex: -1 //当前锁定的方针在targetArr中的索引
首先我们先来写一下键盘按下时要触发的函数:
handleKeyPress(key) { // 键盘按下,判定当前方针 let _this = this; if (_this.currentIndex === -1) { // 当前没有在射击的方针 let index = _this.targetArr.findIndex(item => { return item.txt.indexOf(key) === 0; }); if (index !== -1) { _this.currentIndex = index; _this.targetArr[index].typeIndex = 0; _this.createBullet(index); } } else { // 已有方针正在被射击 if ( key === _this.targetArr[_this.currentIndex].txt.split("")[ _this.targetArr[_this.currentIndex].typeIndex + 1 ] ) { // 获取到方针工具 _this.targetArr[_this.currentIndex].typeIndex++; _this.createBullet(_this.currentIndex); if ( _this.targetArr[_this.currentIndex].typeIndex === _this.targetArr[_this.currentIndex].txt.length - 1 ) { // 这个方针已经别射击完毕 _this.currentIndex = -1; } } } }, // 发射一个子弹 createBullet(index) { let _this = this; this.bulletArr.push({ dx: 1, dy: 4, x: _this.clientWidth / 2, y: _this.clientHeight - 60, targetIndex: index }); }
这个函数做的工作很明晰,拿到当前键盘按下的字符,假如currentIndex ===-1,证明没有正在被进攻的靶子,所以就去靶子数组里看,哪个单词的首字母便是该字符,则配置currentIndex为该单词的索引,并发射一个子弹;假如已经有正在被进攻的靶子,则看还未敲击的单词的第一个字符是否切合,若切合,则增加该靶子工具的typeIndex,并发射一个子弹,若当前靶子已敲击完毕,则重置currentIndex为-1。
接下来就是画子弹咯:
drawBullet() { // 逐帧画子弹 let _this = this; // 判定子弹是否已经击中方针 if (_this.bulletArr.length === 0) { return; } _this.bulletArr = _this.bulletArr.filter(_this.firedTarget); _this.bulletArr.forEach(item => { let targetX = _this.targetArr[item.targetIndex].x; let targetY = _this.targetArr[item.targetIndex].y; let k = (_this.clientHeight - 60 - targetY) / (_this.clientWidth / 2 - targetX); // 飞机头和方针的斜率 let b = targetY - k * targetX; // 常量b item.y = item.y - bullet.dy; // y轴偏移一个单元 item.x = (item.y - b) / k; for (let i = 0; i < 15; i++) { // 画出拖尾结果 _this.ctx.beginPath(); _this.ctx.arc( (item.y + i * 1.8 - b) / k, item.y + i * 1.8, 4 - 0.2 * i, 0, 2 * Math.PI ); _this.ctx.fillStyle = `rgba(193,255,255,${1 - 0.08 * i})`; _this.ctx.fill(); _this.ctx.closePath(); } }); }, firedTarget(item) { // 判定是否击中方针 let _this = this; if ( item.x > _this.targetArr[item.targetIndex].x - _TARGET_CONFIG.radius && item.x < _this.targetArr[item.targetIndex].x + _TARGET_CONFIG.radius && item.y > _this.targetArr[item.targetIndex].y - _TARGET_CONFIG.radius && item.y < _this.targetArr[item.targetIndex].y + _TARGET_CONFIG.radius ) { // 子弹击中了方针 let arrIndex = item.targetIndex; _this.targetArr[arrIndex].hitIndex++; if ( _this.targetArr[arrIndex].txt.length - 1 === _this.targetArr[arrIndex].hitIndex ) { // 所有子弹全部击中了方针 let word = _this.targetArr[arrIndex].txt; _this.targetArr[arrIndex] = { // 生成新的方针 x: _this.getRandomInt( _TARGET_CONFIG.radius, _this.clientWidth - _TARGET_CONFIG.radius ), y: _TARGET_CONFIG.radius * 2, txt: _this.generateWord(1)[0], typeIndex: -1, hitIndex: -1, dx: (_TARGET_CONFIG.speed * Math.random().toFixed(1)) / 2, dy: _TARGET_CONFIG.speed * Math.random().toFixed(1), rotate: 0 }; _this.wordsPool.push(word); // 被击中的方针词重回池子里 _this.score++; } return false; } else { return true; } }