Flutter 仿英雄联盟 - PLAY 按钮文章表达的是思想,尝试从中探寻方案,解决自己的问题,这才是文章想表达的意义
“纠结,这个按钮做出来有什么用?”"谁关注你按钮有没有什么光效啊?我打游戏的" 文章表达的是思想,尝试从中探寻方案,解决自己的问题,这才是文章想表达的意义。 一切都是娱乐,切勿上纲上线
承接上一回,昨天做Demo的时候,最后简单概括了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);
}
然后就发现这样做PATH 不是按照 想要的位置和方向来的,虽然可以通过计算 PATH的百分比位置来制作
// 截取出顶部线条的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;
}
}
}
最终效果如下:
转载自:https://juejin.cn/post/7426035341343588415