【响应式编程的思维艺术】 (4)从打飞机游戏理解并发与流的融合 (3)

enemy.js-敌机流

/** * 敌方飞船 */ //辅助函数-判断是否超出画布范围 function isVisible(obj) { return obj.x > -60 && obj.x < canvas.width + 60 && obj.y > -60 && obj.y < canvas.height + 60; } //每2秒在随机横向位置产生一个敌机 let enemyShipStream = Rx.Observable.interval(2000) .scan((prev)=>{//敌机信息需要一个数组来记录,所以通过scan运算符将随机出现的敌机信息聚合 let newEnemy = { shape:[238,178,120,76], x:parseInt(Math.random() * canvas.width,10), y:50, isDead:false,//标记敌机是否被击中 bullets:[] } //定时生成子弹 Rx.Observable.interval(1500).subscribe(()=>{ if (!newEnemy.isDead) {//被击中的敌人不再产生子弹 newEnemy.bullets.push({ x: newEnemy.x, y: newEnemy.y }); } newEnemy.bullets = newEnemy.bullets.filter(isVisible); }); prev.push(newEnemy); return prev.filter(isVisible); },[]); //绘制飞船 function paintEnemy(enemies) { enemies.forEach(function (enemy) { //绘制时增量改变敌机坐标 enemy.y = enemy.y + 3; enemy.x = enemy.x + parseInt(Math.random()*8 - 4,10); //绘制时增量改变敌机子弹坐标 enemy.bullets.forEach(function(bullet){bullet.y = bullet.y + 16;}); //如果敌机没挂则绘制飞机 if (!enemy.isDead) { ctx.save(); ctx.translate(enemy.x, enemy.y); ctx.rotate(Math.PI); //绘制敌机 ctx.drawImage(spaceShipImg,enemy.shape[0],enemy.shape[1],enemy.shape[2],enemy.shape[3], 0, 0, enemy.shape[2] * 0.8 ,enemy.shape[3] * 0.8); ctx.restore(); } //绘制子弹 enemy.bullets.forEach(function (bullet) { ctx.save(); ctx.translate(bullet.x, bullet.y); ctx.rotate(Math.PI); ctx.drawImage(spaceShipImg,enemy.shape[0],enemy.shape[1],enemy.shape[2],enemy.shape[3], 0, 0, enemy.shape[2] / 4,enemy.shape[3] / 4); ctx.restore(); }); ctx.restore(); }); }

collision.js-碰撞检测

// 辅助函数 function isCollision(target1, target2) { return (target1.x > target2.x - 50 && target1.x < target2.x + 50) && (target1.y > target2.y - 20 && target1.y < target2.y + 20); } //碰撞检测方法 function checkCollision(myship, enemies) { let gameOver = false; myship.bullets.forEach(function(bullet) { enemies.forEach(function (enemy) { //检查是否击中了敌机 if (isCollision(bullet, enemy)) { bullet.used = true; enemy.isDead = true; }; //检查是否被击中,被击中则游戏结束 enemy.bullets.forEach(function (enemyBullet) { if (isCollision(myship, enemyBullet)) { gameOver = true; } }) }) }); return gameOver; }

combineAll.js-融合最终的游戏流

/** * 集合所有流 */ let gameStream = Rx.Observable.combineLatest(starStream, myShipStream, enemyShipStream, function (stars,myship,enemies) { return { stars,myship,enemies } }) .sample(40);//sample函数来规避鼠标移动事件过快触发导致坐标数据更新过快 //绘制所有元素 function paintAll(data) { let isGameOver; isGameOver = checkCollision(data.myship, data.enemies);//检查子弹是否击中敌人 if (!isGameOver) { paintStar(data.stars); paintMyShip(data.myship); paintEnemy(data.enemies); }else{ gameSubscription.dispose(); alert('被击中了'); } } //订阅所有汇总的流来启动游戏 let gameSubscription = gameStream.subscribe(paintAll);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspdxg.html