背景
鱼知识趣味科普
61儿童节到了,没啥好的礼物送给我家小孩,就用coze做两款应用送给他吧,让他见识一下他程序员爸爸的厉害😊。
我家小孩最近喜欢上一款名叫鱼吃鱼的微信小游戏,游戏里有很多鱼,他也认识了各种各样的鱼,但是对鱼的知识了解不多,所以经常玩的时候会问我,这个鱼是什么鱼啊?大多数鱼我也不认识,我也要到网上搜,才能告诉他。
最近coze我用的比较多,所以打算用coze做一个鱼知识科普的小游戏,让小孩可以学习到更多的鱼知识。
怀旧游戏棋(147,258,369)
这个灵感来自于掘金发布的回童年主题,我想起小时候和小伙伴玩过一款棋游戏,3个人随机分配147,258,369,然后三个人准备三个小东西,每次可以选择出0,1,2,3,然后把三个人出的东西加起来,如果加起来时3,然后被分配369的人,棋子往前走一步,然后重新出,到顶就算赢了。
游戏地图
记得小时候在农村没有啥娱乐活动,夏天的时候大人中午午休结束后,喜欢到村里一个大树下乘凉打牌聊天,我们小孩就在旁边玩,有时候玩泥巴,有时候下棋,有时候玩过家家,无忧无虑真的很快乐,既然回不到过去了,那就做一款小游戏来缅怀一下逝去的童年。
这个游戏不知道大家小时候有没有玩过,你们那边叫什么名字,欢迎评论留言。
功能演示
鱼知识趣味科普
小孩子可以输入关于鱼类的问题,然后应用会给他趣味科普和专业知识科普,最后还会生成一个对应鱼类的卡片。
我把这个bot也发布到了豆包平台,手机上下载豆包app,可以让孩子在手机上使用。可以语音输入和语音播放答案,对小孩子体验还是非常好的。
怀旧棋游戏(147,258,369)
游戏介绍
开始游戏
输入数字进行游戏
注意这里的动画,可以清楚的看到那个人向前走了一步。
玩家获取胜利
功能实现
鱼知识趣味科普
人设与回复逻辑
工作流
在工作流里使用大模型分别输出趣味科普和专业科普,大模型和输入用的都是同一个,只是设置的提示词不一样。
紧接着使用了一个消息节点,把前面大模型生成的内容输出出去,这里选择流式输出,为了不让用户等太久,就能看到消息输出。这里中间加了一个消息节点,没有在结束节点里一起输出,是因为后面要生成图片,而生成图片又特别慢,所以为了不让用户等太久,可以先让用户看到文字,然后在结束节点里显示图片。
然后调用图像流根据前面生成的内容生成图片
图像流
图像流这里主要是用文生图节点,根据提示词生成图片。
卡片
一个图片节点和两个文本节点
为工作流绑定卡片
怀旧游戏棋(147,258,369)
这个bot逻辑很复杂,里面用到了数据库,工作流,自己还写了接口。不过虽然逻辑复杂,但是做起来大部分还是比较简单的,这里我和大家分享一下如何在工作流中使用数据库和如何使用node画图并生成gif动态图。
数据库
定义两个数据库,一个存放用户位置信息和座位方向,还有一个存放上一次电脑玩家出的数字。
在工作流中使用数据库
如果sql不会写,可以使用AI帮忙生成。
插入数据
使用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);
按照这个思路可以根据用户位置信息把游戏地图绘制出来,完整代码比较多,就不贴了,就贴部份代码,根据坐标绘制直线和矩形。
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();
...
}
使用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);
});
})
}
然后把生成的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…