java 小球運動軌跡_Flutter Matrix4矩陣影片實現移動、縮放、旋轉,讓你的紙飛機沿著貝茲曲線軌跡飛起來…

40fbe73ed4d535e653ade104ac16348a.png

用到的知識點Matrix4矩陣

貝茲曲線

第一步:畫出目標執行大致軌跡路線

首先我們先畫一條二階貝茲曲線,這樣我們能更直觀的觀察到目標移動的大致軌跡。我們先確定二階貝茲曲線的三個點:p0(開始點)、p1(控制點)、p2(結束點),像上圖的紅線軌跡,螢幕的中心點開始,到達螢幕的寬2/3的位置,那麼p0和p2的點就可以確定了:// 二階貝茲曲線 p0:開始點、p1:控制點、p2:結束點

Offset p0, p1, p2;

@override

Widget build(BuildContext context) {

Size _size = MediaQuery.of(context).size;

if (p0 == null) {

p0 = Offset(_size.width/2, _size.height/2);

p1 = Offset(_size.width+_size.width/4, _size.height/4);

p2 = Offset(_size.width*2/3, 0);

}

}

複製程式碼

得到二階貝茲曲線的三個點之後就可以用 CustomPaint 把它畫出來了,因為每次 setState 之後,build 會重新走一遍,所以我加了判斷讓它們只初始化一次就夠了。

第二步:放置紙飛機在螢幕的中心點

Flutter裡面使用矩陣是透過 Transform 這個 Widget 來設定的,Transform 有多個擴展建構方法,例如 Transform.rotate、Transform.translate、Transform.scale,有興趣的可以自己去了解一下,在這裡我們使用 Transform 預設的建構方法才能透過 Matrix4 來實現飛機的移動、縮放、旋轉。// 矩陣

Matrix4 _matrix4 = Matrix4.identity();

// 飛機尺寸

Size planeSize;

@override

Widget build(BuildContext context) {

Size _size = MediaQuery.of(context).size;

if (planeSize == null) {

planeSize = Size(_size.width/4, _size.width/4);

}

return Stack(

children: [

Container(

alignment: Alignment.center,

child: Transform(

transform: _matrix4,

child: SvgPicture.asset(Res.svg_paper_plane, width: planeSize.width, height: planeSize.height,),

),

),

],

);

}

複製程式碼

第三步:設定影片,透過影片計算飛機移動軌跡等

這一步最重要,涉及到移動軌跡、旋轉角度和縮放倍數的計算,這裡面涉及到一些計算,我直接把程式碼貼出來(PS:畢竟我數學太過垃圾,這一步花了我好多時間也沒能找到移動距離、縮放倍數、旋轉角度的最佳計算公式,只能自己一步一步慢慢調到大致的視覺效果)。// 移動軌跡點,即移動物的中心點

Offset bezierCenter;

// 當前移動距離

Offset transSize = Offset(0.0, 0.0);

/// 初始化影片

_initAnim() {

_animationController = AnimationController(duration: Duration(seconds: 3), vsync: this);

_animation = Tween(begin: 0.0, end: 1.0).animate(_animationController);

_animation.addListener(() {

// t 動態變化的值

var t = _animation.value;

if (mounted) {

setState(() {

_matrix4 = Matrix4.identity();

// 根據二階貝茲曲線計算移動軌跡點

double _left = pow(1 - t, 2) * p0.dx + 2 * t * (1 - t) * p1.dx + pow(t, 2) * p2.dx;

double _top = pow(1 - t, 2) * p0.dy + 2 * t * (1 - t) * p1.dy + pow(t, 2) * p2.dy;

// 設定移動

if (bezierCenter == null) {

transSize = Offset(0.0, 0.0);

} else {

transSize = Offset(transSize.dx - (bezierCenter.dx - _left),

transSize.dy - (bezierCenter.dy - _top));

}

_matrix4..translate(transSize.dx, transSize.dy, 0.0);

bezierCenter = Offset(_left, _top);

// 設定縮小倍數

_matrix4..scale((1-t) < 0.4 ? 0.4 : (1-t));

// 設定旋轉角度

double rotate = pi/2*t;

_matrix4..rotateX(rotate > rotate*0.8 ? rotate*0.8 : rotate);

_matrix4..rotateY(rotate > rotate*0.8 ? -rotate*0.8 : -rotate);

_matrix4..rotateZ(rotate > rotate*0.8 ? -rotate*0.8 : -rotate);

});

}

});

}

複製程式碼

最後附錄上完整程式碼(Github):PlaneFly