驴友花雕 发表于 2025-5-23 06:36:05

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛

本帖最后由 驴友花雕 于 2025-6-6 17:51 编辑



驴友花雕 发表于 2025-5-23 06:42:14

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛

我从来没有养过 Tamagotchi,一种小电子宠物,当它们在 80 年代后期问世时。老实说,图形相当粗糙,纽扣电池过去和现在都是一个环境问题。

但今天你可以做得更好。不是为了你的口袋,而是为了你的桌面。一头可爱的奶牛并没有错。

因此,让我们在谷仓中建造一头奶牛,您可以喂养和抚摸它(我们将跳过谷仓的清洁工作)。



驴友花雕 发表于 2025-5-23 06:44:09

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛

用品与材料

• ESP32 CYD (便宜的黄色显示器) (2432S028R)
• 合适的电源 / 移动电源
• 3D 打印部件。或一些用于谷仓的木材



• 木材 / 胶合板和颜色
• Arduino IDE 软件
(需要具备 Arduino 的基本经验)

驴友花雕 发表于 2025-5-23 06:45:19

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛

第 1 步:奶牛图形

对于我们的奶牛,我们需要一个带有饲喂站和水槽的舞台/谷仓,每个平台都显示不同的高度。
奶牛应该
• 站着, 微笑, 咀嚼, 看起来悲伤
• 吃、喝
• 躺下反刍, 微笑, 睡觉
这些图像作为代码存储在名为 “cow-all.h” 的额外文件中,并在需要时加载。
这些图像是自制的,您可以自由使用它们。



驴友花雕 发表于 2025-5-23 06:53:17

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛

第 2 步:Cow 软件

CYD 是 ESP32 和 Touchschreeen 的完美结合。它为您省去了烦人的焊接和电缆。
诚然,我的编程有点业余。您当然可以从 CYD 的设计方面获得更多收益或为奶牛提供更多功能。但至少程序步骤很容易遵循。

该库可用于模拟各种工作表面。我们不展示背景,而是专注于奶牛、饮水处和饲养处。三个点击区域以隐藏的方式集成在一起,即它们不可见,但可以在三个地方点击:用于补充的水和饲料位置以及用于抚摸的奶牛本身。
奶牛的状态(很快)保存在 ESP32 上,以便随时关闭设备,并保持食物/情绪状态。

饥饿和口渴的值随机变化。ESP32 对毫秒数进行计数。这些值可以根据您的个人喜好进行设置。
文件 “cow-all.h” 在代码中包含了所有不同的奶牛图像,并且必须与 “demo.ino” 或 “tamagotchi_cow.ino” 存储在同一个文件夹中!

cow-all.h
演示.ino

#include <Arduino.h>
#include <SPI.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>

TFT_eSPI tft = TFT_eSPI();

// touchscreen pins
#define XPT2046_IRQ 36// T_IRQ
#define XPT2046_MOSI 32 // T_DIN
#define XPT2046_MISO 39 // T_OUT
#define XPT2046_CLK 25// T_CLK
#define XPT2046_CS 33   // T_CS
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);

#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define FONT_SIZE 2

#include "cow-all.h"

// extra colors
#define NAVY tft.color565(0,0,160)   
#define DODGERBLUE tft.color565(30,144,255)
#define TURQUOISE tft.color565(64,224,208)
#define CYAN tft.color565(0,255,255)
#define GOLD tft.color565(255,215,0)
#define ORANGE tft.color565(255,165,0)
#define RED tft.color565(255,10,0)
#define MAROON tft.color565(123,0,0)
#define BROWN tft.color565(150,75,0)

// Global Variables
int x, y, z;   // touchscreen coordinates + pressure

// Set X and Y coordinates for center of display
int centerX, centerY;

//moodmeter & cow
uint32_t moodcolor;
int food, water, mood, mooddegree, waterlevel, foodlevel;
int cowX,cowY;
uint32_t cowImage;
int saturation, thirst;
int flag;

void drawStable() {
//tft.drawRect(260, 10, 50, 14, TFT_RED);         //status
tft.fillRoundRect(10, 80, 30, 70, 3, GOLD );          //food   TFT_DARKGREEN
tft.fillRoundRect(10, 140, 50, 10, 5, TFT_DARKGREEN); //food

tft.fillRoundRect(290, 80, 16, 60, 5, DODGERBLUE);//water
tft.drawRoundRect(290, 80, 16, 60, 5, TFT_WHITE);//water
tft.drawRoundRect(280, 138, 26, 2, 2, TFT_WHITE);//water
}


void setup()
{
Serial.begin(115200);

// init RGB LED
pinMode(4, OUTPUT); pinMode(16, OUTPUT); pinMode(17, OUTPUT);
// turn off LED
digitalWrite(4, HIGH); digitalWrite(16, HIGH); digitalWrite(17, HIGH);

// Start the SPI for the touchscreen and init the touchscreen
touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
touchscreen.setRotation(3);

// start display
tft.init();
tft.setRotation(3); // may be altered
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_WHITE, TFT_BLACK);

// Set X and Y coordinates for center of display
centerX = SCREEN_WIDTH / 2;
centerY = SCREEN_HEIGHT / 2;

tft.drawCentreString("Welcome to my stable", centerX, 30, FONT_SIZE);

int x = (tft.width() - 116) / 2;
int y = (tft.height() - 110) / 2;

food=60;
saturation = 90;
water= 80;

//clear cow area
tft.fillRect(40, 70, 249, 170, TFT_BLACK);
// draw cow
//tft.drawBitmap(40, 80, cow_well, 160, 140, TFT_WHITE);
//tft.drawBitmap(45, 80, cow_eat, 160, 142, TFT_WHITE);
tft.drawBitmap(70, 80, cow_neutral, 160, 147, TFT_WHITE);
delay(2000);
tft.fillRect(50, 0, 200, 50, TFT_BLACK); //clear area
}

void loop(){
// Checks if Touchscreen is touched
if (touchscreen.tirqTouched() && touchscreen.touched()) {
    // Get Touchscreen points
    TS_Point p = touchscreen.getPoint();
    // Calibrate Touchscreen points with map function to the correct width and height
    x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
    y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
    z = p.z;

    printTouchToSerial(x, y, z);

      
    //food touch
    if ((x>5)&&(x<60)&&(y>70)&&(y<160)) food=food+20;
    if (food>=100) food=100;
    //water touch
    if ((x>270)&&(x<315)&&(y>60)&&(y<155)) water=water+20;
    if (water>=100) water=100;
   
    cowX=50; cowY = 80; //start coordinates of cow bmp
    //cow touch
    if ((x>cowX)&&(x<cowX+150)&&(y>cowY)&&(y<cowY+130)) mood=mood+20;
    if (mood>=100) mood=100;

    Serial.print(food); Serial.print(""); Serial.print(water);Serial.print(""); Serial.println(mood);
    delay(80);
}
moodmeter(mood);
waterfill(water);
foodfill(food);

/*
//food /water levels ********************
if (cowImage = cow_eat) {
    food--;
    saturation = saturation + 6;
   
}
if (cowImage = cow_drink) {
    water--;
    thirst = thirst -7;
}

//hunger/thirst comes up*******************
if (millisnow - millispast = random(480000, 900000)) {//8-15 minutes
    saturation = saturation-3;
    thirst = thirst + 2;
    if (saturation<=0) saturation=0;
    if (thirst<=0) thirst=0;
}
*/
food=food - 0.5; water=water -0.5; mood=mood-0.5;
if (food<=0) food=0;
if (water<=0) water=0;
if (mood<=0) mood=0;

if ((mood> 70) && (flag!=1)) {
    tft.fillRect(54, 70, 220, 170, TFT_BLACK); //clear cow area
    tft.drawBitmap(70, 80, cow_smile2, 160, 147, TFT_WHITE);// draw cow
    flag = 1;
}
if ((mood<= 70) && (mood > 30) && (flag!=2)) {
    tft.fillRect(54, 70, 220, 170, TFT_BLACK); //clear cow area
    tft.drawBitmap(70, 80, cow_neutral, 160, 147, TFT_WHITE);// draw cow
    flag = 2;
}
if ((mood<=30) && (flag !=3)) {
    tft.fillRect(54, 70, 220, 170, TFT_BLACK); //clear cow area
    tft.drawBitmap(70, 80, cow_sad, 160, 145, TFT_WHITE);// draw cow
    flag = 3;
}


delay(300);
}


void waterfill(int water) {
tft.fillRoundRect(290, 80, 16, 60, 5, TFT_BLACK); //clear area
waterlevel = map(water, 0, 100, 140, 80);
tft.fillRect(290, waterlevel, 16, (140-waterlevel), DODGERBLUE);//water
tft.drawRoundRect(289, 79, 18, 62, 5, TFT_WHITE);//water frame
tft.drawRoundRect(275, 138, 26, 3, 1, TFT_WHITE);//water
}

void foodfill(int food) {
tft.fillRoundRect(10, 80, 40, 70, 5, TFT_BLACK); //clear area
foodlevel = map(food, 0, 100, 150 , 80);
tft.drawRoundRect(9, 79, 42, 72, 3, BROWN);   //food frame
tft.fillRoundRect(10, foodlevel, 40, (150-foodlevel), 3, TFT_DARKGREEN);   //food   
tft.fillTriangle(9, 150, 10, 157, 62, 150, BROWN);    //feeding dish
}

void moodmeter(int mood) {
tft.fillRect(0, 0, 43, 43, TFT_BLACK); //clear area
mooddegree = map(mood, 0, 100, 1, 360);
if (mood < 15) moodcolor = RED;
if ((mood >= 15) && (mood < 30)) moodcolor = ORANGE;
if ((mood >= 30) && (mood < 60)) moodcolor = GOLD;
if (mood >= 60) moodcolor = TFT_DARKGREEN;
tft.drawSmoothArc(22, 22, 20, 8, 0, mooddegree, moodcolor, TFT_BLACK);
}

void printTouchToSerial(int x, int y, int z) {
Serial.print("X = ");
Serial.print(x);
Serial.print(" | Y = ");
Serial.print(y);
Serial.print(" | Pressure = ");
Serial.print(z);
Serial.println();
}




驴友花雕 发表于 2025-5-23 06:55:51

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛

tamagotchi_cow.ino

#include <Arduino.h>
#include <SPI.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>

TFT_eSPI tft = TFT_eSPI();

// touchscreen pins
#define XPT2046_IRQ 36// T_IRQ
#define XPT2046_MOSI 32 // T_DIN
#define XPT2046_MISO 39 // T_OUT
#define XPT2046_CLK 25// T_CLK
#define XPT2046_CS 33   // T_CS
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);

#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define FONT_SIZE 2

#include "cow-all.h"

// extra colors
#define NAVY tft.color565(0,0,160)   
#define DODGERBLUE tft.color565(30,144,255)
#define TURQUOISE tft.color565(64,224,208)
#define CYAN tft.color565(0,255,255)
#define GOLD tft.color565(255,215,0)
#define ORANGE tft.color565(255,165,0)
#define RED tft.color565(255,10,0)
#define MAROON tft.color565(123,0,0)
#define BROWN tft.color565(150,75,0)

// Global Variables
int x, y, z;   // touchscreen coordinates + pressure

// Set X and Y coordinates for center of display
int centerX, centerY;

//moodmeter & cow
uint32_t moodcolor;
int food, water, mood, mooddegree, waterlevel, foodlevel;
int cowX,cowY;
uint32_t cowImage;
int saturation, thirst;


void drawStable() {
//tft.drawRect(260, 10, 50, 14, TFT_RED);         //status
tft.fillRoundRect(10, 80, 30, 70, 3, GOLD );          //food   TFT_DARKGREEN
tft.fillRoundRect(10, 140, 50, 10, 5, TFT_DARKGREEN); //food

tft.fillRoundRect(290, 80, 16, 60, 5, DODGERBLUE);//water
tft.drawRoundRect(290, 80, 16, 60, 5, TFT_WHITE);//water
tft.drawRoundRect(280, 138, 26, 2, 2, TFT_WHITE);//water
}


void setup()
{
Serial.begin(115200);

// init RGB LED
pinMode(4, OUTPUT); pinMode(16, OUTPUT); pinMode(17, OUTPUT);
// turn off LED
digitalWrite(4, HIGH); digitalWrite(16, HIGH); digitalWrite(17, HIGH);

// Start the SPI for the touchscreen and init the touchscreen
touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
touchscreen.setRotation(3);

// start display
tft.init();
tft.setRotation(3); // may be altered
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_WHITE, TFT_BLACK);

// Set X and Y coordinates for center of display
centerX = SCREEN_WIDTH / 2;
centerY = SCREEN_HEIGHT / 2;

tft.drawCentreString("Welcome to my stable", centerX, 30, FONT_SIZE);

int x = (tft.width() - 116) / 2;
int y = (tft.height() - 110) / 2;

food=60;
saturation = 90;
water= 80;

//clear cow area
tft.fillRect(40, 70, 249, 170, TFT_BLACK);
// draw cow
//tft.drawBitmap(40, 80, cow_well, 160, 140, TFT_WHITE);
//tft.drawBitmap(45, 80, cow_eat, 160, 142, TFT_WHITE);
tft.drawBitmap(70, 80, cow_smile, 160, 145, TFT_WHITE);
delay(2000);
tft.fillRect(50, 0, 200, 50, TFT_BLACK); //clear area
}

void loop(){
// Checks if Touchscreen is touched
if (touchscreen.tirqTouched() && touchscreen.touched()) {
    // Get Touchscreen points
    TS_Point p = touchscreen.getPoint();
    // Calibrate Touchscreen points with map function to the correct width and height
    x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
    y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
    z = p.z;

    printTouchToSerial(x, y, z);

      
    //food touch
    if ((x>5)&&(x<60)&&(y>70)&&(y<160)) food=food+20;
    if (food>=100) food=100;
    //water touch
    if ((x>270)&&(x<315)&&(y>60)&&(y<155)) water=water+20;
    if (water>=100) water=100;
   
    cowX=50; cowY = 80; //start coordinates of cow bmp
    //cow touch
    if ((x>cowX)&&(x<cowX+150)&&(y>cowY)&&(y<cowY+130)) mood=mood+20;
    if (mood>=100) mood=100;

    Serial.print(food); Serial.print(""); Serial.print(water);Serial.print(""); Serial.println(mood);
    delay(80);
}
moodmeter(mood);
waterfill(water);
foodfill(food);

/*
//food /water levels ********************
if (cowImage = cow_eat) {
    food--;
    saturation = saturation + 6;
   
}
if (cowImage = cow_drink) {
    water--;
    thirst = thirst -7;
}

//hunger/thirst comes up*******************
if (millisnow - millispast = random(480000, 900000)) {//8-15 minutes
    saturation = saturation-3;
    thirst = thirst + 2;
    if (saturation<=0) saturation=0;
    if (thirst<=0) thirst=0;
}
*/
food--; water--; mood--;
if (food<=0) food=0;
if (water<=0) water=0;
if (mood<=0) mood=0;
delay(200);
}


void waterfill(int water) {
tft.fillRoundRect(290, 80, 16, 60, 5, TFT_BLACK); //clear area
waterlevel = map(water, 0, 100, 140, 80);
tft.fillRect(290, waterlevel, 16, (140-waterlevel), DODGERBLUE);//water
tft.drawRoundRect(289, 79, 18, 62, 5, TFT_WHITE);//water frame
tft.drawRoundRect(275, 138, 26, 3, 1, TFT_WHITE);//water
}

void foodfill(int food) {
tft.fillRoundRect(10, 80, 40, 70, 5, TFT_BLACK); //clear area
foodlevel = map(food, 0, 100, 150 , 80);
tft.drawRoundRect(9, 79, 42, 72, 3, BROWN);   //food frame
tft.fillRoundRect(10, foodlevel, 40, (150-foodlevel), 3, TFT_DARKGREEN);   //food   
tft.fillTriangle(9, 150, 10, 157, 62, 150, BROWN);    //feeding dish
}

void moodmeter(int mood) {
tft.fillRect(0, 0, 43, 43, TFT_BLACK); //clear area
mooddegree = map(mood, 0, 100, 1, 360);
if (mood < 15) moodcolor = RED;
if ((mood >= 15) && (mood < 30)) moodcolor = ORANGE;
if ((mood >= 30) && (mood < 60)) moodcolor = GOLD;
if (mood >= 60) moodcolor = TFT_DARKGREEN;
tft.drawSmoothArc(22, 22, 20, 8, 0, mooddegree, moodcolor, TFT_BLACK);
}

void printTouchToSerial(int x, int y, int z) {
Serial.print("X = ");
Serial.print(x);
Serial.print(" | Y = ");
Serial.print(y);
Serial.print(" | Pressure = ");
Serial.print(z);
Serial.println();
}

驴友花雕 发表于 2025-5-23 09:10:08

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛

第 3 步:扬声器和 LDR 传感器

“Mooh”的扬声器是可选的。不幸的是,我还没有能够让声音功能在不复杂的情况下工作。每次 SD 卡在线时,触摸屏都无法正常工作。有什么想法吗?
mp3 文件可以保存在 SD 卡上。连接引脚位于 CYD 的背面。我从一台旧的固定电话中获得了扬声器。
内置的 LDR 传感器 (GPIO 34) 告诉奶牛何时睡觉。天黑时,她躺下。在此期间,不消耗水和食物。


附件

Cow-moo-sounds.mp3



驴友花雕 发表于 2025-5-23 09:12:46

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛

第 4 步:谷仓

对于氛围,我很快就设计了一个带有 tinkercad.com 的马厩,并通过 3D 打印机将其变为现实。当然,您也可以在这里用木头建造一个美妙的微型马厩。不要忘记背面的良好通风。

3D打印件
Hay_Barn_ground.stl
Hay_Barn_roof.stl
Hay_Barn_walls.stl











驴友花雕 发表于 2025-5-23 09:15:08

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛

第 5 步:哞哞

功能:
当奶牛的内部水分和饲料水平下降(= 饥饿、口渴)时,奶牛会进食和饮水。如果水或饲料容器是空的,则奶牛会感到饥饿、不高兴和哞哞。

如果你点击水或饲料,补给就会得到补充,奶牛就可以吃东西了。如果你轻拍奶牛(=抚摸),它也会很开心,很舒服地哞哞叫。

当 LDR 注意到黑暗时,奶牛就会睡觉。她不吃东西,也没有太多的饥饿或口渴。

与您的新宠物一起玩得开心!



驴友花雕 发表于 2025-5-23 09:20:56

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛

本帖最后由 驴友花雕 于 2025-6-6 17:52 编辑

附录
项目链接:https://www.instructables.com/Cute-Tamagotchi-Cow/
项目作者:德国 马库斯·奥皮茨(Markus Opitz)
视频记录:https://www.bilibili.com/video/B ... a9be994cbb4a86cc987
3D打印文件:https://content.instructables.co ... FFOYDLOMADY883L.stl
https://content.instructables.co ... FFY6D47MADY883P.stl
https://content.instructables.co ... F7A3G1NMADY883Q.stl
项目开源代码:https://content.instructables.co ... FI156M8MADY89Z5.ino
图像到字节数组在线转换器(CPP、ARDUINO):https://mischianti.org/images-to ... verter-cpp-arduino/
电子宠物声音文件:https://content.instructables.co ... /FHPLRK4MADY883F.mp 3





https://www.bilibili.com/video/BV1EQJWzeEAA/?share_source=copy_web&vd_source=371a292a55e5ca9be994cbb4a86cc987




驴友花雕 发表于 前天 17:52

【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛


页: [1]
查看完整版本: 【Arduino 动手做】可爱的 Tamagotchi 电子宠物牛