2

I am making a game with flutter and found this problem. While animation starts and ends correctly, everything in between that is a miss as you can see here.

It starts going down (Because of the first vector in the matrix) but even if I put first vector exactly the same then matrix animation won't do anything but just appear after the animation has ended in a new state.

Code for state (I removed everything I think is unnecessary but if you need more info I can paste whole class)

  class _GameState extends State<GameWindow> with TickerProviderStateMixin{
      static Matrix4 originalTransformation = new Matrix4.compose(
          new vector.Vector3(1.0, 1.0, 1.0),
          new vector.Quaternion.euler(0.0, 0.0, 0.0),
          new vector.Vector3(1.0, 1.0, 1.0));

      static Matrix4 animatedTransformation = new Matrix4.compose(
          new vector.Vector3(5.0, 260.0, 1.0),
          new vector.Quaternion.euler(0.0, 1.0, -0.7),
          new vector.Vector3(0.6, 0.6, 0.6));

      Matrix4 currentMatrix = originalTransformation;

      @override
      Widget build(BuildContext context){
          return new Scaffold(
              body: new Column(
                  mainAxisSize: MainAxisSize.max,
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: [
                      new Container(
                          // Applying default transformation matrix
                          transform: currentMatrix,
                          child: _buildSquares(), // Builds GridView with custom squares
                      ),
                      _getFooter(), // Footer
                  ],
              ),
          );
      }


      @override
      void initState(){
          // Init animation tween
          animationTween = new Matrix4Tween(
              begin: originalTransformation,
              end: animatedTransformation
          );

          // Init animation controller
          animationController = new AnimationController(
              vsync: this,
              duration: new Duration(milliseconds: 800),
          )..addListener((){
              this.setState((){
                  currentMatrix = animationTween.evaluate(animationController);
              });
          });
      }

      _clickListener(){
          // Trigger animation
          animationController.forward(from: 0.0);

          if(_squares[_currentSquareIndex].state.isClicked()){
              _increaseScore();
          }else{
              _showGameOver();
          }
      }
  }

So after on click animation obviously starts and a matrix is changing but not in a smooth way. Any ideas why? Did I miss something?

Working example with one square:

import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as vector;

void main() {
    runApp(new MyApp());
}

class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
        return new MaterialApp(
            title: 'Flutter Demo',
            theme: new ThemeData(
                primarySwatch: Colors.blue,
            ),
            home: new MyHomePage(),
        );
    }
}

class MyHomePage extends StatefulWidget {
    MyHomePage({Key key}) : super(key: key);

    @override
    _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin{
    static Matrix4 originalTransformation = new Matrix4.compose(
            new vector.Vector3(1.0, 1.0, 1.0),
            new vector.Quaternion.euler(0.0, 0.0, 0.0),
            new vector.Vector3(1.0, 1.0, 1.0));

    static Matrix4 animatedTransformation = new Matrix4.compose(
            new vector.Vector3(5.0, 260.0, 1.0),
            new vector.Quaternion.euler(0.0, 1.0, -0.7),
            new vector.Vector3(0.6, 0.6, 0.6));

    Matrix4 currentMatrix = originalTransformation;
    AnimationController animationController;
    Matrix4Tween animationTween;

    @override
    Widget build(BuildContext context) {
        return new Scaffold(
            resizeToAvoidBottomPadding: true,
            body: new Column(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                    new AnimatedBuilder(
                        // Pass animation controller
                        animation: animationController,
                        builder: (BuildContext context, Widget child) => new Container(
                            // Apply transformation
                            transform: animationTween.evaluate(animationController),
                            child: child,
                        ),
                        // Passing child argument
                        child: new GestureDetector(
                            onTap: _onClick,
                            child: new Container(
                                height: 400.0,
                                width: 400.0,
                                color: Colors.red,
                            ),
                        ),
                    ),
                ],
            ),
        );
    }

    _onClick() {
        // Start animation
        animationController.forward(from: 0.0);
        return;
    }

    @override
    void initState() {
        super.initState();

        // Init tween for matrix
        animationTween = new Matrix4Tween(
                begin: originalTransformation,
                end: animatedTransformation
        );

        // Init animation controller
        animationController = new AnimationController(
            vsync: this,
            duration: new Duration(milliseconds: 800),
        );
    }
}

Edit: I tried removing listener and passing animation to AnimatedBuilder like this but that did not work either.

Edit 2: Added working example of this with one square.

knezzz
  • 683
  • 5
  • 14
  • I'm having trouble understanding of what the problem is because your one-square working example seems to behave as intended, and I don't have runnable code for something that doesn't behave as intended. – Collin Jackson Jun 29 '17 at 16:10
  • For me, all 3 samples work the same like [this](https://i.stack.imgur.com/lmuOj.gif) but I was hoping for smoother transition something like [this](https://i.imgur.com/PBxkWMZ.gif). And like I said even If I equalize the first vector on both matrices then view does not sink but, I don't see scaling or rotation animation taking place at all it just snaps to position of 2nd matrix – knezzz Jun 29 '17 at 16:25

1 Answers1

3

Pass your Animation to an AnimatedBuilder instead of calling addListener. This reduces the amount of private state you're carrying around and allows you to use the result of _buildSquares() as the child argument so you aren't recomputing everything on every frame when the animation ticks. It should improve animation smoothness.

Edit: Added a working code sample below.

Edit 2: It sounds like you're running into a bug that I'm not experiencing, so please file an issue.

Edit 3: It sounds like the issue has been fixed already on master.

import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as vector;

class HomeScreen extends StatefulWidget {
  HomeScreenState createState() => new HomeScreenState();
}

class HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {

  AnimationController _controller;

  @override initState() {
    _controller = new AnimationController(
      vsync: this, duration: const Duration(milliseconds: 300));
  }

  static Matrix4 originalTransformation = new Matrix4.compose(
    new vector.Vector3(1.0, 1.0, 1.0),
    new vector.Quaternion.euler(0.0, 0.0, 0.0),
    new vector.Vector3(1.0, 1.0, 1.0));

  static Matrix4 animatedTransformation = new Matrix4.compose(
    new vector.Vector3(5.0, 260.0, 1.0),
    new vector.Quaternion.euler(0.0, 1.0, -0.7),
    new vector.Vector3(0.6, 0.6, 0.6));


  Widget build(BuildContext context) {
    return new Scaffold(
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.play_arrow),
        onPressed: () => _controller.forward(from: 0.0),
      ),
      body: new Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          new AnimatedBuilder(
            builder: (BuildContext context, Widget child) {
              return new Container(
                color: Colors.red,
                width: 100.0,
                height: 100.0,
                transform: new Matrix4Tween(
                  begin: originalTransformation,
                  end: animatedTransformation
                ).evaluate(_controller)
              );
            },
            animation: _controller,
          ),
        ],
      ),
    );
  }
}

class ExampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      theme: new ThemeData(
        primarySwatch: Colors.teal,
      ),
      home: new HomeScreen(),
      debugShowCheckedModeBanner: false,
    );
  }
}

void main() {
  runApp(new ExampleApp());
}
Collin Jackson
  • 110,240
  • 31
  • 221
  • 152
  • I tried that right now, and while animation does feel smoother it's still doing the same thing. Just to verify this is what you had in mind: Edit: I don't know how to markdown code here I will edit my question. I will try to replace all my animations with builder maybe that will help? – knezzz Jun 29 '17 at 15:38
  • Consider updating your question with a complete, runnable example. it will make it easier to understand what you're talking about. – Collin Jackson Jun 29 '17 at 15:41
  • Ok, I will. But basically, it seems like matrix rotation and scale are not being animated – knezzz Jun 29 '17 at 15:45
  • I've added my code and I've tried yours but, it still behaves the same. Goes down a bit and then jumps to the 2nd matrix. Pretty much same as gif from the question but with the whole screen. – knezzz Jun 29 '17 at 16:09
  • It's working fine for me, what platform are you running on? – Collin Jackson Jun 29 '17 at 16:19
  • (I'm testing on the ios simulator) – Collin Jackson Jun 29 '17 at 16:25
  • Oh yeah, I should've said that. I'm using Android devices (S7 Edge and Nexus 5) – knezzz Jun 29 '17 at 16:27
  • I just tried with iOS emulator (iP7+) and I still don't see any rotation or scaling taking place during the animation, just the translation is moving. – knezzz Jun 29 '17 at 16:36
  • This is what I see when I run your example on the iOS emulator (iP7+). It seems to be rotating and scaling! https://i.stack.imgur.com/y1d6V.gif The behavior you're seeing sounds like a bug, so please file an issue and include your `flutter doctor` results: https://github.com/flutter/flutter/issues/new – Collin Jackson Jun 29 '17 at 16:48
  • Ohh yeah that's not what I see at all. Ok I will do that :) – knezzz Jun 29 '17 at 16:52