粒子运动概念

粒子运动是将对象按照一定物理公式进行的自定义轨迹运动,与普通动画不同的是,它没有强制性的动画开始到结束的时间概念,因为粒子的运动开始到结束的时间并不是固定的,而是由具体场景的物理运动公式来决定的,什么时候结束由你来定,例如:小球自由落体弹跳动画松开小球开始到地面停止的时间就跟距离地面初始高度有关,初始高度越高,动画时间越长,反之依然,所以,粒子运动可以说是符合物理公式并持续不断的动画。

粒子运动特点:符合物理运动公式、持续不断运动。

如何保持持续运动 

我们可以通过动画控制器AnimationController调用repeat();方法开启无限循环动画来实现,这里时间设置多少都行,因为我们不用它,而是用addListener()这个方法来触发小球运动,这个方法可以理解为粒子运动的刷新率,通常1秒触发回调60次,通过这个回调我们就可以持续不断的驱使小球改运动。

late AnimationController _controller;
_controller = AnimationController(
  duration: const Duration(seconds: 1),
  vsync: this,
) ..addListener((){
// 通常这个回调会一秒回调60次 也就是我们平常的60hz屏幕刷新率。
})..repeat();

创建粒子对象

理解了上方的信息,接下来我们首先创建一个粒子对象,粒子对象包含粒子运动所需速度、加速度、位移等信息。

代码:

// 粒子对象
class Particle {
 double x; // x轴位移.
  double ax; // 粒子水平加速度
  double vx; //粒子水平速度
  
  double y; // y轴位移.
  double ay; // 粒子竖直加速度
  double vy; //粒子竖直速度
  
 double maxY;//最大垂直弹跳高度
 
  double size; // 粒子大小.
  Color color; // 粒子颜色.

  Particle({
   this.x = 0,
    this.ax = 0,
    this.vx = 0,
    this.y = 0,
    this.ay = 0,
    this.vy = 0,
    this.size = 0,
    this.maxY = 0,
    this.color = Colors.blue,
  });
}

创建粒子控制器

有了粒子对象,接下来创建粒子控制器,混入ChangeNotifier通过改变粒子属性通知画板刷新,这里通过update方法改变小球的运动轨迹。

我们知道自由落体弹跳,由于地心引力和能量守恒,在没有外力的加持下,小球落地弹起的过程是一个加速 - 弹起 - 减速 - 速度为0 - 再加速...的过程,最终小球相对地面达到静止状态,那么我们假设小球垂直自由落体弹跳,由于能量的损失,小球弹起速度为下落撞击地面速度的4/5,那么随着时间的推移,小球的速度就会越来越慢,直到静止。

代码:

// 粒子控制器
class ParticleController with ChangeNotifier {
  // 粒子
  late Particle p;
  // 粒子运动区域
  Size? size;

  ParticleController();

  void update() {
    // 此方法一秒刷新60次
    // 距离= 时间 * 速度。
    p.y  = p.vy;
     // 自由落体 速度不断加快,地球加速度9.8/s
    p.vy  = p.ay;
    if (p.y > size!.height) {
    // 反弹高度为之前4/5
      p.maxY = p.maxY * 0.8;
      p.y = size!.height;
      // 假设能量损失 反弹速度为下落最大速度的4/5
      p.vy = -p.vy * 0.8;
    }
    if (p.y < size!.height - p.maxY) {
      p.y = size!.height - p.maxY;
      p.vy = 0;
    }

    if (p.maxY < 0.01) {
    // 如果小球距离地面小于0.01 我们认为小球已达到静止状态,动画结束 恢复初始高度,以及最大高度
      p.y = p.initY;
      p.maxY = size!.height;
    }
    notifyListeners();
  }
}

初始化粒子

创建粒子控制器,初始化粒子,设置粒子初始位移、初始速度,加速度等信息,并将粒子控制器传给画板。

late AnimationController _controller;
ParticleController pController = ParticleController();

@override
void initState() {
  super.initState();
  // 初始化
  initParticleController();
  _controller = AnimationController(
    duration: const Duration(seconds: 1),
    vsync: this,
  )
    ..addListener(() {
      pController.update();
    })
    ..repeat();
}

void initParticleController() {
  pController.size = Size(300, 200);
  Particle particle = Particle(
     // 初始高度
     y: 0,
   // 初始速度
      vy: 0,
    // 由于地球加速度为9.8m/s,这里1s触发60次 所以要除以60.
       ay: 9.8 / 60,
       // 最大弹跳高度
      maxY: pController.size!.height,
      color: Colors.blue,
      size: 8);
  pController.p = particle;
}
 @override
  Widget build(BuildContext context) {
    return  CustomPaint(
      size: Size(double.infinity, double.infinity),
      painter: _BallMove(controller: pController),
    );
  }
}

创建画板

创建画板,绘制小球和辅助区域,小球圆心为粒子位移的距离。

class _BallMove extends CustomPainter {
  //
  final ParticleController controller;
  Paint ballPaint = Paint();
  Paint stokePaint = Paint()
    ..strokeWidth = 0.5
    ..style = PaintingStyle.stroke;

  // 实现super方法 实现刷新
  _BallMove({required this.controller}) : super(repaint: controller);

  @override
  void paint(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);
    canvas.save();
    canvas.translate(0, controller.size!.height / 2);
    // 小球运动区域
    canvas.drawRect(
        Rect.fromCenter(
            center: Offset.zero,
            width: controller.size!.width,
            height: controller.size!.height),
        stokePaint);
    canvas.restore();
    // 设置小球颜色
    ballPaint.color = controller.p.color;
    canvas.drawCircle(Offset(controller.p.x, controller.p.y),
        controller.p.size, ballPaint);

  }

  @override
  bool shouldRepaint(covariant _BallMove oldDelegate) {
    return false;
  }
}

效果:

这样就实现了小球自由落体弹跳效果,当然这只是理想的状态下的自由落体,真实状态下有很多因素的影响,像空气阻力、风等因素。上面只是实现了一个粒子的自由落体,加速度为地球重力加速度,多粒子运动原理一样。

多粒子实现八大行星加速度自由落体弹跳

修改粒子控制器增加粒子集合,实现多粒子运动,

// 粒子集合
List<Particle> particles = [];
void update() {
// 循环粒子集合
  particles.forEach(doUpdate);
  notifyListeners();
}
void doUpdate(Particle p) {
  // 一秒刷新60次
  // 距离= 时间 * 速度。
  // 自由落体 速度不断加快,地球加速度9.8/s
  // s = t * v;
  p.y  = p.vy;
  p.vy  = p.ay;
  if (p.y > size!.height) {
    p.maxY = p.maxY * 0.8;
    p.y = size!.height;
    // 假设能量损失 反弹速度为弹起的4/5
    p.vy = -p.vy * 0.8;
  }
  if (p.y < size!.height - p.maxY) {
    p.y = size!.height - p.maxY;
    p.vy = 0;
  }

  if (p.maxY < 0.01) {
    p.y = p.initY;
    p.maxY = size!.height;
  }
}

已知各大行星加速度为:

  • 水星:3.7m/s。 金星:8.87m/s。
  • 地球:9.8m/s。 火星:3.71m/s。
  • 木星:24.79m/s。 土星:10.44m/s。
  • 天王星:8.87m/s。 海王星:11.15m/s。

初始化八大行星集合。

void initParticleController() {
  pController.size = Size(300, 200);
  // 修改 ay为各大行星的加速度
  Particle particle1 = Particle(
      x: -140,
      ay: 3.7 / 60,
      maxY: pController.size!.height,
      color: Colors.green,
      size: 8);
  Particle particle2 = Particle(
      x: -100,
      ay: 8.87 / 60,
      maxY: pController.size!.height,
      color: Colors.yellow,
      size: 8);

  Particle particle3 = Particle(
      x: -60,
      ay: 9.8 / 60,
      maxY: pController.size!.height,
      color: Colors.blue,
      size: 8);

  Particle particle4 = Particle(
      x: -20,
      ay: 3.71 / 60,
      maxY: pController.size!.height,
      color: Colors.red,
      size: 8);

  Particle particle5 = Particle(
      x: 20,
      ay: 24.79 / 60,
      maxY: pController.size!.height,
      color: Colors.cyan,
      size: 8);
  Particle particle6 = Particle(
      x: 60,
      ay: 10.44 / 60,
      maxY: pController.size!.height,
      color: Colors.orangeAccent,
      size: 8);
  Particle particle7 = Particle(
      x: 100,
      ay: 8.87 / 60,
      maxY: pController.size!.height,
      color: Colors.blueGrey,
      size: 8);
  Particle particle8= Particle(
      x: 140,
      ay: 11.15/ 60,
      maxY: pController.size!.height,
      color: Colors.blueAccent,
      size: 8);

  pController.particles = [particle1,particle2,particle3,particle4,particle5,particle6,particle7,particle8,];
}

当然画板那里也需要修改为循环绘制粒子。

效果:

可以看到木星引力最强,最先停止,水星和火星的引力基本一致最弱,最后静止。

总结

粒子运动可以说是一种特殊的动画,通过特定的物理运动公式可以达到我们想要的运动轨迹,从而实现一些花里胡哨的动画效果,这里只是展示里其中的一种公式,例如一些抛物线运动、随机运动有兴趣的小伙伴可以试试,关键是修改粒子控制器的update方法,改变粒子的运动属性即可。

以上就是Android Flutter实现自由落体弹跳动画效果的详细内容,更多关于Android Flutter自由落体弹跳动画的资料请关注Devmax其它相关文章!

Android Flutter实现自由落体弹跳动画效果的更多相关文章

  1. Canvas实现贝赛尔曲线轨迹动画的示例代码

    这篇文章主要介绍了Canvas实现贝赛尔曲线轨迹动画的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. HTML5 直播疯狂点赞动画实现代码 附源码

    为了烘托直播间的氛围,直播相对于普通视频或者文本内容,点赞动作通常无限次,引导用户疯狂点赞,今天小编给大家分享HTML5 直播疯狂点赞动画实现代码 附源码,感兴趣的朋友一起看看吧

  3. CSS中实现动画效果-附案例

    这篇文章主要介绍了 CSS中实现动画效果并附上案例代码及实现效果,就是CSS动画样式处理,动画声明需要使用@keyframes name,后面的name是人为定义的动画名称,下面我们来看看文章的具体实现内容吧,需要的小伙伴可以参考一下

  4. 基于canvas的骨骼动画的示例代码

    这篇文章主要介绍了基于canvas的骨骼动画的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. html5如何在Canvas中实现自定义路径动画示例

    本篇文章主要介绍了html5如何在Canvas中实现自定义路径动画示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  6. html5 canvas合成海报所遇问题及解决方案总结

    这篇文章主要介绍了html5 canvas合成海报所遇问题及解决方案总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. 基于HTML5+Webkit实现树叶飘落动画

    本文给大家分享一段实例代码给大家介绍基于HTML5+Webkit实现树叶飘落动画效果,需要的朋友参考下吧

  8. Html5页面内使用JSON动画的实现

    这篇文章主要介绍了Html5页面内使用JSON动画的实现的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  9. html5实现图片转圈的动画效果——让页面动起来

    这篇文章主要介绍了html5实现图片转圈的动画效果——让页面动起来的相关资料,需要的朋友可以参考下

  10. Html5 video标签视频的最佳实践

    这篇文章主要介绍了Html5 video标签视频的最佳实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部