美文网首页
【游戏开发】飘雪花效果

【游戏开发】飘雪花效果

作者: 24c41111e47b | 来源:发表于2024-07-15 19:03 被阅读0次

游戏获胜后,天空飘落的彩带雪花效果实现。


使用示例:

Visibility(
       visible: !_duringCelebration, // 是否展示
       child: IgnorePointer(
                child: Confetti(isStopped: false, // 是否停止播放
          ),
      ),
  )

雪花代码:

// Copyright 2022, the Flutter project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:collection';
import 'dart:math';

import 'package:flutter/widgets.dart';

/// Shows a confetti (celebratory) animation: paper snippings falling down.
///
/// The widget fills the available space (like [SizedBox.expand] would).
///
/// When [isStopped] is `true`, the animation will not run. This is useful
/// when the widget is not visible yet, for example. Provide [colors]
/// to make the animation look good in context.
///
/// This is a partial port of this CodePen by Hemn Chawroka:
/// https://codepen.io/iprodev/pen/azpWBr
class Confetti extends StatefulWidget {
  static const _defaultColors = [
    Color(0xffd10841),
    Color(0xff1d75fb),
    Color(0xff0050bc),
    Color(0xffa2dcc7),
  ];

  final bool isStopped;

  final List<Color> colors;

  const Confetti({
    this.colors = _defaultColors,
    this.isStopped = false,
    super.key,
  });

  @override
  State<Confetti> createState() => _ConfettiState();
}

class ConfettiPainter extends CustomPainter {
  final defaultPaint = Paint();

  final int snippingsCount = 200;

  late final List<_PaperSnipping> _snippings;

  Size? _size;

  DateTime _lastTime = DateTime.now();

  final UnmodifiableListView<Color> colors;

  ConfettiPainter(
      {required Listenable animation, required Iterable<Color> colors})
      : colors = UnmodifiableListView(colors),
        super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    if (_size == null) {
      // First time we have a size.
      _snippings = List.generate(
          snippingsCount,
          (i) => _PaperSnipping(
                frontColor: colors[i % colors.length],
                bounds: size,
              ));
    }

    final didResize = _size != null && _size != size;
    final now = DateTime.now();
    final dt = now.difference(_lastTime);
    for (final snipping in _snippings) {
      if (didResize) {
        snipping.updateBounds(size);
      }
      snipping.update(dt.inMilliseconds / 1000);
      snipping.draw(canvas);
    }

    _size = size;
    _lastTime = now;
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

class _ConfettiState extends State<Confetti>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: ConfettiPainter(
        colors: widget.colors,
        animation: _controller,
      ),
      willChange: true,
      child: const SizedBox.expand(),
    );
  }

  @override
  void didUpdateWidget(covariant Confetti oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.isStopped && !widget.isStopped) {
      _controller.repeat();
    } else if (!oldWidget.isStopped && widget.isStopped) {
      _controller.stop(canceled: false);
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      // We don't really care about the duration, since we're going to
      // use the controller on loop anyway.
      duration: const Duration(seconds: 1),
      vsync: this,
    );

    if (!widget.isStopped) {
      _controller.repeat();
    }
  }
}

class _PaperSnipping {
  static final Random _random = Random();

  static const degToRad = pi / 180;

  static const backSideBlend = Color(0x70EEEEEE);

  Size _bounds;

  late final _Vector position = _Vector(
    _random.nextDouble() * _bounds.width,
    _random.nextDouble() * _bounds.height,
  );

  final double rotationSpeed = 800 + _random.nextDouble() * 600;

  final double angle = _random.nextDouble() * 360 * degToRad;

  double rotation = _random.nextDouble() * 360 * degToRad;

  double cosA = 1.0;

  final double size = 7.0;

  final double oscillationSpeed = 0.5 + _random.nextDouble() * 1.5;

  final double xSpeed = 40;

  final double ySpeed = 50 + _random.nextDouble() * 60;

  late List<_Vector> corners = List.generate(4, (i) {
    final angle = this.angle + degToRad * (45 + i * 90);
    return _Vector(cos(angle), sin(angle));
  });

  double time = _random.nextDouble();

  final Color frontColor;

  late final Color backColor = Color.alphaBlend(backSideBlend, frontColor);

  final paint = Paint()..style = PaintingStyle.fill;

  _PaperSnipping({
    required this.frontColor,
    required Size bounds,
  }) : _bounds = bounds;

  void draw(Canvas canvas) {
    if (cosA > 0) {
      paint.color = frontColor;
    } else {
      paint.color = backColor;
    }

    final path = Path()
      ..addPolygon(
        List.generate(
            4,
            (index) => Offset(
                  position.x + corners[index].x * size,
                  position.y + corners[index].y * size * cosA,
                )),
        true,
      );
    canvas.drawPath(path, paint);
  }

  void update(double dt) {
    time += dt;
    rotation += rotationSpeed * dt;
    cosA = cos(degToRad * rotation);
    position.x += cos(time * oscillationSpeed) * xSpeed * dt;
    position.y += ySpeed * dt;
    if (position.y > _bounds.height) {
      // Move the snipping back to the top.
      position.x = _random.nextDouble() * _bounds.width;
      position.y = 0;
    }
  }

  void updateBounds(Size newBounds) {
    if (!newBounds.contains(Offset(position.x, position.y))) {
      position.x = _random.nextDouble() * newBounds.width;
      position.y = _random.nextDouble() * newBounds.height;
    }
    _bounds = newBounds;
  }
}

class _Vector {
  double x, y;
  _Vector(this.x, this.y);
}

相关文章

  • 亲子游戏(13)雪花飘

    适合年龄段:5——12岁 游戏作用:让紧张的孩子放松,释放情绪,扩大孩子的违规界限,促进亲子间的情感链接 所需材料...

  • 雪花飘,雪花飘。 挑到东来飘到西。 雪花飘,雪花飘。 雪人雪仗少不了。 雪花飘,雪花飘。 你若一来人欢呼。

  • 雪花飘

    作者 肖佩云 雪花飘 飘在幽深的山谷 没有人看到她的落寞 雪花飘 飘在城市的上空 没有人注意到她的孤单 雪花飘 ...

  • 雪花飘

    昨天天立冬,今天家乡迎来了第一场雪。似乎穿着一件卫衣走在街上的时间结束了,天渐渐转凉了,外面的雪花还在飘着...

  • 雪花飘

    寒风就像一位年老的渔翁, 向北方撒下无尽的冷意。 你不知道他什么时候收网, 你也不知道他什么时候回家, 你只知道每...

  • 雪花飘

    这几日阴冷的感觉让我不情愿,更是天天盼晴天,盼望能见到阳光,在寒冷的冬季有一丝温暖。 一个上午都是阴天,下午却飘起...

  • 雪花飘……

    夜晚,飘飘洒洒的雪花,带着久别重逢的纯美,邂逅大地温暖的怀抱…… 这是入冬以来的第二场大雪,如同一张洁...

  • 雪花飘

    雪花漫天飞舞,那么的自由,那样的纯洁,有节奏的,轻盈的,那样的美是我们要用心去感受的大自然赋予人类的一切美好。 我...

  • 雪花飘

    满天的情为谁飘 我伸出手 将你捧在手心 我心由此白 不论你落在何地 光明依旧在 你来与不来 都是爱 你见与不见 情依旧开

  • 雪花飘

    文/星拾 那是一个不下雪的早晨 冬日的冷 包裹在山间 电桩上也是冰 南方的雪 很小 在那个小院里 小女孩 转着圈 ...

网友评论

      本文标题:【游戏开发】飘雪花效果

      本文链接:https://www.haomeiwen.com/subject/bhbhhjtx.html