Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[Flutter] 端末を傾けてWidgetを動かす

beeeyan
June 07, 2024
76

[Flutter] 端末を傾けてWidgetを動かす

2024/6/7 FlutterKaigi mini in Osaka の発表資料

beeeyan

June 07, 2024
Tweet

Transcript

  1. 基本 @override void initState() { super.initState(); _streamSubscriptions .add( accelerometerEventStream ().listen(

    (AccelerometerEvent event) {} ), ); StatefulWidget initStateの中でlistenする
  2. Widgetの場所の指定 child: Stack( children: [ Positioned( left: widgetX, top: widgetY,

    Stack・Positionedを利用 ※ leftとtopが両方とも 0であれば左上の位置となる
  3. 定数を乗算 accelerometerEventStream().listen( (AccelerometerEvent event) { setState(() { accelX = event.x;

    accelY = event.y; if (!isPhysics) { // 新しい位置を計算 widgetX -= accelX * 20; widgetY += accelY * 20; // 画面外に出ないようにする if (widgetX < 0) { widgetX = 0; }         〜枠をはみ出ないようにするための制御〜 } });
  4. 等加速度運動 // 物理演算で計算するためにTimerで値を更新する。 // SensorInterval.normalIntervalの値で処理できたかも。 // デフォルトstatic const normalInterval =

    Duration(milliseconds: 200); _timer = Timer.periodic(Duration(milliseconds: timerMilliseconds), (Timer timer) { if (isPhysics) { final seconds = timerMilliseconds / 1000; // 速度の更新 velX -= accelX * seconds; velY += accelY * seconds; widgetX += velX * seconds + 1 / 2 * preAccelX * pow(seconds, 2); widgetY += velY * seconds + 1 / 2 * preAccelY * pow(seconds, 2); preAccelX = accelX; preAccelY = accelY;
  5. 反発係数 壁にぶつかった時、反発係数をかけて速度を反転させる。 if (widgetX < 0) { widgetX = 0;

    velX *= bounceFactor; preAccelX = 0; } if (widgetY < 0) { widgetY = 0; velY *= bounceFactor; preAccelY = 0; } bounceFactor自体がマイナス
  6. 回転 加速度から位相角を取得 final rotationAngle = atan2(accelY, accelX); Transform.rotateで回転状態を反映 child: Transform.rotate(

    angle: isRotate ? rotationAngle : 0, child: Container( height: boxSize, width: boxSize, decoration: BoxDecoration(
  7. 加速度センサーの反映 @override Future<void> onLoad() async { super.onLoad(); final viewWidth =

    size.x; final viewHeight = size.y - kBottomNavigationBarHeight - kToolbarHeight; ball = Ball(pos: Vector2(size.x / 2, size.y / 2)); add(ball!); accelerometerEventStream().listen((AccelerometerEvent event) { accelX = event.x; accelY = event.y; }); _timer = Timer.periodic(const Duration(milliseconds: 16), (Timer timer) { if (ball != null) { ball!.body.applyForce(Vector2(-accelX * 1000, accelY * 1000)); } }); onLoadの中で呼び出せる 物体に「applyForce」で影響を 与えることができる