效果图

数据流分析

1.ticker$ 数据流 interval配合scheduler/animationFrame 作为游戏随时间变化的控制数据流

ticker$ = interval(this.TICKER_INTERVAL, animationFrame).pipe(
map(() => ({
time: Date.now(),
deltaTime: null
})),
scan((previous, current) => ({
time: current.time,
deltaTime: (current.time - previous.time) / 1000
}))
); // Observable单播 每次订阅都是启动一个数据流

2.key$ 数据流检测keydown/keyup 玩家控制的部分(整个状态中的一个副作用),改变底部船桨的位置

PADDLE_CONTROLS = {
ArrowLeft: -1,
ArrowRight: 1
};
key$ = merge(
fromEvent(document, 'keydown').pipe(
map(event => this.PADDLE_CONTROLS[event['key']] || 0)
),
fromEvent(document, 'keyup').pipe(map(event => 0))
).pipe(distinctUntilChanged()); // 提供船桨移动的方位的数据源

实现逻辑:按下‘<’直到 keyup 输出 -1 / 按下‘>’直到 keyup 输出 1 / keyup 输出 0 3.paddle$ 数据流使用操作符withLatestFrom合并了ticker$和key$ 持续流出船桨的位置

createPaddle$(ticker$: Observable<{ time: number; deltaTime: any }>) {
return ticker$.pipe(
withLatestFrom(this.key$), // withLatestFrom操作符 作为游戏开始的触发条件,只有这个数据流产生数据才会往下游流动
scan<[{ deltaTime: number; time: number }, number], number>(
(position: number, [ticker, direction]) => {
const nextPosition =
position + direction * ticker.deltaTime * this.PADDLE_SPEED;
return Math.max(
Math.min(
nextPosition,
this.breakoutCanvasService.stage.width - config.PADDLE_WIDTH / 2
),
config.PADDLE_WIDTH / 2
);
},
this.breakoutCanvasService.stage.width / 2
),
distinctUntilChanged()
);
}

3.createState$ 数据流使用withLatestFrom合并ticker$和paddle$ 最终输出界面需要的全部状态数据

createState$(ticker$, paddle$) {
return ticker$.pipe(
withLatestFrom(paddle$),
scan<
[{ deltaTime: number; time: number }, number],
{ ball: Ball; bricks: Brick[]; score: number }
>(({ ball, bricks, score }, [ticker, paddle]) => {
const remainingBricks = [];
const collisions = {
paddle: false, // 球撞船桨
floor: false, //
wall: false, // 撞墙
ceiling: false, // 撞顶
brick: false // 球撞砖块
};
ball.position.x =
ball.position.x +
ball.direction.x * ticker.deltaTime * this.BALL_SPEED;
ball.position.y =
ball.position.y +
ball.direction.y * ticker.deltaTime * this.BALL_SPEED;
bricks.forEach(brick => {
if (!this.isCollision(brick, ball)) {
remainingBricks.push(brick);
} else {
collisions.brick = true;
score = score + 10;
}
});
collisions.paddle = this.isHit(paddle, ball);
if (
ball.position.x < config.BALL_RADIUS ||
ball.position.x >
this.breakoutCanvasService.stage.width - config.BALL_RADIUS
) {
ball.direction.x = -ball.direction.x;
collisions.wall = true;
} collisions.ceiling = ball.position.y < config.BALL_RADIUS;
if (collisions.brick || collisions.paddle || collisions.ceiling) {
if (collisions.paddle) {
ball.direction.y = -Math.abs(ball.direction.y);
} else {
ball.direction.y = -ball.direction.y;
}
} return {
ball: ball,
bricks: remainingBricks,
collisions: collisions,
score: score
};
}, this.initState())
);
}
  • 用到ticker$流控制球的移动位置
  • 根据当前状态控制下一步的状态,包括计分、球的运动方向、砖块数量

4.game$ 数据流最终的游戏控状态输出流(包括这状态数据、船桨位置数据)

game$ = Observable.create(observer => {
this.breakoutCanvasService.drawIntro();
this.restart = new Subject();
const paddle$ = this.createPaddle$(this.ticker$); // 数据源吐出船桨的位置
const state$ = this.createState$(this.ticker$, paddle$);
this.ticker$
.pipe(
withLatestFrom(paddle$, state$),
OperatorMerge(this.restart)
)
.subscribe(observer); // 这个this.ticker$ 也可以不使用,直接通过merge合并后面两个数据流
});

merge数据流restart$后 可以通过error方法终止流从而控制游戏结束

状态

两个结果状态:砖块数量、分数

两个影响状态的副作用:时间、游戏者的行为

状态交叉点

球接触砖块 -> 砖块消失

球接触船桨/墙 -> 球自然改变运动方向

整个过程用rxjs实现不需要额外保存中间数据,在管道中实现数据的缓存、状态处理 。

两个字形容 “优秀”

演示地址:http://tiny.pubuzhixing.com/

github:https://github.com/pubuzhixing8/tiny-game

出处:《深入浅出RxJS》十四章实例,使用TS+Angular重新包装,修改了一个小缺陷,据说这个游戏最初是由乔布斯和他的一个朋友设计

Worktile官网:www.worktile.com

本文作者:徐海峰

文章首发于「Worktile官方博客」,转载请注明来源。

技术分享:RxJS实战练习-经典游戏Breakout的更多相关文章

  1. 【华为云技术分享】MongoDB经典故障系列五:sharding集群执行sh.stopBalancer()命令被卡住怎么办?

    [摘要] MongoDB sharding集群执行sh.stopBalancer()命令时被卡住怎么办?别慌,华为云数据库来给您支招,收下这份方案指南,让您分分钟远离被自建MongoDB数据库支配的恐 ...

  2. 腾讯技术分享:微信小程序音视频技术背后的故事

    1.引言 微信小程序自2017年1月9日正式对外公布以来,越来越受到关注和重视,小程序上的各种技术体验也越来越丰富.而音视频作为高速移动网络时代下增长最快的应用形式之一,在微信小程序中也当然不能错过. ...

  3. 【C语言探索之旅】 第二部分第九课: 实战"悬挂小人"游戏 答案

    内容简介 1.课程大纲 2.第二部分第九课: 实战"悬挂小人"游戏 答案 3.第二部分第十课预告: 安全的文本输入 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题, ...

  4. 【技术分享】小乖乖的 Linux/Ubuntu 历险记

    本文将同步发布于 WHU-TD 的博客. 这是一篇自带故事背景的博客. 总所周知,写的多,错的多,更何况一个刚刚接触 Linux 的小白.虽然只是介绍一些非常基础的内容,还是希望大家在发现错误时可以及 ...

  5. 分享一实战性开源MVC框架<Linux、Windows跨平台开发so easy>

    一.引子   开源地址 https://github.com/564064202/Moon.Mvc 欢迎加入开发 .NET Core微软还在发力,但作为商用还有一段距离,很多开发库尚不能用于.NET ...

  6. C++复现经典游戏——扫雷

    国庆小长假,当大家都去看人山人海的时候,我独自一人狂码代码.这两天想要实现的内容是Windows上的一个经典游戏——扫雷.相信90后和一些上班族对此并不陌生.然而,从win8开始,扫雷就不再是Wind ...

  7. HTML5学堂 全新的HTML5/前端技术分享平台

    HTML5学堂 全新的HTML5/前端技术分享平台 HTML5学堂是做什么的? HTML5学堂~http://www.h5course.com~由多名热爱H5的讲师们组成的一个组织.致力于构建一个前端 ...

  8. iOS开发技术分享(1)— iOS本地数据存储

    iOS开发技术分享(1)— iOS本地数据存储 前言: 我本是一名asp.net程序员,后来加入了iOS游戏开发队伍,到现在也有一年多的时间了.这一年来,每天都干到2.3点钟才睡觉,不为别的,只为了学 ...

  9. fir.im Weekly - 8 个不能错过的 iOS / Android 技术分享

    本期 fir.im Weekly 收集了 2 月下旬新鲜出炉的 iOS /Android 技术分享.源码等,iOS 中图片技术的解压缩.逆向实战.iOS SDK 实践,Android架构思考.Andr ...

随机推荐

  1. 如何让pandas表格直接转换为markdown表格

    https://stackoverflow.com/questions/33181846/programmatically-convert-pandas-dataframe-to-markdown-t ...

  2. 刚学的vue.js的单一事件管理组件通信

    第一次在博客园写的技术分享,写的不好的话各位大神多体谅,好啦进入主题 说说思路 首先 第一步,准备一个空的示例对象 var Event=new Vue(); 第二步,准备发送的数据 Event.$em ...

  3. 匿名函数 javascript

    匿名函数: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...

  4. Linux-1.Windows远程连接Linux的工具

    1.下载工具 想要链接远程Linux服务器,就需要工具来进行连接. 工具一:连接远端Linux工具--putty(可以用xshell啥的,我懒,就弄了个这个,建议还是xshell哈,功能多,还好看) ...

  5. 批量引用iconfont字体图标到项目

    打开https://www.iconfont.cn/网址登录后选择你需要的图标添加到购物车中 点击下载代码或者添加到项目后再下载代码,再找到之前下载的的文件,拷贝到项目中

  6. C#转发Post请求,包括参数和文件

    /// <summary> /// 转发Post请求 /// </summary> /// <param name="curRequest">要 ...

  7. Docker的基本概念

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何 ...

  8. 浅析Diffie–Hellman

    一.作者 这个密钥交换方法,由惠特菲尔德·迪菲(Bailey Whitfield Diffie).马丁·赫尔曼(Martin Edward Hellman)于1976年发表. 二.说明 它是一种安全协 ...

  9. 阿里面试100%问到,JVM性能调优篇

    JVM 调优概述 性能定义 吞吐量 - 指不考虑 GC 引起的停顿时间或内存消耗,垃圾收集器能支撑应用达到的最高性能指标. 延迟 - 其度量标准是缩短由于垃圾啊收集引起的停顿时间或者完全消除因垃圾收集 ...

  10. CSS3 阴影模拟灯照效果

    效果如下: 代码如下: <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset= ...