สารบัญ:

เกมงู Arduino OLED: 3 ขั้นตอน
เกมงู Arduino OLED: 3 ขั้นตอน

วีดีโอ: เกมงู Arduino OLED: 3 ขั้นตอน

วีดีโอ: เกมงู Arduino OLED: 3 ขั้นตอน
วีดีโอ: How to make the Snake Game on Arduino: Arduino Snake Game | Arduino Projects 2024, กรกฎาคม
Anonim
เกมงู Arduino OLED
เกมงู Arduino OLED

สวัสดีและยินดีต้อนรับสู่คำแนะนำของเราเกี่ยวกับวิธีการสร้างและเกม Arduino OLED โปรเจ็กต์นี้เกิดขึ้นเมื่อเรากำลังพยายามสร้างเกมแรกของเราด้วย Arduino ดีมาก เราคิดว่าจะเริ่มต้นที่ไหนดีกว่างูคลาสสิกของ Nokia (ดีที่ อย่างน้อยโคลนงู:))

สิ่งที่คุณต้องการ

เสบียง

Arduino UNO หรือโคลน

จอแสดงผล OLED

4 ไดโอด

ตัวต้านทาน 500-1k

4 ปุ่มควบคุม

ออด Piezo แบบพาสซีฟ

ไม่จำเป็น

เขียงหั่นขนมไร้บัดกรี

โปรดทราบว่าลิงก์เหล่านี้เป็นเพียงตัวอย่างเท่านั้น

ขั้นตอนที่ 1: วงจร

The Circuit
The Circuit

ในภาพด้านบนคุณจะเห็นวงจรของเรา เราใช้พิน d3 บน Arduino เป็นพินคำขอขัดจังหวะ เพื่อให้ Arduino ให้ความสำคัญกับการอ่านอินพุตคอนโทรลเลอร์ซึ่งก็คือ d4 d5 d6 d7 พื้นฐานของวงจรคือการกดปุ่มทิศทางซึ่งสูง 5v ซึ่งจะเปิดใช้งานพินคำขอขัดจังหวะ (d3 สายสีม่วง) และพินทิศทางที่สอดคล้องกัน ฟังก์ชันขัดจังหวะจะเรียกใช้ฟังก์ชันทิศทางการอัปเดตและรหัสนั้นจะย้ายงูตามลำดับ พิน 9 ใช้เป็นพินเสียงเนื่องจากเป็น PWM (~ การมอดูเลตความกว้างพัลส์) ซึ่งเชื่อมต่อโดยตรงกับ 5v piezo บนพิน + และ - จะกลับไปที่ 0v/กราวด์

(FYI บน Arduino uno และโคลนเฉพาะ d2 และ d3 เท่านั้นที่สามารถทำหน้าที่เป็นหมุดคำขอขัดจังหวะ)

หมุดทิศทาง:

d4 ขึ้น สีส้ม

d5 ลงสีชมพู

d6 ซ้าย BLUE

d7 ขวา BROWN

d9 เสียงสีเทา

แต่ละปุ่มมีอินพุตการเชื่อมต่อ 5v และเอาต์พุตที่เชื่อมต่อกับอินพุตดิจิตอลตามลำดับบน Arduino ก่อน จากนั้นเอาต์พุตเดียวกันของแต่ละปุ่มจะเชื่อมต่อกับไดโอดของมันเอง เราใช้ไดโอดเพื่อหยุดการป้อนแรงดันไฟฟ้ากลับไปยัง ปุ่มอื่นๆ และเปิดใช้งาน ที่ปลายแคโทด (-) ของไดโอดทั้ง 4 ตัว เรารวมพวกมันเข้าด้วยกันเพื่อสร้างทางแยกเอาต์พุตที่เชื่อมต่อกับ d3 จากนั้นผ่านตัวต้านทานไปที่ 0v/earth เพื่อดึงพิน Arduino ให้ต่ำเพื่อไม่ให้พินลอยเมื่อไม่ได้อยู่ เปิดใช้งาน

(FYI พินลอยสามารถรับแรงดันไฟหลอกและทำให้เกิดพฤติกรรมผิดปกติได้)

ใช้พินอะนาล็อก 2 อันเพื่อขับเคลื่อนจอแสดงผล นี่คือพินฮาร์ดแวร์ Arduino i2c

A5 เชื่อมต่อกับ SCL YELLOW

A4 เชื่อมต่อกับ SDA GREEN

เอาต์พุต +5v และ 0v (สายดิน) จาก Arduino ถูกใช้เป็นแหล่งพลังงานสำหรับวงจรทั้งหมด ซึ่งสามารถจ่ายไฟด้วย USB หรือเครื่องชาร์จโทรศัพท์

ขั้นตอนที่ 2: รหัส

//----------------------- ANJAWARE SNAKE Games ด้วยความช่วยเหลือจากชาวเน็ต --------------- --------

#รวม

#include // https://github.com/adafruit/Adafruit-GFX-Library #include // https://github.com/adafruit/Adafruit-GFX-Library // ชุดแสดงผล (ความกว้าง, ความสูง) Adafruit_SSD1306 display(128, 64); // กำหนดพินอินพุท นี่คือพินบน Arduino ที่พวกเขาไม่เคยเปลี่ยน ดังนั้น #define #define INTPIN 3 // เฉพาะพิน 2 และ 3 เท่านั้นที่สามารถเป็นพินอินเทอร์อัปบน UNO #define UPPIN 4 // สิ่งเหล่านี้คือพินที่เชื่อมต่อ tp สวิตช์ที่เกี่ยวข้อง #define DWNPIN 5 #define LFTPIN 6 #define RHTPIN 7 #define SND 9 // กำหนดทิศทาง #define DIRUP 1 // ค่าเหล่านี้คือสิ่งที่ "งู" มองเพื่อตัดสินใจ - #define DIRDOWN 2 // ทิศทางที่งูจะเดินทาง # นิยาม DIRLEFT 3 #define DIRRIGHT 4

// ตั้งค่าตัวแปรปุ่ม

// ระเหยเพราะเราต้องการให้มันอัปเดตด้วยการขัดจังหวะเพื่อให้สามารถเป็นค่ารอบได้

// ไม่เคยสูงกว่า 4 ดังนั้นต้องการเพียง 8 บิต int เพื่อประหยัดทรัพยากร uint8_t buttonpressed = 0; บูลบัตอัพ=0; ปุ่มบูลดาวน์=0; // เราใช้สิ่งนี้เพื่อตั้งค่าจริงเป็น "ตรวจจับ" ว่าทิศทางใดที่กด bool butleft=0; บูล แต่ไรท์=0;

// งู ints

ไบต์ snakePosX[30]; // อาร์เรย์เพื่อสร้างเนื้อความของงูไบต์ snakePosY[30];

int งูX=30; // ตำแหน่งหัวงู

int งูY=30; int งูขนาด=1; // ขนาดงู จำกัด อยู่ที่ขนาดของอาร์เรย์

// โลกทั้งใบ

uint8_t worldMinX=0; // สิ่งเหล่านี้กำหนดขอบเขตของพื้นที่เล่น

uint8_t worldMaxX=128; uint8_t worldMinY=10; uint8_t worldMaxY=63;

// เก็บ scran(อาหาร) และตำแหน่งของ scran

บูล scranAte =0; uint8_t scranPosX=0; uint8_t scranPosY=0;

// คะแนนตัวแปร

playcore แบบยาว=0; คะแนนสูงสุดยาว = 30; // ตั้งคะแนนสูงเป็น 3 รวบรวมเป็นจุดเริ่มต้น

//--------------------------- นี่คือสิ่งที่อินเตอร์รัปต์ทำงานเมื่อแรงดันไฟฟ้าเพิ่มขึ้น ------------ --------------

โมฆะถูกขัดจังหวะ () { ล่าช้า (150); // หน่วงเวลาเล็กน้อยสำหรับการป้องกัน "ตีกลับ" ที่เพิ่มเข้ามา updatedirection(); } // ------------------ อัปเดตค่าทิศทางจากการกดปุ่ม ----------------- void updatedirection() { // Serial.println("updatingdirection"); butup=digitalRead(UPPIN); // ตรวจสอบว่าอินพุตใดสูงและตั้งค่าบูลที่เกี่ยวข้อง true butdown=digitalRead(DWNPIN); butleft=digitalRead(LFTPIN); butright=digitalRead(RHTPIN); // สิ่งเหล่านี้หาก statemeents ดูว่าอินพุตใดสูงและป้อนค่าที่เกี่ยวข้องในตัวแปร "buttonpressed" // ตัวแปรนี้กำหนดทิศทางของการเคลื่อนไหว if(butup==true) { buttonpressed=DIRUP; // Serial.println("กดขึ้น"); // Serial.println (ปุ่มกด); butup=เท็จ; โทน (SND, 1500, 10); } if(butdown==true) { buttonpressed=DIRDOWN; // Serial.println("กดลง"); // Serial.println (ปุ่มกด); ปุ่มลัด=เท็จ; โทน (SND, 1500, 10); }

ถ้า(butleft==จริง)

{ กดปุ่ม = DIRLEFT; // Serial.println("กดซ้าย"); // Serial.println (ปุ่มกด); butleft=false; โทน (SND, 1500, 10); } if(butright==true) { กดปุ่ม = DIRRIGHT; // Serial.println("กดขวา"); // Serial.println (ปุ่มกด); butright=false; โทน (SND, 1500, 10); } }

//-------------------------- วาดขั้นตอนการแสดงผล ------------------ -----------------

ถือเป็นโมฆะ updateDisplay() // วาดคะแนนและโครงร่าง

{ // Serial.println ("อัปเดตการแสดงผล");

display.fillRect(0, 0, display.width()-1, 8, BLACK);

display.setTextSize(0); display.setTextColor(สีขาว); // วาดคะแนน display.setCursor(2, 1); display.print("คะแนน:"); display.print(สตริง(playscore, ธ.ค.)); display.setCursor(66, 1); display.print("สูง:"); display.print(สตริง(คะแนนสูงสุด ธ.ค.)); // วาดพื้นที่เล่น // pos 1x, 1y, 2x, 2y, color display.drawLine(0, 0, 127, 0, WHITE); // ขอบบนสุด display.drawLine (63, 0, 63, 9, WHITE); // ตัวคั่นคะแนน display.drawLine(0, 9, 127, 9, WHITE); // ด้านล่างเส้นขอบข้อความ display.drawLine(0, 63, 127, 63, WHITE); // ขอบล่าง display.drawLine(0, 0, 0, 63, WHITE); // ขอบซ้าย display.drawLine(127, 0, 127, 63, WHITE); //ขอบขวา

}

//----------------------------------- อัปเดตพื้นที่เล่น ---------- --------------------

ถือเป็นโมฆะ updateGame() // อัปเดตพื้นที่เกม display

{ display.clearDisplay();

display.drawPixel (scranPosX, scranPosY, สีขาว);

scranAte = scranFood();

// ตรวจสอบกิจวัตรงู

ถ้า (outOfArea()||selfCollision())

{ จบเกม(); }

//แสดงงู

สำหรับ (int i=0;i0;i--) { snakePosX = snakePosX[i-1]; งูPosY = งูPosY[i-1]; } // เพิ่มพิกเซลพิเศษให้กับงูถ้า (scranAte) { snakeSize+=1; snakePosX[snakeSize-1]=snakeX; snakePosY[snakeSize-1]=snakeY; }

switch(buttonpressed) // เป็น snakeDirection

{ กรณี DIRUP: งูY-=1; หยุดพัก; กรณี DIRDOWN: งูY+=1; หยุดพัก; กรณี DIRLEFT: snakeX-=1; หยุดพัก; กรณี DIRRIGHT: งูX+=1; หยุดพัก; } งูPosX[0] = งูX; งูPosY[0] = งูY; อัปเดตดิสเพลย์ (); display.display(); // --------------------- วาง scran --------------------

เป็นโมฆะ placeScran()

{ scranPosX=random(worldMinX+1, worldMaxX-1); scranPosY=random(worldMinY+1, worldMaxY-1); } // ------------------------ SCRAN ATE POINT UP ---------------- bool scranFood() { if(snakeX==scranPosX&&snakeY==scranPosY) {playscore=playscore+10; โทน (SND, 2000, 10); อัปเดตดิสเพลย์ (); placeScran(); ส่งคืน 1; } อื่น ๆ { กลับ 0; } } //--------------------- นอกพื้นที่---------------------- bool outOfArea () { กลับ snakeX = worldMaxX ||snakeY = worldMaxY; } //---------------------- จบเกม----------------------- --- โมฆะ gameOver () { uint8_t rectX1, rectY1, rectX2, rectY2; rectX1=38; rectY1=28; rectX2=58; rectY2=12; display.clearDisplay(); display.setCursor(40, 30); display.setTextSize(1); โทน (SND, 2000, 50); display.print("เกม"); โทน (SND, 1000, 50); display.print("OVER"); if(playscore>=highscore) //ตรวจสอบว่าคะแนนสูงกว่าคะแนนสูงหรือไม่ { highscore=playscore; // single if statment เพื่ออัปเดตคะแนนสูง } สำหรับ (int i=0;i<=16;i++) // นี่คือการวาดสี่เหลี่ยมรอบเกมเหนือ { display.drawRect(rectX1, rectY1, rectX2, rectY2, WHITE); Serial.println("ถ้าวนซ้ำ"); display.display(); rectX1-=2; // เลื่อนไป 2 พิกเซล rectY1-=2; rectX2+=4; // เลื่อนมากกว่า 2 พิกเซลจากจุดสุดท้าย rectY2+=4; โทน(SND, i*200, 3); } display.display(); //Screen Wipe หลังจากชื่อเสียงเหนือ rectX1=0; // กำหนดตำแหน่งเริ่มต้นของเส้น rectY1=0; rectX2=0; rectY2=63; สำหรับ (int i =0;i<=127;i++) { uint8_t cnt=0; display.drawLine(rectX1, rectY1, rectX2, rectY2, สีดำ); rectX1++; rectX2++; display.display(); } display.clearDisplay(); เพลย์สกอร์=0; // รีเซ็ตรายละเอียดงูและผู้เล่น snakeSize=1; snakeX=display.width()/2; งูY=display.height()/2; waitForPress(); // รอให้ผู้เล่นเริ่มเกม } //----------------------------------- รอการกดวน ---------- --------------- เป็นโมฆะ waitForPress () { บูลรอ = 0; // วนรอบสิ้นสุดลงเมื่อนี่คือ display.clearDisplay(); ในขณะที่ (รอ == 0) { drawAlineForMe (สีขาว); // วาดเส้นสีขาวแบบสุ่ม drawAlineForMe(BLACK); // วาดเส้นสีดำแบบสุ่มเพื่อไม่ให้หน้าจอเต็ม display.fillRect(19, 20, 90, 32, BLACK); // พื้นหลังว่างสำหรับ text display.setTextColor(WHITE); display.setCursor (35, 25); display.setTextSize(2); // แบบอักษรที่ใหญ่กว่า display.println("SNAKE"); // x y w hr col display.drawRoundRect(33, 22, 62, 20, 4, WHITE); // เส้นขอบงู display.drawRect (19, 20, 90, 32, WHITE); // กล่องเส้นขอบ - 3 display.setCursor(28, 42); display.setTextSize(0); // แบบอักษรกลับไปที่ display.println ปกติ ("กดปุ่มใดก็ได้"); display.display(); รอ = digitalRead (INTPIN); // ตรวจสอบเพื่อดูว่าการกดปุ่มรอจะเปลี่ยนเป็น 1 สิ้นสุดในขณะที่กดปุ่ม = 0; // กดปุ่มรีเซ็ต } } //-------------------- วาดสีอินพุตบรรทัดสุ่ม uint8_t -------------- ----- เป็นโมฆะ drawAlineForMe (uint8_t clr) { uint8_t line1X, line1Y, line2X, line2Y = 0; // กำหนดพิกัดสุ่มสำหรับเส้นแล้ววาดมัน // ตัวแปรไม่น้อยกว่าไม่มีอีกแล้ว line1X = สุ่ม (worldMinX+1, worldMaxX-1); line1Y = สุ่ม (worldMinY+1, worldMaxY-1); line2X = สุ่ม (worldMinX+1, worldMaxX-1); line2Y = สุ่ม (worldMinY+1, worldMaxY-1); display.drawLine(line1X, line1Y, line2X, line2Y, clr); } //------------------------------------------ การตรวจจับการชน -------- ------------------------

for(byte i=4;i<snakeSize;i++) { if(snakeX==snakePosX&&snakeY==snakePosy) { return 1; โทน (SND, 2000, 20); โทน (SND, 1000, 20); } คืนค่า 0; }

//-------------------------------- ติดตั้ง--------------- -------------------------------------

การตั้งค่าเป็นโมฆะ () { ล่าช้า (100); // เพียงแค่ให้โอกาสในการ "บูต" // Serial.begin(9600); // ยกเลิกการเลือกนี้หากคุณต้องการดูเอาต์พุตอนุกรม display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); // เริ่มต้นด้วยการแสดงผลที่สะอาดหมดจด display.setTextColor(WHITE); // ตั้งค่าขนาดการหมุนสีข้อความ ฯลฯ display.setRotation(0); display.setTextWrap (เท็จ); display.dim(0); // ตั้งค่า pinMode ความสว่างของจอแสดงผล (INTPIN, INPUT); // ตั้งค่าพอร์ตที่ถูกต้องเป็นอินพุต pinMode (UPPIN, INPUT); โหมดพิน (DWNPIN, อินพุต); โหมดพิน (LFTPIN, INPUT); โหมดพิน (RHTPIN, อินพุต); // นี่คือคำสั่ง interupt ซึ่ง "หยุด" Arduino เพื่ออ่านอินพุต //command- function- pin-function เพื่อดำเนินการเงื่อนไขบน pin AttachInterrupt (digitalPinToInterrupt (INTPIN), ขัดจังหวะ, RISING); // Serial.println("การตั้งค่าผ่าน"); waitForPress(); // แสดงหน้าจอเริ่มต้นของงู placeScran(); // วางอาหารมื้อแรก } //--------------------------- MAIN LOOP----------------- ---------------------- วงเป็นโมฆะ () { updateGame (); // ฟังก์ชั่นนี้คือสิ่งที่ถือรหัสหลัก }

ขั้นตอนที่ 3:

แนะนำ: