[Dragon Boat Festival] Have you ever seen a talking dumpling?

I am participating in the "Early Summer Creative Contest" for details, please see: Early Summer Creative Contest .

foreword

Hello everyone, the Dragon Boat Festival is approaching. First of all, I wish the Nuggets a healthy Dragon Boat Festival in advance. As a very important traditional festival of the Chinese nation, the Dragon Boat Festival is indispensable, but do you really know the history of the dumpling? Follow this article today to Flutter pathdraw a zongzi that will be popular for popular science festivals~

draw

1. Basic outline

First of all, we need to draw the basic outline of the zongzi. From the picture, we can see that the outline of the zongzi is a round triangle shape.
All the graphics in this article are made with pure Pathpaths. Here we can divide the outline of the zongzi into three parts. A second-level Bezier curve is used to draw, the outline of the head, left and right leaves. Core code:


canvas.translate(size.width / 2, size.height / 2);
canvas.translate(-50, -50);
Paint paint = Paint()
  ..style = PaintingStyle.stroke
  ..strokeWidth = 2
  ..color = Colors.black
  ..isAntiAlias = true;

Path path = Path();
path.relativeQuadraticBezierTo(50, -80, 100, 0);
path.relativeQuadraticBezierTo(90, 130, -50, 130);
path.relativeQuadraticBezierTo(-140, 0, -50, -130);
path.close();
canvas.drawPath(path, paint);
复制代码

Effect picture:
image.png

2. Dumpling leaves

With the basic outline, we need to draw the zongye leaves. You can see that the shape of the zongzi leaves is an irregular shape. Here, you can use the Path path to combine the two paths to generate a new path, so that we can get the left zongzi. Leaf area, core code:

Path path2 = Path();
path2.relativeQuadraticBezierTo(60, 100, 190, 130);
path2.relativeLineTo(0, 40);
path2.relativeLineTo(-260, 0);
path2.relativeLineTo(0, -200);
path2.close();

canvas.drawPath(
   path2,
   paint
     ..color = Color(0xFF2A9200));
复制代码

Effect picture:
image.png

Then use the path joint to take the intersection of these two areas to get the area on the left side of the zongye.
Core code:

Path pathStart = Path.combine(PathOperation.intersect, path, path2);
pathStart.close();

canvas.drawPath(
   pathStart,
   paint
     ..color = Color(0xFF2A9200)
     ..style = PaintingStyle.fill);
复制代码

Effect picture:
image.png

After we have the area, we need to have more textures, which look more like zongye leaves. We continue to use path union here. We only need to offset the new path we synthesized above to the lower left several times. Core code:

_canvasStartLines(Canvas canvas, Path pathStart, Paint paint) {
  for (int i = 1; i < 10; i++) {
    Path path = Path();
    path.moveTo(-8 * i.toDouble(), 8 * i.toDouble());
    path.relativeQuadraticBezierTo(60, 100, 190, 130);
    path.relativeLineTo(0, 60);
    path.relativeLineTo(-300, 0);
    path.relativeLineTo(0, -200);
    path.close();
    canvas.drawPath(
        Path.combine(PathOperation.intersect, pathStart, path),
        paint
          ..color = Colors.black
          ..style = PaintingStyle.stroke);
  }
}
复制代码

Effect picture:
image.png

Next, the same is true for the leaves on the right: the core code
will not be posted here. For those who want to see it, please refer to the demo, the address is at the bottom, and it has been uploaded to github.

Effect picture:
image.png

The dumpling leaves are almost done.

mouth

For the mouth, we use a third-order Bezier curve to draw a happy expression.
Core code:

Path path4 = Path();
path4.moveTo(40, 20);
path4.relativeCubicTo(2, 18, 18, 18, 20, 0);
path4.close();
canvas.drawPath(path4, paint..color = Colors.black87);
复制代码

Effect picture:
image.png

Eye

We also use two third-order Bezier curves for the eyes, looking happy.

/// 眼睛
Path path5 = Path();
path5.moveTo(20, 5);
path5.relativeCubicTo(5, -10, 15, -10, 20, 0);
canvas.drawPath(
    path5,
    paint
      ..color = Colors.black87
      ..style = PaintingStyle.stroke);
canvas.save();
canvas.translate(40, 0);
canvas.drawPath(
    path5,
    paint
      ..color = Colors.black87
      ..style = PaintingStyle.stroke);
canvas.restore();
复制代码

Effect picture:
image.png

blush

接下来给面部设置下肤色,然后添加一点点细节。这里我们给path路径添加一个椭圆点缀那么一下。 核心代码:

/// 晒红
Path path9 = Path();
path9.addArc(Rect.fromCenter(center: Offset(30,30), width: 4, height: 6),0,pi*2);
canvas.drawPath(path9, paint..color = Color(0xFFFFA2AE)..style = PaintingStyle.fill);
canvas.save();
canvas.translate(6, 0);
canvas.drawPath(path9, paint..color = Color(0xFFFFA2AE)..style = PaintingStyle.fill);
canvas.restore();
canvas.save();
canvas.translate(34, 0);
canvas.drawPath(path9, paint..color = Color(0xFFFFA2AE)..style = PaintingStyle.fill);
canvas.restore();
canvas.save();
canvas.translate(40, 0);
canvas.drawPath(path9, paint..color = Color(0xFFFFA2AE)..style = PaintingStyle.fill);
canvas.restore();
复制代码

效果图:
image.png

手&脚

看着光溜溜的没有手脚怎么行,接下来我们继续使用path路径给粽子添加手脚,这里有一个知识点就是我们需要找到手脚的位置坐标在哪,就需要使用到 path的路径测量 ,根据路径上的点找到我们合适的手脚位置。
通过path.computeMetrics()我们可以得到一个路径的迭代对象PathMetric() ,这个迭代对象里面包含这个路径所有图形的很多信息,我们都可以从这个对象得到,这里我们从粽叶路径中得到我们的手脚的坐标点。绘制手脚, 这里只贴了左手的代码,其他同理。
核心代码:

///粽叶路径
///左边
var pms = pathStart.computeMetrics();
var first = pms.first;
var offsetStart = first.getTangentForOffset(first.length * 0.55)!;
/// 
Path path7 = Path();
path7.moveTo(offsetStart.position.dx, offsetStart.position.dy);
path7.relativeLineTo(-30, 20);
path7.relativeLineTo(-5, -30);
/// 左手
canvas.drawPath(
    path7,
    paint
      ..color = Colors.black
      ..style = PaintingStyle.stroke
      ..strokeWidth = 3);
复制代码

效果图: image.png

头巾

粽子有了,接下来给粽子来个标记,我是甜粽子还是咸粽子,毕竟有人爱吃咸粽子,有人爱吃甜粽子, 这里我们用路径绘制一个头绳,然后在头绳中间对标记粽子的咸甜。
这里知识点需要掌握绘制文字,核心代码:

Path path6 = Path();
path6.moveTo(0, -50);
path6.quadraticBezierTo(50, 10, 100, -50);
canvas.drawPath(
    Path.combine(PathOperation.intersect, path, path6),
    paint
      ..color = Colors.pink
      ..style = PaintingStyle.stroke);

var textPainter = TextPainter(
    text: TextSpan(
        text: "甜", style: TextStyle(fontSize: 16, color: Colors.white)),
    textDirection: TextDirection.ltr);
textPainter.layout();
var size2 = textPainter.size;

canvas.drawCircle(
    Offset(50, -20),
    size2.width,
    paint
      ..color = Colors.pink
      ..style = PaintingStyle.fill);
textPainter.paint(
    canvas, Offset(-size2.width / 2, -size2.height / 2).translate(50, -20));
复制代码

效果图: image.png

咸甜是一家

有甜粽子那也得有咸粽子不是,我们只需将上面粽子的代码复制,改下文字就可以制作一个咸粽子啦。 效果图: image.png 背景有点空,再加个背景图:
image.png OK,粽子的绘制工作到这里已经结束了,接下来我们让粽子说话可以给小朋友科普端午节的来历吧。

发声

粽子制作完成,接下来我们需要让粽子会说话,这里我使用的讯飞的语音合成WebAPI流式传输数据,将文本转化为音频文件实时播放,只需要调用接口即可将文本转化为音频文件播放,这里需要web_socket_channel插件来和讯飞进行webSocket连接,这样做的好处是不需要集成任何sdk,只需要通过APi接口就可以实时转换, image.png

web_socket_channel的简单使用:
创建连接:
image.png
发送消息方法:_channel?.sink.add(data);
在listen监听接收信息。
具体实现步骤已经整理文章分享: Flutter实现讯飞在线语音合成(WebSocket流式版)。

动画控制嘴巴开合

这里我们就让甜粽子为我们讲解,动画绘制之间的配合使用之前的文章介绍过多次,这里就不再过多介绍,直接看效果吧。

  • 嘴巴张合运动曲线:

d8de77b13cc41ee8e0e97d6bf50e35d5.gif
身体也加一个默认的运动曲线。
效果图:

1653970078130.gif 科普文字
image.png 加上科普文章,加上声音,此处已经有声音科普了哦,想体验的小伙伴可以下载源码自己体验一下,传送门 demo地址

1653970114575.gif 这里我们使用童声豆豆的声音, image.png 设置到这里即可。 示例代码demo地址 image.png

用到的技术点

绘制: path路径贝塞尔曲线路径联合路径测量路径添加图形绘制文字绘制图片域
动画: 多动画与绘制联合使用。
通信: web_socket_channel 的使用。
文件操作: 插件 path_provider 写入文件。
播放音频操作: 插件 audioplayers 播放音频。

总个结

This inspiration comes from the video of the traditional Chinese festival of popular science, and then there is this article, because I have integrated iFLYTEK voice on the client side when making smart furniture before, so I went to the official document of iFLYTEK to see if there is a Flutter plug-in, but Obviously not, but when I saw that there WebSocketwas transmission in the form of streams, I thought um, it was you, but when I was looking for a demo, there was no dartlanguage version. I followed the documentation step by step and finally realized the requirements. The WebSocketmethod is very suitable The use of cross-platform applications does not need to integrate any SDK, and the conversion can be completed only through the transmission of streams. It is really convenient to use SDK integration at one end, but it is cumbersome for cross-platform applications. After that, I have time to study Xunfei's speech recognition, which should be similar. OK, that's it for this article. Finally, I wish the Nuggets a healthy Dragon Boat Festival in advance, and a fragrant life in the garden.

Guess you like

Origin juejin.im/post/7103758484910866446