Flutter efficient way to implement drawing game like pictionary using custompainter

258

A solution might be to "stream" pictures of the canvas, kind of like a video. Did you already try the painter package ? It can help you do just that and improve the drawing experience.

Share:
258
tanweer anwar
Author by

tanweer anwar

Updated on December 26, 2022

Comments

  • tanweer anwar
    tanweer anwar over 1 year

    I am trying to build a drawing game like pictionary in flutter where one user will draw an object on the screen while other users can see the drawing in realtime on their devices. My idea was to draw on a canvas using custom painter and while user is drawing emit events using websocket sending points to the other users who are watching. And draw the received points on their screen as well.

    But the issue I am facing is that drawing using custom painter canvas.drawlines() is pretty inefficient and starts lagging after sometime. Main issue I noticed is that whenever a new point is added to canvas, custom painter redraws all the points again. So if there are at least 1000 points on the canvas, performance is going to take a serious hit.

    I tried provider and notifyListeners() instead of setState() which improved the performance little bit but then again when I emit event using websocket with huge list of points, app become unusable and framerate drops below 10fps.

    What I want to know is that is it possible use custompainter in a way that it draws on the newly added points and does not redraws the whole canvas. If that is possible, then I would be able to get away by emitting only the new points to all the watchers.

    If behaviour is not possible, is there a efficient the whole workflow in flutter using custompainter and websockets.

    Here is my SketchPainter class

    class SketchPainter extends CustomPainter {
      final List<Point> offsets;
      final double strokeWidth;
      final Color strokeColor;
      SketchPainter({@required this.offsets, @required this.strokeWidth, @required this.strokeColor});
    
    
      @override
      void paint(Canvas canvas, Size size) {
        Paint paint = Paint()
        ..isAntiAlias = true;
        for(int i = 0; i < offsets.length - 1; i++) {
          if(offsets[i] != null){
            paint.color = offsets[i].color;
            paint.strokeWidth = offsets[i].width;
          }
          if(offsets[i] != null && offsets[i + 1] != null) {
            canvas.drawLine(offsets[i].offset, offsets[i+1].offset, paint);
          }
          if(offsets[i] != null && offsets[i + 1] == null) {
            canvas.drawPoints(PointMode.points, [offsets[i].offset], paint);
          }
        }
      }
    
      @override
      bool shouldRepaint(SketchPainter oldDelegate) {
        return true;
      }
    }
    

    And here is my Point class

    class Point {
      Offset offset;
      Color color;
      double width;
      Point({this.offset, this.color, this.width});
    }
    
  • tanweer anwar
    tanweer anwar over 3 years
    Thank you for pointing me to the painter package. I could take inspiration from this package to improve performance even further. But I think streaming pictures of the canvas can become resource consuming very quickly for both clients and the server. Emitting only the new points on the canvas would be much more efficient. Is there any other suggestion apart from this one??
  • MickaelHrndz
    MickaelHrndz over 3 years
    Try that then, but I don't think representing a drawing with points is very efficient (hence the frame drops >1000). Also, I don't think there's a way not to render the whole canvas with the paint() function, that's just how it works.