|
你玩过棋盘游戏吗?你喜欢玩骰子吗?我们在许多棋盘游戏中使用骰子,但有时它们会引起问题。例如,当我和朋友一起玩thriller游戏时,有时我们会忘记玩了多少回合。您是否想知道如何解决这个问题?如果是这样,请阅读本文。
在本篇文章中,我们将展示如何使用电子组件制作智能助手,包含KY-037声音检测模块、RGB LED、TFT LCD扩展板,当然还有Arduino UNO。
什么是骰子塔? 许多棋盘游戏使用骰子。对于那些喜欢真实游戏而不是计算机游戏的人来说,握住并掷骰子至关重要。但是不能保证公平,玩家可能会作弊!此外,一些棋盘游戏有很多骰子。同时扔几个骰子可能很困难,有些甚至可能会弄丢。骰子塔是解决这些问题的好主意。骰子从塔楼上方进入,接触内板并向下旋转,固定在底部。
棋盘游戏:更多魅力,更少作弊! 不管是哪种游戏,都会有可能存在作弊。特别是骰子游戏。游戏的快感和节奏可能会使玩家不记得回合数。因此,存在公正的判断可能会有所帮助。通过一些电子创新,我们可以制造出一个智能骰子塔,以帮助保持点数并将其显示在五颜六色的灯光下。
您可能会在游戏中弄丢骰子。因此,您必须使用其他物体(石头!)代替骰子。智能骰子塔为您提供最佳选择。即使没有任何可用的骰子,也不要担心,我们的塔楼也有一个虚拟的骰子。
所需的组件 ● Arduino UNO R3开发板 ● 2.4英寸TFT LCD显示屏扩展板 ● KY-037声音检测传感器模块 ● 5mm RGB三色LED灯 ● 3 X 1.5V AAA电池盒固定器 ● 1.5V AAA电池
如何组装骰子塔的主体结构 要制造智能骰子塔,首先,我们需要构建主体。它可以由2.8mm MDF或有机玻璃制成。请在此处免费下载激光切割草图。设计的骰子塔有58个零件。
电路 在本文中,我们使用Arduino TFT LCD扩展板。要操作该模块,只需将其安装在Arduino UNO上(注意引脚的位置和方向)。为了设置KY-037模块,请将模块的电源引脚连接到VCC和GND引脚,并将数字输出引脚连接到Arduino的D13引脚。
要使用RGB LED,请将阴极引脚连接到Arduino的GND引脚,并将红色、绿色和蓝色引脚连接到Arduino板上的D5、D6和D7。
如何使用声音检测模块知道骰子何时掉落 我们可以使用或声音检测模块来知道骰子何时掉落。如果我们将震动传感器放在一块内板的下面,那么给定的震动将是不够的。将传感器直接放在骰子路径上也不正确。因此,声音模块是正确的选择。我们可以仅根据图4设置KY-037声音模块。由于在此项目中只检测一种音调,因此我们仅使用声音模块的数字引脚。要识别骰子声音,我们可以使用digitalRead()命令读取Arduino的D13引脚。数字引脚在此模块中上拉,当声音达到阈值时,数字引脚电压将变为零。我们可以通过旋转板上的电位器来更改声音阈值。要精确地校准此传感器,请按照下列步骤操作: 1. 将以下代码上传到Arduino开发板: - void setup() {
- Serial.begin(9600); // setup serial
- pinMode(13,INPUT);
- }
- void loop() {
- Serial.println(digitalRead(13));
- delay(100);
- }
复制代码2. 打开串口监视器,将骰子持续不断放入塔中,同时旋转电位器,直到在“Serial Monitor”窗口中看到数字零。 再投入一些时间以确保模块已正确调整。 应该对其进行调整,以使环境中的其他噪声不会激活传感器。
如何使用RGB LED显示点数和添加灯光效果 有各种RGB LED类型。 在此项目中,我们使用4针共阴极RGB LED。 要点亮LED,我们应将阴极连接到GND。 在其他引脚上加电压会使LED变成红色、绿色或蓝色。 如果所有三个引脚都设置为高电平,LED将发白光。 使用以下代码,您可以周期性将LED颜色更改为红色、绿色、蓝色和白色。 - #define rLED 10
- #define rLED 11
- #define rLED 12
- Void setup(){
- pinMode(rLED,OUTPUT);
- pinMode(gLED,OUTPUT);
- pinMode(bLED,OUTPUT);
- void loop(){
- //LED equalizer
- digitalWrite(rLED,HIGH);digitalWrite(gLED,LOW);digitalWrite(bLED,LOW);
- delay(100);
- digitalWrite(rLED,LOW);digitalWrite(gLED,HIGH);digitalWrite(bLED,LOW);
- delay(100);
- digitalWrite(rLED,LOW);digitalWrite(gLED,LOW);digitalWrite(bLED,HIGH);
- delay(100);
- digitalWrite(rLED,HIGH);digitalWrite(gLED,HIGH);digitalWrite(bLED,HIGH);
- delay(100);
- }
复制代码
使用TFT LCD显示更多信息并制作虚拟骰子 要显示玩家的回合数,我们应该知道玩家的数量及其相应的颜色。 我们可以使用带触摸屏的TFT LCD。 用于Arduino的2.4英寸Adafruit LCD扩展板是一个绝佳的简单选择。
在以下代码中,当启动LCD时,首先要询问玩家的数量,然后用户可以通过触摸屏幕上的骰子从1到4中进行选择。 根据玩家的数量,它会询问每个玩家的颜色。 在此部分的最后,显示颜色顺序,然后开始游戏。 - */
- Smart Dice Tower – main code
- */
- #include <Adafruit_GFX.h>
- #include <Adafruit_TFTLCD.h>
- #include <TouchScreen.h>
-
- #define LCD_CS A3
- #define LCD_CD A2
- #define LCD_WR A1
- #define LCD_RD A0
- #define LCD_RESET A4
-
- #define YP A3
- #define XM A2
- #define YM 9
- #define XP 8
-
- #define rLED 5
- #define gLED 6
- #define bLED 7
- #define ss 13
-
- TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
-
- //find these number through “SDT_TS_calibration.ino” code
- #define TSx_dices 600
- #define Tsy_1st_dice 825
- #define Tsy_2nd_dice 625
- #define Tsy_3th_dice 425
- #define Tsy_4th_dice 225
- #define Tsy_virtual_dice 760
-
- #define BLACK 0x0000
- #define BLUE 0x001F
- #define RED 0xF800
- #define GREEN 0x07E0
- #define YELLOW 0xFFE0
- #define WHITE 0xFFFF
- #define PURPLE 0x780F
-
- Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
-
- int n=1,a=1,t=0,count=0;
- int c[4];
- bool pres=false,vd=false;
-
- void setup() {
-
- Serial.begin(9600);
- Serial.println(F(“TFT LCD test”));
-
- tft.reset();
-
- #ifdef USE_ADAFRUIT_SHIELD_PINOUT
- Serial.println(F(“Using Adafruit 2.4\” TFT Arduino Shield Pinout”));
- #else
- Serial.println(F(“Using Adafruit 2.4\” TFT Breakout Board Pinout”));
- #endif
- Serial.print(“TFT size is “);
- Serial.print(tft.width());
- Serial.print(“x");
- Serial.println(tft.height());
-
- tft.reset();
- delay(1000);
- uint16_t identifier = tft.readID();
-
- if (identifier == 0x9325){
- Serial.println(F(“Found ILI9325 LCD driver”));
- } else if (identifier == 0x9328){
- Serial.println(F(“Found ILI9328 LCD driver”));
- } else if (identifier == 0x7575){
- Serial.println(F(“Found HX8347G LCD driver”));
- } else if (identifier == 0x9341){
- Serial.println(F(“Found ILI9341 LCD driver”));
- } else if (identifier == 0x8357){
- Serial.println(F(“Found HX8357D LCD driver”));
- } else {
- Serial.print(F(“Unknown LCD driver chip: “));
- Serial.println(identifier, HEX);
- Serial.println(F(“If using the Adafruit 2.4\” TFT Arduino shield, the line:”));
- Serial.println(F(“ #define USE_ADAFRUIT_SHIELD_PINOUT”));
- Serial.println(F(“should appear in the library header (Adafruit_TFT.h).”));
- Serial.println(F(“If using the breakout board, it should NOT be #defined!”));
- Serial.println(F(“Also if using the breakout, double-check that all wiring”));
- Serial.println(F(“matches the tutorial.”));
- return;
- }
-
- pinMode(13, OUTPUT);
- pinMode(XM, OUTPUT);
- pinMode(YP, OUTPUT);
-
- tft.begin(identifier);
-
- Serial.println(F(“Benchmark Time (microseconds)”));
- //-------------------------------------------------------------------------------------
- //LCD starting:
- tft.fillScreen(PURPLE);
- tft.setTextColor(YELLOW);
- tft.setRotation(1);
- tft.setCursor(30, 100);
- tft.setTextSize(4);
- tft.println(“Electropeak”);
- tft.setCursor(60, 150);
- tft.setTextSize(2);
- tft.println(“Smart Dice Tower”);
- delay(1000);
- //-------------------------------------------------------------------------------------
- //asking number of player
- tft.fillScreen(PURPLE);
- tft.setRotation(1);
- tft.setCursor(5, 50);
- tft.setTextSize(3);
- tft.println(“number of player?”)
- delay(200);
- tft.fillRoundRect(20,110,60,60,5,WHITE);
- tft.fillCircle(50,140,10,RED);
-
- tft.fillRoundRect(90,110,60,60,5,WHITE);
- tft.fillCircle(120,125,8,BLACK);
- tft.fillCircle(120,155,8,BLACK);
-
- tft.fillRoundRect(160,110,60,60,5,WHITE);
- tft.fillCircle(170,120,8,BLACK);
- tft.fillCircle(190,140,8,BLACK);
- tft.fillCircle(210,160,8,BLACK);
-
- tft.fillRoundRect(230,110,60,60,5,WHITE);
- tft.fillCircle(245,125,8,BLACK);
- tft.fillCircle(275,125,8,BLACK);
- tft.fillCircle(245,155,8,BLACK);
- tft.fillCircle(275,155,8,BLACK);
-
- while(!pres){
- digitalWrite(13, HIGH);
- TSPoint p = ts.getPoint();
- digitalWrite(13, LOW);
- pinMode(XM, OUTPUT);
- pinMode(YP, OUTPUT);
- if(p.z > ts.pressureThreshhold){
- pres= true;
- // Serial.print(p.x); Serial.print(“ “); Serial.println(p.y);
-
- if (p.x>TSx_dices-100 && p.x<TSx_dices+100){
- if(p.y>Tsy_1st_dice-75 && p.y<Tsy_1st_dice+75)
- n=1;
- else if(p.y>Tsy_2nd_dice-75 && p.y<Tsy_2nd_dice+75)
- n=2;
- else if(p.y>Tsy_3th_dice-75 && p.y<Tsy_3th_dice+75)
- n=3;
- else if(p.y>Tsy_4th_dice-75 && p.y<Tsy_4th_dice+75)
- n=4;
- }
- }
- }
- //-------------------------------------------------------------------------------------
- //asking players colors
- for(int j=0;j<n;j++){
- pres=false;
- tft.fillScreen(PURPLE);
- tft.setRotation(1);
- tft.setCursor(20, 50);
- tft.setTextSize(3);
- tft.print(“player”);tft.print(j+1);tft.print(“ color?”);
- delay(200);
- tft.fillRoundRect(20,110,60,60,5,WHITE);
- tft.fillCircle(50,140,10,BLACK);
-
- tft.fillRoundRect(90,110,60,60,5,RED);
- tft.fillCircle(120,140,10,BLACK);
-
- tft.fillRoundRect(160,110,60,60,5,GREEN);
- tft.fillCircle(190,140,10,BLACK);
-
- tft.fillRoundRect(230,110,60,60,5,BLUE);
- tft.fillCircle(260,140,10,BLACK);
-
- while(!pres){
- digitalWrite(13, HIGH);
- TSPoint p = ts.getPoint();
- digitalWrite(13, LOW);
- pinMode(XM, OUTPUT);
- pinMode(YP, OUTPUT);
- if(p.z > ts.pressureThreshhold){
- pres= true;
- if (p.x>TSx_dices-100 && p.x<TSx_dices+100){
- if(p.y>Tsy_1st_dice-75 && p.y<Tsy_1st_dice+75)
- c[j]=WHITE;
- else if(p.y>Tsy_2nd_dice-75 && p.y<Tsy_2nd_dice+75)
- c[j]=RED;
- else if(p.y>Tsy_3th_dice-75 && p.y<Tsy_3th_dice+75)
- c[j]=GREEN;
- else if(p.y>Tsy_4th_dice-75 && p.y<Tsy_4th_dice+75)
- c[j]=BLUE;
- }
- }
- }
- }
- for(int i=0;i<n;i++){
- tft.fillScreen(c[i]);
- delay(200);
- }
- }
复制代码
程序收到玩家的数量及其颜色后,将启动主代码。 使用KY-037声音模块,可以对骰子下落进行计数并存储在count变量中。 然后将计数除以玩家人数,其余的将显示下一个回合。 每回合,LCD都会显示玩家的颜色,并等待直到他/她掷骰子。 当骰子掉落时,RGB LED会显示随机颜色,LCD会播放简单的骰子动画。 LCD右侧显示总体丢球计数。 - int j=1;
- void loop() {
- //calculation of players turn
- t=count%n;
- tft.fillScreen(c[t]);
- tft.setTextColor(YELLOW);
- tft.setRotation(1);
- tft.setCursor(0, 50);
- tft.setTextSize(3);
- tft.print("it's player");tft.print(t+1);tft.print(" turn");
-
- //showing number of dice fallen
- tft.fillRoundRect(225,110,60,60,5,BLACK);
- tft.setTextColor(YELLOW);
- tft.setRotation(1);
- tft.setTextSize(2);
- tft.setCursor(245, 135);
- tft.print(count);
- //sensing with microphone
- while(j==0){
- pinMode(13,INPUT);
- int a=digitalRead(ss);
- if(a==0)j=1;
- //showing the color of player whose turn is
- if(c[t]==RED){
- digitalWrite(rLED,HIGH);digitalWrite(gLED,LOW);digitalWrite(bLED,LOW);}
-
- if(c[t]==BLUE){
- digitalWrite(rLED,LOW);digitalWrite(gLED,LOW);digitalWrite(bLED,HIGH);}
-
- if(c[t]==GREEN){
- digitalWrite(rLED,LOW);digitalWrite(gLED,HIGH);digitalWrite(bLED,LOW);}
-
- if(t==WHITE){
- digitalWrite(rLED,HIGH);digitalWrite(gLED,HIGH);digitalWrite(bLED,HIGH);}
- }
- //LED equalizer
- if(j==1){
- for(int i=0;i<6;i==){
- digitalWrite(rLED,LOW);digitalWrite(gLED,HIGH);digitalWrite(bLED,HIGH);
- delay(100);
- digitalWrite(rLED,HIGH);digitalWrite(gLED,LOW);digitalWrite(bLED,HIGH);
- delay(100);
- digitalWrite(rLED,HIGH);digitalWrite(gLED,HIGH);digitalWrite(bLED,LOW);
- delay(100);
- digitalWrite(rLED,LOW);digitalWrite(gLED,LOW);digitalWrite(bLED,LOW);
- delay(100);
- //LCD dice animation
- tft.setTextColor(YELLOW);
- tft.setRotation(1);
- tft.setCursor(20, 200);
- tft.setTextSize(2);
- tft.print("Dice is falling...”);
- tft.fillRoundRect(130,110,60,60,5,WHITE);
- delay(200);
- Dice(random(6)+1);
- }
- a=1;
- j=0;
- }
- count++;
- }
- //-------------------------------------------------------------------------------------
- //dice drawing function
- void Dice(int d){
- if(d==1){
- tft.fillRoundRect(130,110,60,60,5,WHITE);
- tft.drawRoundRect(130,110,60,60,5,BLACK);
- tft.fillCircle(160,140,10,RED);
- }
- else if(d==2){
- tft.fillRoundRect(130,110,60,60,5,WHITE);
- tft.drawRoundRect(130,110,60,60,5,BLACK);
- tft.fillCircle(160,125,8,BLACK);
- tft.fillCircle(160,155,8,BLACK);
- }
- else if(d==3){
- tft.fillRoundRect(130,110,60,60,5,WHITE);
- tft.drawRoundRect(130,110,60,60,5,BLACK);
- tft.fillCircle(140,120,8,BLACK);
- tft.fillCircle(160,140,8,BLACK);
- tft.fillCircle(180,160,8,BLACK);
- }
- else if(d==4){
- tft.fillRoundRect(130,110,60,60,5,WHITE);
- tft.drawRoundRect(130,110,60,60,5,BLACK);
- tft.fillCircle(145,125,8,BLACK);
- tft.fillCircle(175,125,8,BLACK);
- tft.fillCircle(145,155,8,BLACK);
- tft.fillCircle(175,155,8,BLACK);
- }
- else if(d==5){
- tft.fillRoundRect(130,110,60,60,5,WHITE);
- tft.drawRoundRect(130,110,60,60,5,BLACK);
- tft.fillCircle(145,125,8,BLACK);
- tft.fillCircle(175,125,8,BLACK);
- tft.fillCircle(145,155,8,BLACK);
- tft.fillCircle(175,155,8,BLACK);
- tft.fillCircle(160,140,8,BLACK);
- }
- else if(d==6){
- tft.fillRoundRect(130,110,60,60,5,WHITE);
- tft.drawRoundRect(130,110,60,60,5,BLACK);
- tft.fillCircle(145,125,6,BLACK);
- tft.fillCircle(175,125,6,BLACK);
- tft.fillCircle(145,140,6,BLACK);
- tft.fillCircle(175,140,6,BLACK);
- tft.fillCircle(145,155,6,BLACK);
- tft.fillCircle(175,155,6,BLACK);
- }
- }
复制代码这部分代码使用Dice (number) 函数显示骰子数。
为了使游戏更有趣,可以使用图片代替颜色。 将您喜欢的图像保存在micro SD卡中,然后放入SD卡插槽。 以下代码从SD卡读取图像。 - void bmpDraw(String filename, int x, int y) {
- File bmpFile;
- int bmpWidth, bmpHeight; // W+H in pixels
- uint8_t bmpDepth; // Bit depth (currently must be 24)
- uint32_t bmpImageoffset; // Start of image data in file
- uint32_t rowSize; // Not always = bmpWidth; may have padding
- uint8_t sdbuffer[3 * BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
- uint16_t lcdbuffer[BUFFPIXEL]; // pixel out buffer (16-bit per pixel)
- uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
- boolean goodBmp = false; // Set to true on valid header parse
- boolean flip = true; // BMP is stored bottom-to-top
- int w, h, row, col;
- uint8_t r, g, b;
- uint32_t pos = 0, startTime = millis();
- uint8_t lcdidx = 0;
- boolean first = true;
- if ((x >= tft.width()) || (y >= tft.height())) return;
- Serial.println();
- Serial.print(F("Loading image ‘ ‘’));
- Serial.print(filename);
- Serial.println(‘\’’);
- // Open requested file on SD card
- if ((bmpFile = SD.open(filename)) == NULL){
- Serial.println(F("File not found”));
- return;
- }
- // Parse BMP header
- if (read16(bmpFile) == 0x4D42) { // BMP signature
- Serial.println(F("File size: ")); Serial.println(read32(bmpFile));
- (void)read32(bmpFile); // Read & ignore creator bytes
- bmpImageoffset = read32(bmpFile); // Start of image data
- Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
- // Read DIB header
- Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
- bmpWidth = read32(bmpFile);
- bmpHeight = read32(bmpFile);
- if (read16(bmpFile) == 1) { // # planes -- must be '1'
- bmpDepth = read16(bmpFile); // bits per pixel
- Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
- if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
- goodBmp = true; // Supported BMP format -- proceed!
- Serial.print(F("Image size:”));
- Serial.print(bmpWidth);
- Serial.print('x’);
- Serial.println(bmpHeight);
- // BMP rows are padded (if needed) to 4-byte boundary
- rowSize = (bmpWidth * 3 + 3) & ~3;
- // If bmpHeight is negative, image is in top-down order.
- // This is not canon but has been observed in the wild.
- if (bmpHeight < 0){
- bmpHeight = -bmpHeight;
- flip = false;
- }
- // Crop area to be loaded
- w = bmpWidth;
- h = bmpHeight;
- if ((x + w - 1) >= tft.width()) w = tft.width() - x;
- if ((y + h - 1) >= tft.height()) h = tft.height() - y;
-
- // Set TFT address window to clipped image bounds
- tft.setAddrWindow(x, y, x + w - 1, y + h – 1);
- for (row = 0; row < h; row++) { // For each scanline...
- // Seek to start of scan line. It might seem labor-
- // intensive to be doing this on every line, but this
- // method covers a lot of gritty details like cropping
- // and scanline padding. Also, the seek only takes
- // place if the file position actually needs to change
- // (avoids a lot of cluster math in SD library).
- if (flip) // Bitmap is stored bottom-to-top order (normal BMP)
- pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
- else // Bitmap is stored top-to-bottom
- pos = bmpImageoffset + row * rowSize;
- if (bmpFile.position() != pos) { // Need seek?
- bmpFile.seek(pos);
- buffidx = sizeof(sdbuffer); // Force buffer reload
- }
- for (col = 0; col < w; col++) { // For each column...
- // Time to read more pixel data?
- if (buffidx >= sizeof(sdbuffer)) { // Indeed
- // Push LCD buffer to the display first
- if (lcdidx > 0) {
- tft.pushColors(lcdbuffer, lcdidx, first);
- lcdidx = 0;
- first = false;
- }
- bmpFile.read(sdbuffer, sizeof(sdbuffer));
- buffidx = 0; // Set index to beginning
- }
- // Convert pixel from BMP to TFT format
- b = sdbuffer[buffidx++];
- g = sdbuffer[buffidx++];
- r = sdbuffer[buffidx++];
- lcdbuffer[lcdidx++] = tft.color565(r, g, b);
- }// end pixel
- }// end scanline
- // Write any remaining data to LCD
- if (lcdidx > 0){
- tft.pushColors(lcdbuffer, lcdidx, first);
- }
- Serial.print(F("Loaded in “));
- Serial.print(millis() – startTime);
- Serial.println(" ms”);
- }// end goodBmp
- {
- {
- bmpFile.close();
- if (!goodBmp) Serial.println(F("BMP format not recognized.”));
- }
- // These read 16- and 32-bit types from the SD card file.
- // BMP data is stored little-endian, Arduino is little-endian too.
- // May need to reverse subscript order if porting elsewhere.
- uint16_t read16(File f) {
- uint16_t result;
- ((uint8_t *)&result)[0] = f.read(); // LSB
- ((uint8_t *)&result)[1] = f.read(); // MSB
- return result;
- }
- uint32_t read32(File f) {
- uint32_t result;
- ((uint8_t *)&result)[0] = f.read(); // LSB
- ((uint8_t *)&result)[1] = f.read();
- ((uint8_t *)&result)[2] = f.read();
- ((uint8_t *)&result)[3] = f.read(); // MSB
- return result;
- }
复制代码将此函数放在主代码的末尾,并使用tft.fillScreen(c[t]); 替换整个代码中的bmpDraw(c[t], 0, 0); 。 然后,每回合,LCD都会显示玩家的图像而不是颜色。
变量c [t]应该是长度至少为10个字符的字符串。 它包含SD卡上图片的名称。SD卡上的所有图片必须为320×240像素,并且位图为24位格式。
以上就是本文的全部内容。您可以更改虚拟骰子的代码,以使掷出6的玩家获得另一次掷骰子机会的奖励。 |