范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

教你用ECharts轻松做一个FlappyBird小游戏

  本文分享自华为云社区《没想到吧!这个可可爱爱的游戏居然是用 ECharts 实现的!-云社区-华为云》,作者:DevUI。前言
  echarts是一个很强大的图表库,除了我们常见的图表功能,echarts有一个自定义图形的功能,这个功能可以让我们很简单地在画布上绘制一些非常规的图形,基于此,我们来玩一些花哨的。
  Flappy Bird小游戏体验地址(看看你能玩几分):
  foolmadao.github.io/echart-flap…
  下面我们来一步步实现他。1 在坐标系中画一只会动的小鸟
  首先实例化一个echart容器,再从网上找一个像素小鸟的图片,将散点图的散点形状,用自定义图片的方式改为小鸟。const myChart = echarts.init(document.getElementById("main")); option = {   series: [     {       name: "bird",       type: "scatter",       symbolSize: 50,       symbol: "image://bird.png",       data: [         [50, 80]       ],       animation: false     },   ] };  myChart.setOption(option);
  要让小鸟动起来,就需要给一个向右的速度和向下的加速度,并在每一帧的场景中刷新小鸟的位置。而小鸟向上飞的动作,则可以靠角度的旋转来实现,向上飞的触发条件设置为空格事件。option = {   series: [     {       xAxis: {         show: false,         type: "value",         min: 0,         max: 200,       },       yAxis: {         show: false,         min: 0,         max: 100       },       name: "bird",       type: "scatter",       symbolSize: 50,       symbol: "image://bird.png",       data: [         [50, 80]       ],       animation: false     },   ] };  // 设置速度和加速度 let a = 0.05; let vh = 0; let vw = 0.5  timer = setInterval(() => {   // 小鸟位置和仰角调整   vh = vh - a;   option.series[0].data[0][1] += vh;   option.series[0].data[0][0] += vw;   option.series[0].symbolRotate = option.series[0].symbolRotate ? option.series[0].symbolRotate - 5 : 0;    // 坐标系范围调整   option.xAxis.min += vw;   option.xAxis.max += vw;    myChart.setOption(option); }, 25);
  效果如下
  2 用自定义图形绘制障碍物
  echarts自定义系列,渲染逻辑由开发者通过renderItem函数实现。该函数接收两个参数params和api,params包含了当前数据信息和坐标系的信息,api是一些开发者可调用的方法集合,常用的方法有:api.value(…),意思是取出 dataItem 中的数值。例如 api.value(0) 表示取出当前 dataItem 中第一个维度的数值。api.coord(…),意思是进行坐标转换计算。例如 var point = api.coord([api.value(0), api.value(1)]) 表示 dataItem 中的数值转换成坐标系上的点。api.size(…), 可以得到坐标系上一段数值范围对应的长度。api.style(…),可以获取到series.itemStyle 中定义的样式信息。
  灵活使用上述api,就可以将用户传入的Data数据转换为自己想要的坐标系上的像素位置。
  renderItem函数返回一个echarts中的graphic类,可以多种图形组合成你需要的形状,graphic类型。对于我们游戏中的障碍物只需要使用矩形即可绘制出来,我们使用到下面两个类。type: group, 组合类,可以将多个图形类组合成一个图形,子类放在children中。type: rect, 矩形类,通过定义矩形左上角坐标点,和矩形宽高确定图形。// 数据项定义为[x坐标,下方水管上侧y坐标, 上方水管下侧y坐标] data: [   [150, 50, 80],   ... ]  renderItem: function (params, api) {     // 获取每个水管主体矩形的起始坐标点     let start1 = api.coord([api.value(0) - 10, api.value(1)]);     let start2 = api.coord([api.value(0) - 10, 100]);     // 获取两个水管头矩形的起始坐标点     let startHead1 = api.coord([api.value(0) - 12, api.value(1)]);     let startHead2 = api.coord([api.value(0) - 12, api.value(2) + 8])     // 水管头矩形的宽高     let headSize = api.size([24, 8])     // 水管头矩形的宽高     let rect = api.size([20, api.value(1)]);     let rect2 = api.size([20, 100 - api.value(2)]);     // 坐标系配置     const common = {         x: params.coordSys.x,         y: params.coordSys.y,         width: params.coordSys.width,         height: params.coordSys.height     }     // 水管形状     const rectShape = echarts.graphic.clipRectByRect(       {         x: start1[0],         y: start1[1],         width: rect[0],         height: rect[1]       },common     );     const rectShape2 = echarts.graphic.clipRectByRect(       {         x: start2[0],         y: start2[1],         width: rect2[0],         height: rect2[1]       },       common     )      // 水管头形状     const rectHeadShape = echarts.graphic.clipRectByRect(       {         x: startHead1[0],         y: startHead1[1],         width: headSize[0],         height: headSize[1]       },common     );      const rectHeadShape2 = echarts.graphic.clipRectByRect(       {         x: startHead2[0],         y: startHead2[1],         width: headSize[0],         height: headSize[1]       },common     );      // 返回一个group类,由四个矩形组成     return {         type: "group",         children: [{             type: "rect",             shape: rectShape,             style: {               ...api.style(),               lineWidth: 1,               stroke: "#000"             }         }, {             type: "rect",             shape: rectShape2,             style: {               ...api.style(),               lineWidth: 1,               stroke: "#000"             }         },         {             type: "rect",             shape: rectHeadShape,             style: {               ...api.style(),               lineWidth: 1,               stroke: "#000"             }         },         {             type: "rect",             shape: rectHeadShape2,             style: {               ...api.style(),               lineWidth: 1,               stroke: "#000"             }         }]     };   },
  颜色定义, 我们为了让水管具有光泽使用了echarts的线性渐变色对象。itemStyle: {   // 渐变色对象   color: {     type: "linear",     x: 0,     y: 0,     x2: 1,     y2: 0,     colorStops: [{         offset: 0, color: "#ddf38c" // 0% 处的颜色     }, {         offset: 1, color: "#587d2a" // 100% 处的颜色     }],     global: false // 缺省为 false   },   borderWidth: 3 },
  另外,用一个for循环一次性随机出多个柱子的数据function initObstacleData() {     // 添加minHeight防止空隙太小     let minHeight = 20;     let start = 150;     obstacleData = [];     for (let index = 0; index < 50; index++) {       const height = Math.random() * 30 + minHeight;       const obstacleStart = Math.random() * (90 - minHeight);       obstacleData.push(         [           start + 50 * index,           obstacleStart,           obstacleStart + height > 100 ? 100 : obstacleStart + height         ]       )     }   }
  再将背景用游戏图片填充,我们就将整个游戏场景,绘制完成:
  3 进行碰撞检测
  由于飞行轨迹和障碍物数据都很简单,所以我们可以将碰撞逻辑简化为小鸟图片的正方形中,我们判断右上和右下角是否进入了自定义图形的范围内。
  对于特定坐标下的碰撞范围,因为柱子固定每格50坐标值一个,宽度也是固定的,所以,可碰撞的横坐标范围就可以简化为 (x / 50 % 1) < 0.6
  在特定范围内,依据Math.floor(x / 50)获取到对应的数据,即可判断出两个边角坐标是否和柱子区域有重叠了。在动画帧中判断,如果重叠了,就停止动画播放,游戏结束。// centerCoord为散点坐标点 function judgeCollision(centerCoord) {   if (centerCoord[1] < 0 || centerCoord[1] > 100) {     return false;   }   let coordList = [     [centerCoord[0] + 15, centerCoord[1] + 1],     [centerCoord[0] + 15, centerCoord[1] - 1],   ]    for (let i = 0; i < 2; i++) {     const coord = coordList[i];     const index = coord[0] / 50;     if (index % 1 < 0.6 && obstacleData[Math.floor(index) - 3]) {       if (obstacleData[Math.floor(index) - 3][1] > coord[1] || obstacleData[Math.floor(index) - 3][2] < coord[1]) {         return false;       }     }   }   return false }  function initAnimation() {   // 动画设置   timer = setInterval(() => {     // 小鸟速度和仰角调整     vh = vh - a;     option.series[0].data[0][1] += vh;     option.series[0].data[0][0] += vw;     option.series[0].symbolRotate = option.series[0].symbolRotate ? option.series[0].symbolRotate - 5 : 0;      // 坐标系范围调整     option.xAxis.min += vw;     option.xAxis.max += vw;      // 碰撞判断     const result = judgeCollision(option.series[0].data[0])      if(result) { // 产生碰撞后结束动画       endAnimation();     }      myChart.setOption(option);   }, 25); }总结
  echarts提供了强大的图形绘制自定义能力,要使用好这种能力,一定要理解好数据坐标点和像素坐标点之间的转换逻辑,这是将数据具象到画布上的重要一步。
  运用好这个功能,再也不怕产品提出奇奇怪怪的图表需求。
  源码地址:github.com/foolmadao/e…
  点击下方,第一时间了解华为云新鲜技术~
  华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云

以岭药业放大招,千亿巨头回应分拆上市,明天有利好发布今天大A尾盘拉红了,资金还是很讲政治的!但个股有点稀烂,只有三分之一是涨的,高位票更是炸板潮,一度炸板率接近60,说明资金开始恐高了。最惨的股民,昨天打板深振业,今天地板割,反手打中国中铁,时隔8年,正在重演历史中国中铁,像一只沉睡的大象,躺在资本市场里面,多年来很少有人问津,并有80万股民黯然离场。然而,细心的人们会发现一个有趣的现象。在2020年春节之后,中国中铁的股价已经停止了下跌,航空发动机控制系统龙头,航发控制产业地位突出,成长潜力大(报告出品方分析师民生证券尹会伟孔厚融赵博轩)1主营航发控制系统,十四五进入快速增长阶段1。1聚焦航空发动机控制系统主业历史悠久积累深厚,2021年募投33。7亿元扩产迎接行业需求近百品牌通过二次配方注册奶粉企业态度不一截至目前,共有近100个奶粉品牌通过了二次配方注册。其中,仅11月30日就有25个奶粉品牌的68个配方产品通关。那么,闯关成功的品牌有何共同特征?大小奶粉企业对二次配方注册的态度如金融持续发力支持实体经济央视网消息(新闻联播)今年以来,金融持续发力支持实体经济,助力我国经济平稳发展。日前,人民银行正式降低金融机构存款准备金率0。25个百分点,共计释放银行资金约5000亿元。保持流动人民币重回6时代,外贸人边加大锁汇边抢单对于以出口为主的外贸人来说,人民币的快速升值以及剧烈波动,都是需要防范的风险。我们最近加大了锁汇的比例,从原来的3050,增加到了50以上。长三角地区一家规模较大的服装外贸企业负责坑过张兰的资本圈,咋又让中国餐饮心动了?文零度出品节点财经背靠全球最大的披萨公司,达美乐中国即将冲击港交所。继今年3月招股书失效后,达势股份近日再次更新了招股书。作为全球最大披萨公司达美乐的中国特许经销商,达势股份坚定的欲变更实控人海南椰岛前路何方海南椰岛更换实控人计划进行的似乎没那么顺利。12月6日,海南椰岛发布收到上海证券交易所问询函的公告,上交所对海南椰岛非公开发行股票事项进行问询。据了解,10天前,海南椰岛发布公告称跨境电子商务先行先试再次扩围自2015年3月批准设立中国(杭州)跨境电子商务综合试验区之后,已历经多次扩围,在一些地区(如江苏浙江广东)跨境电子商务综合试验区(以下简称跨境电商综试区)已实现地级市全覆盖1。2连续3月增长!丰田最新销量公布11月29日,丰田汽车集团对外发布10月产销数据。数据显示,2022年10月丰田汽车全球销量同比增长22。1至83。2万辆,连续3个月同比增长,其中日本本土销量同比增长34。26至12。6超短复盘指数继续按照趋势线震荡,指数在这个区间每天最好的走势就是每天保证有新高,然后一点点的震荡。具体的说法可以参考我周一的复盘文章,现在都在按照之前所说的剧本来行动。板块今日轮动趋势变得
肚子经常咕咕叫是怎么回事?看完或对您有帮助早上没有吃饭,还没有到中午肚子就开始咕咕叫,这是肠胃在提醒人们需要及时进食了,吃一些东西可以缓解饥饿感,肠道在工作时,如果体内的水分和液体发生了变化,我们会听到咕噜咕噜的声音,肠鸣补充维生素C真的那么神奇吗?健康2023大家是不是看到很多人推荐补充维生素C,那每天吃真的有用吗?其实只需要补充够每日所需量就可以了,但是如果生病期间,补充维生素C有没有效果呢?维生素C可以刺激淋巴细胞增殖刺38岁男子坚持每天喝枸杞水降血糖养肾,3个月后健康情况如何?为什么我喝了3个月的枸杞泡水,结果好像啥好处都没有!反而感觉更上火了。原来早在3个月前,38岁的杨先生感觉自己最近有些不适,出现了腰酸膝软,同房后无力等症状,上网搜了搜,说这是肾虚阳痿了就补肾?大错特错!别忽略这个部位,一张方子找准问题所在前段时间看到过这样一段话,人生最好的三种状态,分别是不期而遇不言而喻不药而愈。这个词看似空空如也,其实这和我们中国文化中所倡导的人生理念不谋而合,这个人生理念便是遵循天道,顺其自然高血压患者想要保护血管,要注意这5件事一合理的服用降压药高血压病人大部分情况下,都是要坚持药物治疗的,而且要坚持稳定准时的服用降压药。病人服药方式和剂量都要根据医生处方来进行,医生会根据病人的真实情况来调整用药,所以病独行侠4换1报价阿奴诺比!东契奇将迎来防守帮手,这是要起飞了?报价背景独行侠在洛杉矶双熊的主场,先是被快船胖揍了一顿,然后和湖人鏖战双加时,堪堪取得一场胜利,东契奇依旧是高效稳定,又是两场35的表现,早已经是联盟第一得分手的表现。如果说联盟里即将租借加盟曼联,官方韦霍斯特与贝西克塔斯结束租约直播吧1月13日讯官方消息,韦霍斯特与贝西克塔斯提前结束租约,伯恩利支付282。5万欧解约金。据此前罗马诺消息,曼联将向贝西克塔斯支付300万欧元,从伯恩利租借签下韦霍斯特,租期半全新一代的红旗EQM5整体的外观颜值比较高EQM5纯电动B级车正式亮相,车型的长度超5米,目前续航里程在431公里左右,并且支持换电功能,整体的竞争力十足,目前车型价格水平在12万左右,这样的价格水平表现,展现出了很强的性怪了!中国四大名酒,为啥没有五粮液剑南春?背后有何内幕?怪了!中国四大名酒,为啥没有五粮液剑南春?背后有何内幕?中国的酒文化历史悠久,发展至今,每年的好酒也是层出不穷,还有各种白酒榜单,获得了不少酒友们的一致认可,即使过了很多年,今天看五粮液永不分梨,那么大的梨是咋放进去的?看完懂了,太巧妙把一整个鸭梨泡在白酒中,寓意永不分梨,这款酒一经上市便有着很高的关注度,这并不是博人眼球的网红酒,而是名酒五粮液推出的五粮液永不分梨。这是款浓香型白酒,酒精度数为40度。它的售价也小小轵城三国保关帝庙头条创作挑战赛2019年,看济源轵城关帝庙成了新晋的八批国保,想起这个小小的轵城居然有大明寺古轵国遗迹和关帝庙三个国保了。2017年年初去济源,玩了王屋山(见我帖)阳台宫(见我帖)