likes
comments
collection
share

Flutter 仿英雄联盟 - PLAY 按钮文章表达的是思想,尝试从中探寻方案,解决自己的问题,这才是文章想表达的意义

作者站长头像
站长
· 阅读数 23

“纠结,这个按钮做出来有什么用?”"谁关注你按钮有没有什么光效啊?我打游戏的" 文章表达的是思想,尝试从中探寻方案,解决自己的问题,这才是文章想表达的意义。 一切都是娱乐,切勿上纲上线

承接上一回,昨天做Demo的时候,最后简单概括了PLAY按钮的做法,使用的是 随机 坐标点 光斑 + 模糊效果实现,效果稍差。

Flutter 仿英雄联盟 - PLAY 按钮文章表达的是思想,尝试从中探寻方案,解决自己的问题,这才是文章想表达的意义

生成随机的光斑(未开启模糊效果)

我想到的解决方案是PATH路径绘制。

我刚开始写的时候,都是在尝试,结果做出来这个效果。


Path 就是很多条线组合到一起的,既然可以跟着路径画,那么也可以 产生 很多光点,然后在路径上面 移动的。

这时候其实脑袋都炸了,因为根本没学过类似的东西,我甚至连怎么固定画 一个Path 点都不会,更不提要绘制移动的点了。

最后找到关键代码。

// 测量Path
PathMetrics pathMetrics = playPath.computeMetrics();

// 获取第一小节信息(猜测可能有多个Path叠加?)
PathMetric pathMetric = pathMetrics.first;

// 整个Path的长度
double length = pathMetric.length;

通过动态截取Path就 实现了上面“光线追踪效果”。

// 动画控制 0~1
final Animation<double> factor;

Path extractPath = pathMetric.extractPath(offset, length * factor.value , startWithMoveTo: false);

脑袋还是乱乱的,解决问题的思路是一步一步走,尝试。 整个思考起来过于复杂,先实现一个简单的效果,让1个光点 从 0到1跑完整个Path。

// 错误示范
// 尝试使用固定长度裁剪出长度 为 1/10的 PATH
Path extrPath = pathMetric.extractPath(
          pathMetric.length * factor.value - .1, 
          pathMetric.length * factor.value,
          startWithMoveTo: false
);

// 正确示范
// 获取百分比所在路径的位置
Tangent? tangent = pathMetric.getTangentForOffset(pathMetric.length * factor.value);
if (tangent != null) {
    canvas.drawRect(tangent.position & const Size(3, 3), paint);
}

Flutter 仿英雄联盟 - PLAY 按钮文章表达的是思想,尝试从中探寻方案,解决自己的问题,这才是文章想表达的意义

然后就发现这样做PATH 不是按照 想要的位置和方向来的,虽然可以通过计算 PATH的百分比位置来制作

Flutter 仿英雄联盟 - PLAY 按钮文章表达的是思想,尝试从中探寻方案,解决自己的问题,这才是文章想表达的意义

// 截取出顶部线条的Path  .45 是大概估摸出来的
Path extrPath = pathMetric.extractPath(
        0,
        pathMetric.length * .45,
        startWithMoveTo: true,
);

定义路径(点)

  /// 第一段路径上面的点集合
  List<Offset> firstPathPoints;

  /// 第二段路径上面的点集合
  List<Offset> lastPathPoints;

产生光点

// 将路径拆分成 多个点位
final int pointCount = 10;

 // 产生光点
for (var i = 0; i < pointCount; i++) {
    double radius = Random().nextDouble() * 2 + 1;
   _lights.add(PlayButtonLight(offset: i, radius: radius));
}

接着是拆分2段路径:

//路径分析
PathMetrics pathMetrics = playPath.computeMetrics();
//获取第一小节信息
PathMetric pathMetric = pathMetrics.first;

// 获取顶部路径
PathMetric topPathMetric = pathMetric
  .extractPath(
   0,
   pathMetric.length * .45,
   startWithMoveTo: true,
)
.computeMetrics()
.first;

// 截取顶部的路径
lastPathPoints = splitPath(topPathMetric);

// 获取底部部路径
PathMetric bottomPathMetric = pathMetric
   .extractPath(
   pathMetric.length * .45,
   pathMetric.length,
   startWithMoveTo: false,
)
.computeMetrics()
.first;

// 截取底部路径 - 如果不翻转倒序那么是从左到右,翻转倒叙后 偏移量就会从 右往左
lastPathPoints = splitPath(bottomPathMetric);
//lastPathPoints = splitPath(bottomPathMetric).reversed.toList();//倒叙

-拆分方法

  /// 拆分路径
  List<Offset> splitPath(PathMetric pathMetric) {
    List<Offset> points = [];
    for (var i = 0; i < pointCount; i++) {
      Tangent? tangent =
          pathMetric.getTangentForOffset(pathMetric.length * i / pointCount);
      if (tangent != null) {
        points.add(tangent.position);
      }
    }
    return points;
  }

动画改用 Ticker 而不是 AnimationController (因为我们的动画 没有 进度概念)

_ticker = Ticker(_onTick);

  /// 间隔
  int elapsed = 0;

  void _onTick(Duration newElapsed) {
    //debugPrint("OnTick:$elapsed");
    elapsed++;
    if (elapsed > 10) {
      elapsed = 0;
      _painter.update();
    }
  }

移动光点

/// 移动光点 
  void moveLight() {
     for (var light in _lights) {
        light.offset++;
        if (light.offset >= pointCount) {
          light.offset = 0;
        }
      }
  }

最终效果如下:

Flutter 仿英雄联盟 - PLAY 按钮文章表达的是思想,尝试从中探寻方案,解决自己的问题,这才是文章想表达的意义

转载自:https://juejin.cn/post/7426035341343588415
评论
请登录