Android Flutter实现自由落体弹跳动画效果

目录
  • 粒子运动概念
  • 如何保持持续运动
  • 创建粒子对象
  • 创建粒子控制器
  • 初始化粒子
  • 创建画板
  • 多粒子实现八大行星加速度自由落体弹跳
  • 总结

粒子运动概念

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

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

如何保持持续运动

我们可以通过动画控制器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自由落体弹跳动画的资料请关注我们其它相关文章!

(0)

相关推荐

  • Flutter绘制3.4边形及多边形渐变动画实现示例

    目录 正文 绘制3.4边形 整数边形的绘制 分数边形的绘制 具体代码 效果改进1 效果改进2 正文 项目被优化了,人也跟着被优化了,正好趁这一个月整理整理关于flutter的一些东西. 绘制3.4边形 先看一下效果图: 起因是上上上上上个月浏览flutter的canvas相关内容时,点进去一个网站,看到一个让我眼前一亮的动效: 作者用的代码是swift的,我没细看,不过他文章里的一句话让我醍醐灌顶: That is, we want the shape be asked to draw mult

  • Android Flutter绘制有趣的 loading加载动画

    目录 前言 效果1:圆环内滚动的球 效果2:双轨运动 效果3:钟摆运动 总结 前言 在网络速度较慢的场景,一个有趣的加载会提高用户的耐心和对 App 的好感,有些 loading 动效甚至会让用户有想弄清楚整个动效过程到底是怎么样的冲动.然而,大部分的 App的 loading 就是下面这种千篇一律的效果 —— 俗称“转圈”. 本篇我们利用Flutter 的 PathMetric来玩几个有趣的 loading 效果. 效果1:圆环内滚动的球 如上图所示,一个红色的小球在蓝色的圆环内滚动,而且在往

  • 利用Flutter绘制出3D效果动画

    目录 前言 Path 的 transform 方法 绕任意点旋转 卡片3D 旋转实现 日历翻页效果 总结 前言 本篇我们继续介绍 Flutter 绘图的 Path 的应用.Flutter 的 Path 类提供了一个三维空间的变换方法,可以实现路径在三维空间的平移.旋转等操作,从而可以实现3D 绘制的效果.通过本篇你将了解到: Path的三维转换方法 transform 的使用. 绕三维空间某一点的旋转实现. 卡片3D 旋转动效. 类似日历的三维翻页效果. Path 的 transform 方法

  • Android实现左右摆动的球体动画效果

    首先,看一下效果 可能各位在别处看到过类似的东西,我在微信的文章末尾看到有个玩意,感觉有意思,就用代码实现一下.这篇文章主要把握写代码的思路展示一下. 看到上图,我想各位能想到最简单的实现方案就是用动画,切很多图出来,然后就可以轻松实现了.为了不让自己再舒适区里呆的太安逸,就弄点麻烦的:通过计算来实现.文章的末尾会将全部代码贴出,复制可以直接运行. 需要回忆的知识 重力势能 E = mgh 动能 E = ½mv² 在理想状态下,动能和重力式能可以相互转换,且能量守恒 如果不想太注意细节,以上的知

  • 利用Flutter实现“孔雀开屏”的动画效果

    前言 今天分享一个类似"孔雀开屏"的动画效果,打开新的页面时,新的页面从屏幕右上角以圆形逐渐打开到全屏. 先来看下具体的效果 不知道这种效果大家叫什么名字?如果有更合适的名字可以在评论处告诉我,下面来说下如何实现此效果. 在使用Navigator进入一个新的页面时,通常用法如下: Navigator.of(context).push(MaterialPageRoute( builder: (context){ return PageB(); } )); MaterialPageRout

  • Android仿支付宝的头部伸缩动画效果

    Android5.0推出的MaterialDesign库包含了处理头部工具栏的多个控件,不但允许自定义顶部导航栏,而且导航栏高度是可以伸缩的.如此一来,一方面导航栏能够放得下更多控件,另一方面在用户想看具体内容时也能腾出更多的屏幕空间. 这么说可能比较抽象,那就先来看看两张导航栏的效果图,第一张是导航栏完全展开时的界面,此时页面头部的导航栏占据了较大部分的高度: 第二张是导航栏完全收缩时的界面,此时头部导航栏只剩矮矮的一个长条. 看起来很眼熟是不是,上面的截图正是仿支付宝首页的头部效果.如果你熟

  • Android编程实现ImageView图片抛物线动画效果的方法

    本文实例讲述了Android编程实现ImageView图片抛物线动画效果的方法.分享给大家供大家参考,具体如下: 想实现抛物线动画,必须知道抛物线的方程,这时候数学其作用了,假如有如图的抛物线: 按照抛物线的方程特别,知道任何的三点可以确定一条抛物线,由已知抛物线的标注 方程为 y = ax² + bx + c:假设A1坐标为(0,0),A2坐标为(300,0),A3坐标为(150,300):联合解方程得知该抛物线的方程为 y = -1/75 x² + 4x:由此方程,我们可以确定抛物线x和y的

  • Android 自定义view实现水波纹动画效果

    在实际的开发中,很多时候还会遇到相对比较复杂的需求,比如产品妹纸或UI妹纸在哪看了个让人兴奋的效果,兴致高昂的来找你,看了之后目的很明确,当然就是希望你能给她: 在这样的关键时候,身子板就一定得硬了,可千万别说不行,爷们儿怎么能说不行呢: 好了,为了让大家都能给妹纸们想要的,后面会逐渐分享一些比较比较不错的效果,目的只有一个,通过自定义view实现我们所能实现的动效: 今天主要分享水波纹效果: 1.标准正余弦水波纹: 2.非标准圆形液柱水波纹: 虽说都是水波纹,但两者在实现上差异是比较大的,一个

  • Android编程之界面跳动提示动画效果实现方法

    本文实例讲述了Android编程之界面跳动提示动画效果实现方法.分享给大家供大家参考,具体如下: 上一个效果图: 先上布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" a

  • Android开发中MJRefresh自定义刷新动画效果

    [一]常见用法 最原始的用法,耦合度低,但是不能统一管理.我们需要在每一个控制器都写以下代码,很繁琐,以后项目修改起来更繁琐,得一个控制器一个控制器的去定位.修改. 1.1 使用默认刷新(耦合度底,但是想统一修改起来特别麻烦) self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ //在这里执行刷新操作 }]; self.tableView.mj_header = [MJRefreshNorm

  • Android仿硬币转动微信红包动画效果

    项目需要研究了一下微信红包动画,即硬币转动的效果,原理其实就是三张不同角度的图片利用AnimationDrawable帧动画进行播放,在参考了案例之后,给自己记录一下完成的过程. 1,在XML文件中定义动画: 步骤如下: ①新建 Android 项目 ②在drawable目录中新建一个anim.xml(注意文件名小写) <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:andr

  • android实现直播点赞飘心动画效果

    前段时间在写直播的时候,需要观众在看直播的时候点赞的效果,在此参照了腾讯大神写的点赞(飘心动画效果).下面是效果图: 1.自定义飘心动画的属性 在attrs.xml 中增加自定义的属性 <!-- 飘心动画自定义的属性 --> <declare-styleable name="HeartLayout"> <attr name="initX" format="dimension"/> <attr name=&

  • Android 开机充电图标和充电动画效果

    首先驱动需要先获取到2个power supply kernel\msm-3.18\drivers\usb\phy\phy-msm-usb.c motg->usb_psy.name = "usb"; motg->usb_psy.type = POWER_SUPPLY_TYPE_USB; motg->usb_psy.supplied_to = otg_pm_power_supplied_to; motg->usb_psy.num_supplicants = ARRA

随机推荐