particles.dart

// Adapted from https://github.com/nhancv/nc_flutter_util import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter/animation.dart'; import 'package:flutter/material.dart'; main() { runApp(new MaterialApp( home: new DemoPage(), )); } class DemoPage extends StatelessWidget { @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); return new Scaffold( body: new DemoBody( screenSize: MediaQuery.of(context).size, ), ); } } class DemoBody extends StatefulWidget { final Size screenSize; DemoBody({Key key, @required this.screenSize}) : super(key: key); @override State<StatefulWidget> createState() { return new _DemoBodyState(); } } class _DemoBodyState extends State<DemoBody> with TickerProviderStateMixin { AnimationController animationController; final nodeList = <Node>[]; final numNodes = 20; @override void initState() { super.initState(); Iterable.generate(numNodes).forEach( (i) => nodeList.add(new Node(id: i, screenSize: widget.screenSize))); animationController = new AnimationController( vsync: this, duration: new Duration(seconds: 10)) ..addListener(() { for (int x = 0; x < nodeList.length; x++) { nodeList[x].move(); for (int y = x + 1; y < nodeList.length; y++) { nodeList[x].connect(nodeList[y]); } } }) ..repeat(); } @override Widget build(BuildContext context) { return new Container( child: new AnimatedBuilder( animation: animationController, builder: (context, child) => new CustomPaint( size: widget.screenSize, painter: new _DemoPainter(widget.screenSize, nodeList), ), ), ); } } class _DemoPainter extends CustomPainter { final List<Node> nodeList; final Size screenSize; var counter = 0; _DemoPainter(this.screenSize, this.nodeList); @override void paint(Canvas canvas, Size size) { for (var node in nodeList) { node.display(canvas); } } @override bool shouldRepaint(_DemoPainter oldDelegate) => true; } enum Direction { LEFT, RIGHT, TOP, BOTTOM, TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT } class Node { int id; Size screenSize; double radius; double size; Offset position; Direction direction; Random random; Paint notePaint, linePaint; Map<int, Node> connected; Node( {@required this.id, this.size = 5.0, this.radius = 200.0, @required this.screenSize}) { random = new Random(); connected = new Map(); position = screenSize.center(Offset.zero); direction = Direction.values[random.nextInt(Direction.values.length)]; notePaint = new Paint() ..color = Colors.orange ..strokeWidth = 1.0 ..style = PaintingStyle.fill; linePaint = new Paint() ..color = Colors.orange ..strokeWidth = 0.5 ..style = PaintingStyle.stroke; } void move() { switch (direction) { case Direction.LEFT: position -= new Offset(1.0, 0.0); if (position.dx <= 5.0) { List<Direction> dirAvailableList = [ Direction.RIGHT, Direction.BOTTOM_RIGHT, Direction.TOP_RIGHT ]; direction = dirAvailableList[random.nextInt(dirAvailableList.length)]; } break; case Direction.RIGHT: position += new Offset(1.0, 0.0); if (position.dx >= screenSize.width - 5.0) { List<Direction> dirAvailableList = [ Direction.LEFT, Direction.BOTTOM_LEFT, Direction.TOP_LEFT ]; direction = dirAvailableList[random.nextInt(dirAvailableList.length)]; } break; case Direction.TOP: position -= new Offset(0.0, 1.0); if (position.dy <= 5.0) { List<Direction> dirAvailableList = [ Direction.BOTTOM, Direction.BOTTOM_LEFT, Direction.BOTTOM_RIGHT ]; direction = dirAvailableList[random.nextInt(dirAvailableList.length)]; } break; case Direction.BOTTOM: position += new Offset(0.0, 1.0); if (position.dy >= screenSize.height - 5.0) { List<Direction> dirAvailableList = [ Direction.TOP, Direction.TOP_LEFT, Direction.TOP_RIGHT, ]; direction = dirAvailableList[random.nextInt(dirAvailableList.length)]; } break; case Direction.TOP_LEFT: position -= new Offset(1.0, 1.0); if (position.dx <= 5.0 || position.dy <= 5.0) { List<Direction> dirAvailableList = [ Direction.BOTTOM_RIGHT, ]; //if y invalid and x valid if (position.dy <= 5.0 && position.dx > 5.0) { dirAvailableList.add(Direction.LEFT); dirAvailableList.add(Direction.RIGHT); dirAvailableList.add(Direction.BOTTOM); dirAvailableList.add(Direction.BOTTOM_LEFT); } //if x invalid and y valid if (position.dx <= 5.0 && position.dy > 5.0) { dirAvailableList.add(Direction.TOP); dirAvailableList.add(Direction.RIGHT); dirAvailableList.add(Direction.BOTTOM); dirAvailableList.add(Direction.TOP_RIGHT); } direction = dirAvailableList[random.nextInt(dirAvailableList.length)]; } break; case Direction.TOP_RIGHT: position -= new Offset(-1.0, 1.0); if (position.dx >= screenSize.width - 5.0 || position.dy <= 5.0) { List<Direction> dirAvailableList = [ Direction.BOTTOM_LEFT, ]; //if y invalid and x valid if (position.dy <= 5.0 && position.dx < screenSize.width - 5.0) { dirAvailableList.add(Direction.LEFT); dirAvailableList.add(Direction.RIGHT); dirAvailableList.add(Direction.BOTTOM); dirAvailableList.add(Direction.BOTTOM_RIGHT); } //if x invalid and y valid if (position.dx >= screenSize.width - 5.0 && position.dy > 5.0) { dirAvailableList.add(Direction.TOP); dirAvailableList.add(Direction.BOTTOM); dirAvailableList.add(Direction.LEFT); dirAvailableList.add(Direction.TOP_LEFT); } direction = dirAvailableList[random.nextInt(dirAvailableList.length)]; } break; case Direction.BOTTOM_LEFT: position -= new Offset(1.0, -1.0); if (position.dx <= 5.0 || position.dy >= screenSize.height - 5.0) { List<Direction> dirAvailableList = [ Direction.TOP_RIGHT, ]; //if y invalid and x valid if (position.dy >= screenSize.height - 5.0 && position.dx > 5.0) { dirAvailableList.add(Direction.LEFT); dirAvailableList.add(Direction.RIGHT); dirAvailableList.add(Direction.TOP); dirAvailableList.add(Direction.TOP_LEFT); } //if x invalid and y valid if (position.dx <= 5.0 && position.dy < screenSize.height - 5.0) { dirAvailableList.add(Direction.TOP); dirAvailableList.add(Direction.BOTTOM); dirAvailableList.add(Direction.RIGHT); dirAvailableList.add(Direction.BOTTOM_RIGHT); } direction = dirAvailableList[random.nextInt(dirAvailableList.length)]; } break; case Direction.BOTTOM_RIGHT: position += new Offset(1.0, 1.0); if (position.dx >= screenSize.width - 5.0 || position.dy >= screenSize.height - 5.0) { List<Direction> dirAvailableList = [ Direction.TOP_LEFT, ]; //if y invalid and x valid if (position.dy >= screenSize.height - 5.0 && position.dx < screenSize.width - 5.0) { dirAvailableList.add(Direction.LEFT); dirAvailableList.add(Direction.RIGHT); dirAvailableList.add(Direction.TOP); dirAvailableList.add(Direction.TOP_RIGHT); } //if x invalid and y valid if (position.dx >= screenSize.width - 5.0 && position.dy < screenSize.height - 5.0) { dirAvailableList.add(Direction.TOP); dirAvailableList.add(Direction.BOTTOM); dirAvailableList.add(Direction.LEFT); dirAvailableList.add(Direction.BOTTOM_LEFT); } direction = dirAvailableList[random.nextInt(dirAvailableList.length)]; } break; } } bool canConnect(Node node) { double x = node.position.dx - position.dx; double y = node.position.dy - position.dy; double d = x * x + y * y; return d <= radius * radius; } void connect(Node node) { if (canConnect(node)) { if (!node.connected.containsKey(id)) { connected.putIfAbsent(node.id, () => node); } } else if (connected.containsKey(node.id)) { connected.remove(node.id); } } void display(Canvas canvas) { canvas.drawCircle(position, size, notePaint); connected.forEach((id, node) { canvas.drawLine(position, node.position, linePaint); }); } bool operator ==(o) => o is Node && o.id == id; int get hashCode => id; }
Demonstrates drawing and animating simple shapes in Flutter

Be the first to comment

You can use [html][/html], [css][/css], [php][/php] and more to embed the code. Urls are automatically hyperlinked. Line breaks and paragraphs are automatically generated.