61儿童节,我给儿子做了两款coze小应用,让他见识一下程序员爸爸的厉害。

15,796 阅读6分钟

背景

鱼知识趣味科普

61儿童节到了,没啥好的礼物送给我家小孩,就用coze做两款应用送给他吧,让他见识一下他程序员爸爸的厉害😊。

我家小孩最近喜欢上一款名叫鱼吃鱼的微信小游戏,游戏里有很多鱼,他也认识了各种各样的鱼,但是对鱼的知识了解不多,所以经常玩的时候会问我,这个鱼是什么鱼啊?大多数鱼我也不认识,我也要到网上搜,才能告诉他。

最近coze我用的比较多,所以打算用coze做一个鱼知识科普的小游戏,让小孩可以学习到更多的鱼知识。

怀旧游戏棋(147,258,369)

这个灵感来自于掘金发布的回童年主题,我想起小时候和小伙伴玩过一款棋游戏,3个人随机分配147,258,369,然后三个人准备三个小东西,每次可以选择出0,1,2,3,然后把三个人出的东西加起来,如果加起来时3,然后被分配369的人,棋子往前走一步,然后重新出,到顶就算赢了。

游戏地图

image.png

记得小时候在农村没有啥娱乐活动,夏天的时候大人中午午休结束后,喜欢到村里一个大树下乘凉打牌聊天,我们小孩就在旁边玩,有时候玩泥巴,有时候下棋,有时候玩过家家,无忧无虑真的很快乐,既然回不到过去了,那就做一款小游戏来缅怀一下逝去的童年。

这个游戏不知道大家小时候有没有玩过,你们那边叫什么名字,欢迎评论留言。

功能演示

鱼知识趣味科普

image.png

image.png

image.png

小孩子可以输入关于鱼类的问题,然后应用会给他趣味科普和专业知识科普,最后还会生成一个对应鱼类的卡片。

我把这个bot也发布到了豆包平台,手机上下载豆包app,可以让孩子在手机上使用。可以语音输入和语音播放答案,对小孩子体验还是非常好的。

怀旧棋游戏(147,258,369)

游戏介绍

image.png

开始游戏

image.png

输入数字进行游戏

Kapture 2024-06-03 at 21.50.04.gif

注意这里的动画,可以清楚的看到那个人向前走了一步。

玩家获取胜利

image.png

功能实现

鱼知识趣味科普

人设与回复逻辑

image.png

工作流

在工作流里使用大模型分别输出趣味科普和专业科普,大模型和输入用的都是同一个,只是设置的提示词不一样。

image.png

紧接着使用了一个消息节点,把前面大模型生成的内容输出出去,这里选择流式输出,为了不让用户等太久,就能看到消息输出。这里中间加了一个消息节点,没有在结束节点里一起输出,是因为后面要生成图片,而生成图片又特别慢,所以为了不让用户等太久,可以先让用户看到文字,然后在结束节点里显示图片。

然后调用图像流根据前面生成的内容生成图片

image.png

图像流

图像流这里主要是用文生图节点,根据提示词生成图片。

image.png

卡片

一个图片节点和两个文本节点

image.png

为工作流绑定卡片

image.png

怀旧游戏棋(147,258,369)

这个bot逻辑很复杂,里面用到了数据库,工作流,自己还写了接口。不过虽然逻辑复杂,但是做起来大部分还是比较简单的,这里我和大家分享一下如何在工作流中使用数据库和如何使用node画图并生成gif动态图。

数据库

定义两个数据库,一个存放用户位置信息和座位方向,还有一个存放上一次电脑玩家出的数字。

image.png

image.png

在工作流中使用数据库

image.png

如果sql不会写,可以使用AI帮忙生成。

image.png

插入数据

image.png

image.png

使用node绘制图片

大家可以在上面演示中看到,使用gif动态显示玩家位置。这个功能在浏览器中实现还是很简单的,可以使用canvas绘制,但是coze中不能写前端代码,所以需要我们在插件中使用node绘制,然后导出图片。

node绘制图片可以使用node-canvas库,和浏览器中的canvas操作一样,使用起来很简单。

开始我打算在coze插件中使用canvas绘制,然后导出成base64在卡片中渲染,但是卡片中的图片不支持base64,并且插件中也无法安装canvas库,所以我只能自己写一个服务,在服务中绘制图片并且把图片上传到自己的文件服务器,对外暴露图片链接。

先使用canvas库写一个demo,绘制一个矩形,并生成demo.png文件

const { createCanvas } = require('canvas');
const fs = require('fs');

const canvas = createCanvas(200, 200);

const ctx = canvas.getContext('2d');
// 绘制一个红色矩形
ctx.fillStyle = 'red'
ctx.fillRect(10, 10, 50, 50)

const base64Data = canvas.toDataURL('image/png', 1).replace(/^data:image\/png;base64,/, "");
const bitmap = Buffer.from(base64Data, 'base64');
// 写入文件到指定路径
fs.writeFileSync(`demo.png`, bitmap);

image.png

按照这个思路可以根据用户位置信息把游戏地图绘制出来,完整代码比较多,就不贴了,就贴部份代码,根据坐标绘制直线和矩形。

function drawMap(ctx) {

  // 白色背景
  ctx.beginPath();
  ctx.fillStyle = '#FFFFFF';
  ctx.closePath();
  ctx.fillRect(0, 0, 400, 400);

  // 中间矩形
  ctx.beginPath();
  ctx.strokeStyle = '#000000';
  ctx.closePath();
  ctx.strokeRect(150, 150, 100, 100);

  // 中间竖线
  ctx.beginPath();
  ctx.strokeStyle = '#000000';
  ctx.moveTo(200, 50);
  ctx.lineTo(200, 350);
  ctx.closePath();
  ctx.stroke();

  // 中间横线
  ctx.beginPath();
  ctx.strokeStyle = '#000000';
  ctx.moveTo(50, 200);
  ctx.lineTo(350, 200);
  ctx.closePath();
  ctx.stroke();

  // 下边4条线
  ctx.beginPath();
  ctx.strokeStyle = '#000000';
  ctx.moveTo(180, 350);
  ctx.lineTo(220, 350);
  ctx.closePath();
  ctx.stroke();

  ctx.beginPath();
  ctx.strokeStyle = '#000000';
  ctx.moveTo(180, 330);
  ctx.lineTo(220, 330);
  ctx.closePath();
  ctx.stroke();

  ctx.beginPath();
  ctx.strokeStyle = '#000000';
  ctx.moveTo(180, 310);
  ctx.lineTo(220, 310);
  ctx.closePath();
  ctx.stroke();

  ctx.beginPath();
  ctx.strokeStyle = '#000000';
  ctx.moveTo(180, 290);
  ctx.lineTo(220, 290);
  ctx.closePath();
  ctx.stroke();
  
  ...
 }

image.png

使用node生成gif动态图

上面把图片生成出来,那我们怎么给做成gif呢,需要先根据坐标生成多张图片,然后把这些图片合成gif动态图就行了。那node中怎么把图片转换为gif呢,这就需要用到gm库了,使用这个库电脑需要先安装graphicsmagick工具。

brew install graphicsmagick

npm i gm

先生成多张游戏图片

  for (let i = 0; i < instance; i += 1) {
    const canvas = createCanvas(400, 400);
    const ctx = canvas.getContext('2d');
    drawMap(ctx);

    data.forEach(item => {
      drawChess(ctx, item, 1, i);
    });

    // 把canvas转为图片
    saveImg(canvas, i);

    imagePaths.push(`output${i}.png`)
  }

把游戏图片合成gif


function saveGIF(imagePaths) {
  return new Promise((resolve) => {
    const gifPath = Date.now() + '.gif';

    const img = gm();

    imagePaths.forEach((image) => {
      img.in('-page', '+0+0').in(image);
    });

    img
      .in('-loop', '0') // 循环播放
      .write(gifPath, function (err) {
        if (err) console.log(err);
        console.log('GIF animation generated successfully!');
        resolve(gifPath);
      });
  })
}

1717399455144.gif

然后把生成的gif图上传到oss对象存储库就行了,然后在coze的卡片中绑定返回的图片链接,就能正常的展示gif动态图了。

最后

随着coze的使用越来越熟练,发现coze能做出好多好玩的东西,大家可以去体验一下,创建自己的小应用。

coze官网地址:www.coze.cn/home

鱼知识趣味科普体验地址:www.coze.cn/store/bot/7…

怀旧游戏棋(147,258,369)体验地址:www.coze.cn/store/bot/7…