日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Android?Flutter實現自由落體彈跳動畫效果_Android

作者:老李code ? 更新時間: 2022-12-02 編程語言

粒子運動概念

粒子運動是將對象按照一定物理公式進行的自定義軌跡運動,與普通動畫不同的是,它沒有強制性的動畫開始到結束的時間概念,因為粒子的運動開始到結束的時間并不是固定的,而是由具體場景的物理運動公式來決定的,什么時候結束由你來定,例如:小球自由落體彈跳動畫松開小球開始到地面停止的時間就跟距離地面初始高度有關,初始高度越高,動畫時間越長,反之依然,所以,粒子運動可以說是符合物理公式并持續不斷的動畫。

粒子運動特點:符合物理運動公式、持續不斷運動。

如何保持持續運動?

我們可以通過動畫控制器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方法,改變粒子的運動屬性即可。

原文鏈接:https://juejin.cn/post/7158850965116813320

欄目分類
最近更新