哈喽,大家好,今天给大家推荐一款开源游戏
Github 地址 https://github.com/chvin/react-tetris
效果预览
正常速度的录制,体验流畅。
响应式
不仅指屏幕的自适应,而是在PC使用键盘、在手机使用手指的响应式操作
:
手机
数据持久化
玩单机游戏最怕什么?断电。通过订阅 store.subscribe
,将 state 储存在 localStorage,精确记录所有状态。网页关了刷新了、程序崩溃了、手机没电了,重新打开连接,都可以继续。
Redux状态预览
Redux 设计管理了所有应存的状态,这是上面持久化的保证。
游戏框架使用的是 React + Redux,其中再加入了 Immutable,用它的实例来做来 Redux 的 state。(有关 React 和 Redux 的介绍可以看:React 入门实例、Redux 中文文档)
Immutable 是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。
让我们看下面一段代码:
function keyLog(touchFn) {
let data = { key: 'value' };
f(data);
console.log(data.key); // 猜猜会打印什么?
}
不查看 f,不知道它对 data
做了什么,无法确认会打印什么。但如果 data
是 Immutable,你可以确定打印的是 value
:
function keyLog(touchFn) {
let data = Immutable.Map({ key: 'value' });
f(data);
console.log(data.get('key')); // value
}
JavaScript 中的Object
与Array
等使用的是引用赋值,新的对象简单的引用了原始对象,改变新也将影响旧的:
foo = {a: 1}; bar = foo; bar.a = 2;
foo.a // 2
虽然这样做可以节约内存,但当应用复杂后,造成了状态不可控,是很大的隐患,节约的内存优点变得得不偿失。
Immutable 则不一样,相应的:
foo = Immutable.Map({ a: 1 }); bar = foo.set('a', 2);
foo.get('a') // 1
在Redux
中,它的最优做法是每个reducer
都返回一个新的对象(数组),所以我们常常会看到这样的代码:
// reducer
...
return [
...oldArr.slice(0, 3),
newValue,
...oldArr.slice(4)
];
为了返回新的对象(数组),不得不有上面奇怪的样子,而在使用更深的数据结构时会变的更棘手。让我们看看 Immutable 的做法:
// reducer
...
return oldArr.set(4, newValue);
是不是很简洁?
我们知道对于Object
与Array
的===
比较,是对引用地址的比较而不是“值比较”,如:
{a:1, b:2, c:3} === {a:1, b:2, c:3}; // false
[1, 2, [3, 4]] === [1, 2, [3, 4]]; // false
对于上面只能采用 deepCopy
、deepCompare
来遍历比较,不仅麻烦且好性能。
我们感受来一下Immutable
的做法!
map1 = Immutable.Map({a:1, b:2, c:3});
map2 = Immutable.Map({a:1, b:2, c:3});
Immutable.is(map1, map2); // true
// List1 = Immutable.List([1, 2, Immutable.List[3, 4]]);
List1 = Immutable.fromJS([1, 2, [3, 4]]);
List2 = Immutable.fromJS([1, 2, [3, 4]]);
Immutable.is(List1, List2); // true
似乎有阵清风吹过。
React 做性能优化时有一个大招
,就是使用 shouldComponentUpdate()
,但它默认返回 true
,即始终会执行 render()
方法,后面做 Virtual DOM 比较。
在使用原生属性时,为了得出 shouldComponentUpdate 正确的true
or false
,不得不用 deepCopy、deepCompare 来算出答案,消耗的性能很不划算。而在有了 Immutable 之后,使用上面的方法对深层结构的比较就变的易如反掌。
对于「俄罗斯方块」,试想棋盘是一个二维数组
,可以移动的方块则是形状(也是二维数组)
+坐标
。棋盘与方块的叠加则组成了最后的结果Matrix
。游戏中上面的属性都由Immutable
构建,通过它的比较方法,可以轻松写好shouldComponentUpdate
。源代码:/src/components/matrix/index.js#L35
Immutable 学习资料:
Immutable.js
Immutable 详解及 React 中实践
目标:将state
-> Immutable 化。关键的库:gajus/redux-immutable将原来 Redux 提供的 combineReducers 改由上面的库提供:
// rootReducers.js
// import { combineReducers } from 'redux'; // 旧的方法
import { combineReducers } from 'redux-immutable'; // 新的方法
import prop1 from './prop1';
import prop2 from './prop2';
import prop3 from './prop3';
const rootReducer = combineReducers({
prop1, prop2, prop3,
});
// store.js
// 创建store的方法和常规一样
import { createStore } from 'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer);
export default store;
通过新的combineReducers
将把 store 对象转化成 Immutable,在 container 中使用时也会略有不同(但这正是我们想要的):
const mapStateToProps = (state) => ({
prop1: state.get('prop1'),
prop2: state.get('prop2'),
prop3: state.get('prop3'),
next: state.get('next'),
});
export default connect(mapStateToProps)(App);
游戏里有很多不同的音效,而实际上只引用了一个音效文件:/build/music.mp3。借助Web Audio Api
能够以毫秒级精确、高频率的播放音效,这是<audio>
标签所做不到的。在游戏进行中按住方向键移动方块,便可以听到高频率的音效。
网页音效进阶
WAA
是一套全新的相对独立的接口系统,对音频文件拥有更高的处理权限以及更专业的内置音频效果,是 W3C 的推荐接口,能专业处理“音速、音量、环境、音色可视化、高频、音向”等需求,下图介绍了 WAA 的使用流程。
流程
其中 Source 代表一个音频源,Destination 代表最终的输出,多个 Source 合成出了 Destination。源代码:/src/unit/music.js 实现了 ajax 加载 mp3,并转为 WAA,控制播放的过程。
WAA
在各个浏览器的最新 2 个版本下的支持情况(CanIUse)
浏览器兼容
可以看到 IE 阵营与大部分安卓机不能使用,其他 ok。
Web Audio Api 学习资料:
Web API 接口| MDN
Getting Started with Web Audio API
技术:
按下方向键水平移动和竖直移动的触发频率是不同的,游戏可以定义触发频率,代替原生的事件频率,源代码:/src/unit/event.js ;
左右移动可以 delay 掉落的速度,但在撞墙移动的时候 delay 的稍小;在速度为 6 级时 通过 delay 会保证在一行内水平完整移动一次;
对按钮同时注册touchstart
和mousedown
事件,以供响应式游戏。当touchstart
发生时,不会触发mousedown
,而当mousedown
发生时,由于鼠标移开事件元素可以不触发mouseup
,将同时监听mouseout
模拟 mouseup
。源代码:/src/components/keyboard/index.js;
监听了 visibilitychange
事件,当页面被隐藏\切换的时候,游戏将不会进行,切换回来将继续,这个focus
状态也被写进了 Redux 中。所以当用手机玩来电话
时,游戏进度将保存;PC 开着游戏干别的也不会听到 gameover,这有点像 ios
应用的切换。
在任意
时刻刷新网页,(比如消除方块时、游戏结束时)也能还原当前状态;
游戏中唯一用到的图片是
image
,其他都是 CSS;
游戏兼容 Chrome、Firefox、IE9+、Edge 等;
玩法:
可以在游戏未开始时制定初始的棋盘(十个级别)和速度(六个级别);
一次消除 1 行得 100 分、2 行得 300 分、3 行得 700 分、4 行得 1500 分;
方块掉落速度会随着消除的行数增加(每 20 行增加一个级别);
为所有的component
都编写了shouldComponentUpdate
,在手机上的性能相对有显著的提升。中大型应用在遇到性能上的问题的时候,写好 shouldComponentUpdate 一定会帮你一把。
无状态组件
(Stateless Functional Components)是没有生命周期的。而因为上条因素,所有组件都需要生命周期 shouldComponentUpdate,所以未使用无状态组件。
在 webpack.config.js
中的 devServer 属性写入host: '0.0.0.0'
,可以在开发时用 ip 访问,不局限在 localhost;
redux 中的store
并非只能通过 connect 将方法传递给container
,可以跳出组件,在别的文件拿出来做流程控制(dispatch),源代码:/src/control/states.js;
用 react+redux 做持久化非常的方便,只要将 redux 状态储存,在每一个 reduers 做初始化的时候读取就好。
通过配置 .eslintrc.js与 webpack.config.js
,项目中集成了 ESLint
检验。使用 ESLint 可以使编码按规范编写,有效地控制代码质量。不符规范的代码在开发时(或 build 时)都能通过 IDE 与控制台发现错误。参考:Airbnb: React 使用规范;
作为一个 React 的练手应用,在实现的过程中发现小小的“方块”还是有很多的细节可以优化和打磨,这时就是考验一名前端工程师的细心和功力的时候。
优化的方向既有 React 的本身,比如哪些状态由 Redux 存,哪些状态给组件的 state 就好;而跳出框架又有产品的很多特点可以玩,为了达到你的需求,这些都将自然的推进技术的发展。
一个项目从零开始,功能一点一滴慢慢累积,就会盖成高楼,不要畏难,有想法就敲起来吧。^_^
控制流程
npm install
npm start
浏览自动打开 http://127.0.0.1:8080/
在 i18n.json 配置多语言环境,使用"lan"参数匹配语言如:https://chvin.github.io/react-tetris/?lan=en
npm run build
在 build 文件夹下生成结果。
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/pcejw3mRX2dS3M0UYEWeSw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。