เกมคอนโซลบน Arduino คอนโซลเกมทีวีที่เรียบง่ายที่ใช้ Arduino ฟังก์ชั่นการรับพารามิเตอร์



มาเริ่มสร้างเกมด้วยชื่อรหัสว่า “Arithmetic Collector” ผู้เล่นถูกควบคุมโดยจอยสติ๊กซึ่งมีความสามารถในการเคลื่อนที่ไปรอบๆ สนามขนาด 128x90 ด้วยการโก่งตัวของจอยสติ๊กเป็นศูนย์ เครื่องเล่นจะอยู่ตรงกลาง การเบี่ยงเบนของจอยสติ๊กสูงสุดสอดคล้องกับการเคลื่อนไหวสูงสุดของผู้เล่น ในช่วงระยะเวลาหนึ่ง วัตถุตัวเลขจะถูกสร้างขึ้นโดยเลื่อนจากบนลงล่าง เมื่อไปถึงตำแหน่งด้านล่างของหน้าจอ วัตถุรูปร่างจะหายไป โดยลดคะแนนของผู้เล่นตามมูลค่าของตัวเลขนี้ หากผู้เล่นสกัดกั้นวัตถุตัวเลขบนหน้าจอ สิ่งนี้จะทำให้วัตถุตัวเลขหายไปและตัวนับแต้มของผู้เล่นจะเพิ่มขึ้น ในช่วงเวลาหนึ่ง ไอคอนของผู้เล่นจะเปลี่ยนค่าจากเลข 0 เป็น 9 เมื่อสกัดกั้นวัตถุหลัก ตัวนับคะแนนของผู้เล่นจะเพิ่มขึ้นตามจำนวนเท่ากับผลรวมของวัตถุหลักและหลักของผู้เล่น หากตัวเลขของผู้เล่นเป็น เท่ากับหลักของวัตถุหลัก จากนั้นตัวนับแต้มของผู้เล่นจะเพิ่มขึ้นตามผลคูณของตัวเลข เมื่อถึงเกณฑ์ที่กำหนดการเปลี่ยนแปลงไปสู่ระดับที่สูงขึ้นของเกมจะเกิดขึ้นซึ่งนำไปสู่การเพิ่มความเร็วในการเคลื่อนที่และความเร็วในการสร้างวัตถุตัวเลข นอกจากนี้ จากระดับ 4 ของเกม การชนกันของผู้เล่นกับวัตถุหลักไม่เพียงทำให้เคาน์เตอร์ของผู้เล่นเพิ่มขึ้นเท่านั้น แต่ยังลดลงอีกด้วย (หากตัวเลขของผู้เล่นน้อยกว่าหลักของวัตถุหลัก) หากคะแนนของผู้เล่นลดลงต่ำกว่า 0 เกมจะเริ่มต้นใหม่

นี่คือวิดีโอของสิ่งที่เกิดขึ้น

คุณสามารถดาวน์โหลดไฟล์เก็บถาวรด้วยไฟล์ภาพร่างและไลบรารี TVOut ได้จากลิงก์

และขั้นตอนการสร้างเกม

การสร้างตัวแปรเกม

เพื่อควบคุมเกมเราจะสร้างวัตถุเพื่อจัดเก็บตำแหน่งปัจจุบันของเกม สัญลักษณ์ที่แสดงถึงผู้เล่นและสัญลักษณ์ที่แสดงถึงวัตถุตัวเลขจะแสดงเป็นข้อมูลข้อความ ดังนั้นเราจะแบ่งสนามเกมทั้งหมดออกเป็นเส้น และการเคลื่อนไหวของวัตถุทั้งหมดจะดำเนินการเมื่อสัญลักษณ์ถูกส่งไปยังสถานที่ที่คุ้นเคยบนสนาม ตัวแปร MAX_X=31 และ MAX_Y=14 กำหนดขนาดของสนามเกมด้วยจำนวนช่องว่างที่คุ้นเคยในแนวนอนและแนวตั้ง ตัวแปร MAX_OBJ=30 กำหนดจำนวนวัตถุตัวเลขสูงสุดบนสนามแข่งขันในเวลาเดียวกัน อาร์เรย์ int FIGURA จัดเก็บข้อมูลเกี่ยวกับวัตถุตัวเลขที่อยู่ในสนามเกมดังต่อไปนี้:

  • FIGURA[i] – ค่าตัวเลขของวัตถุหลัก (0 – วัตถุว่าง);
  • FIGURA[i] – พิกัด x ปัจจุบันของวัตถุหลัก
  • FIGURA[i] – พิกัด y ปัจจุบันของวัตถุหลัก

เพื่อจัดเก็บตัวแปรอื่นๆ ที่อธิบาย สถานะปัจจุบันเกม เรามาสร้างโครงสร้าง GAME กัน รายการฟิลด์โครงสร้าง:

  • xk – พิกัด x(/4) ของผู้เล่น;
  • yk – ประสานงาน y(/6) ของผู้เล่น;
  • tekCursor – ค่าเคอร์เซอร์ปัจจุบัน
  • BlinkCursor – สถานะปัจจุบันของเคอร์เซอร์กะพริบ;
  • vblink – ความเร็วการกะพริบใน vk;
  • vk – ความเร็วในการเคลื่อนที่ของผู้เล่น – ตรวจสอบอินพุต A0, A1;
  • vo_10 – อัตราการเปลี่ยนแปลงหลักของผู้เล่น
  • vo_11 – ความเร็วของการปรากฏตัวของวัตถุตัวเลข
  • vo_12 – ความเร็วการเคลื่อนที่ของวัตถุดิจิทัล
  • count_objects – จำนวนวัตถุตัวเลขบนสนาม
  • ระดับ – ระดับเกม;
  • ลูกบอล – จำนวนแต้ม

อินท์ MAX_X=31; อินท์ MAX_Y=14; // โครงสร้างข้อมูลเกม struct GAME // โครงสร้างสำหรับข้อมูลเกม ( int xk; // x(/4) พิกัดของผู้เล่น int yk; // y(/6) พิกัดของผู้เล่น int tekCursor; // ค่าเคอร์เซอร์ปัจจุบัน int กะพริบเคอร์เซอร์; / / สถานะปัจจุบันของเคอร์เซอร์กะพริบ; // ความเร็วของการกะพริบใน vk ยาว vk; // ความเร็วของการเคลื่อนไหวของผู้เล่น - ตรวจสอบอินพุต A0, A1 ยาว vo_10; ของการเคลื่อนไหวของตัวเลข int count_objects; // จำนวนวัตถุในระดับ int ของสนาม; // จำนวนคะแนน); int MAX_OBJ=30; int รูป=((0,0,0),(0,0,0),(0,0,0),(0,0,0),(0,0,0), (0,0,0 ),(0,0,0),(0,0,0),(0,0,0),(0,0,0), (0,0,0),(0,0,0), (0,0,0),(0,0,0),(0,0,0), (0,0,0),(0,0,0),(0,0,0),(0 ,0,0),(0,0,0), (0,0,0),(0,0,0),(0,0,0),(0,0,0),(0,0 ,0), (0,0,0),(0,0,0),(0,0,0),(0,0,0),(0,0,0) );

การควบคุมตำแหน่งของผู้เล่นโดยใช้จอยสติ๊ก

ตำแหน่งของผู้เล่นบนหน้าจอถูกกำหนดโดยการเคลื่อนไหวของจอยสติ๊ก หมุดจอยสติ๊กเชื่อมต่อกับพอร์ตอะนาล็อก A0, A1 ของบอร์ด Arduino พอร์ตจะถูกสำรวจหลังจากเวลาที่กำหนดโดยพารามิเตอร์ GAME.vk ข้อมูลนี้จะถูกประมวลผลโดยฟังก์ชัน map() ซึ่งจะถ่ายโอนค่าจากช่วงปัจจุบัน 0-124 ไปยังช่วงใหม่ตามสัดส่วน (ค่าความกว้างและความสูงของหน้าจอ) ค่านี้จะถูกแปลงเป็นพิกัดที่คุ้นเคย จำเป็นต้องย้ายรูปภาพสัญลักษณ์ของผู้เล่นไปยังตำแหน่งที่คุ้นเคย หลังจากวางสัญลักษณ์ช่องว่างในตำแหน่งก่อนหน้าของผู้เล่นแล้ว ในการแสดงเครื่องเล่น จะใช้สัญลักษณ์กะพริบ - ตัวเลขและช่องว่าง

//****************** การตั้งค่าตำแหน่งผู้เล่นใหม่เป็นโมฆะ set_iam() ( TV.set_cursor(min(123,GAME1.xk*4),min(84,GAME1) .yk*6)); GAME1.xk=map(analogRead(A0), 0, 1024, 0, 128); GAME1.xk=GAME1.xk/4; .yk/6;<0) { GAME1.blinkCursor=1-GAME1.blinkCursor; GAME1.vblink=5+GAME1.blinkCursor*5; } TV.set_cursor(min(123,GAME1.xk*4),min(84,GAME1.yk*6)); if(GAME1.blinkCursor==1) TV.print(GAME1.tekCursor); else TV.print(” “); }

สัญลักษณ์ที่แสดงถึงผู้เล่นจะเปลี่ยนไปหลังจากเวลาที่กำหนดโดยพารามิเตอร์ GAME.vo_10 โดยการเรียกฟังก์ชัน set_new_cursor() การเปลี่ยนแปลงจะเกิดขึ้นแบบสุ่มโดยใช้ฟังก์ชัน Random()

//****************** การตั้งค่ารูปแบบใหม่ของสัญลักษณ์ผู้เล่นเป็นโมฆะ set_new_cursor() ( GAME1.tekCursor=random(0,10); )

การสร้างและการเคลื่อนไหวของวัตถุดิจิทัล

ออบเจ็กต์ตัวเลขจะถูกสร้างขึ้นหลังจากเวลาที่ระบุโดยพารามิเตอร์ GAME.vo11 ฟังก์ชัน set_new_object() เรียกว่า ข้อมูลเกี่ยวกับออบเจ็กต์หลักทั้งหมดจะถูกจัดเก็บไว้ในอาร์เรย์ FIGURA โปรแกรมค้นหาดัชนีว่างตัวแรกในอาร์เรย์ (FIGURA=0) และวางวัตถุหลักใหม่ในนั้น ค่าดิจิทัลและพิกัดแนวนอนของวัตถุใหม่จะถูกสร้างขึ้นโดยฟังก์ชันสุ่ม และพิกัดแนวตั้งจะถูกตั้งค่าเป็นศูนย์ สัญลักษณ์ที่แสดงถึงวัตถุหลักใหม่จะแสดงบนหน้าจอ

//****************** การปรากฏตัวของวัตถุตัวเลขใหม่เป็นโมฆะ set_new_object() ( int null_index=0; if(GAME1.count_objects)<>( สำหรับ(int i=0;i;i++)<>( ถ้า(FIGURA[i]==0) (null_index=i;break;) ) FIGURA=สุ่ม(1,9); รูปที่=สุ่ม(0,MAX_X); รูป=0; // ส่งออกไปยังบอร์ด TV.set_cursor(FIGURA*4,0); TV.print(ฟิกูรา); GAME1.count_objects++; -

ฟังก์ชันสำหรับเคลื่อนย้ายวัตถุดิจิทัล (go_object()) จะถูกเรียกหลังจากเวลาที่ระบุโดยพารามิเตอร์ GAME.vo12 การแสดงการเคลื่อนไหวของวัตถุหลักเกิดขึ้นโดยการลบสัญลักษณ์ออกจากตำแหน่งก่อนหน้าของวัตถุ (การเขียนอักขระเว้นวรรค) และการเขียนสัญลักษณ์วัตถุไปยังตำแหน่งใหม่ (พิกัดแนวตั้งของความคุ้นเคยของวัตถุหลักเพิ่มขึ้นทีละหนึ่ง) . เมื่อไปถึงด้านล่างสุดของหน้าจอ วัตถุตัวเลขจะถูกลบ (เขียน 0 ไปยังองค์ประกอบอาร์เรย์ FIGURA[i]) รวมถึงจำนวนคะแนนผู้เล่นจะลดลง

//****************** การเคลื่อนไหวของวัตถุหลักเป็นโมฆะ go_object() ( for(int i=0;i;i++)<>( ถ้า(FIGURA[i]>0) ( TV.set_cursor(FIGURA[i]*4,FIGURA[i]*6); TV.print(" "); ถ้า(FIGURA[i])<>( FIGURA[i]++; TV.set_cursor(FIGURA[i]*4,FIGURA[i]*6); TV.print(FIGURA[i]); ) else ( TV.tone(294,200); change_balls(FIGURA [i]*(-1)); FIGURA[i]=0; GAME1.count_objects– ) )

ตรวจสอบการชนกันระหว่างเครื่องเล่นกับวัตถุที่เป็นตัวเลข

เมื่อย้ายสัญลักษณ์ผู้เล่นผ่านหน้าจอ จำเป็นต้องตรวจสอบการชนกันระหว่างผู้เล่นและวัตถุตัวเลข เมื่อต้องการทำเช่นนี้ เราใช้ฟังก์ชัน collision() หลังจากตั้งค่าสัญลักษณ์ที่สอดคล้องกับผู้เล่นแล้ว เราจะตรวจสอบองค์ประกอบของอาร์เรย์ FIGURA เพื่อดูว่าพิกัดของวัตถุหลักสอดคล้องกับพิกัดของสัญลักษณ์ของผู้เล่นหรือไม่ หากพิกัดตรงกัน ให้ดำเนินการต่อไปนี้:

  • วัตถุหลักจากอาร์เรย์ FIGURA ถูกทำลาย (รายการ 0 ใน FIGURA[[i]);
  • ลดลง 1 ตัวนับสำหรับจำนวนวัตถุที่เป็นตัวเลข (GAME.count_objects)
  • ตัวนับแต้มของผู้เล่นมีการเปลี่ยนแปลง (เรียกว่าฟังก์ชัน change_balls())

//****************** ตรวจสอบการชน การชนกันเป็นโมฆะ () ( สำหรับ (int i = 0; i; i ++)<>( ถ้า(FIGURA[i]>0) ( ถ้า(FIGURA[i]==GAME1.xk && FIGURA[i]==GAME1.yk) ( TV.tone(740,200); if(FIGURA[i]==GAME1 .tekCursor) change_balls(GAME1.tekCursor*GAME1.tekCursor); อย่างอื่นถ้า(FIGURA[i]>GAME1.tekCursor && GAME1.level>3) change_balls(FIGURA[i]*(-1)); tekCursor); FIGURA[i]=0;

ฟังก์ชั่นการเปลี่ยนตัวนับแต้มของผู้เล่น (change_balls()) จะส่งผ่านเป็นอาร์กิวเมนต์จำนวนที่ควรเพิ่มตัวนับแต้มของผู้เล่น (ลดลง) ตัวเลขนี้เท่ากับผลรวมของวัตถุหลักและหลักของผู้เล่น หากตัวเลขของผู้เล่นเท่ากับตัวเลขของวัตถุหลัก ค่าที่เท่ากับผลคูณของตัวเลขจะถูกส่งไป เพื่อเพิ่มความยากของเกมจากระดับ 4 การชนกันของผู้เล่นกับวัตถุหลักไม่เพียงแต่ส่งผลให้ตัวนับของผู้เล่นเพิ่มขึ้นเท่านั้น แต่ยังลดลงอีกด้วย (หากตัวเลขของผู้เล่นน้อยกว่าหลักของวัตถุหลัก)

ผู้เล่นนับแต้ม

ฟังก์ชัน change_balls() จะเปลี่ยนตัวนับแต้มของผู้เล่นตามค่าของอาร์กิวเมนต์ที่เข้ามา หากตัวนับคะแนนลดลงต่ำกว่า 0 เกมจะจบลง หน้าจอจะถูกล้าง และเกมจะกลับสู่จุดเริ่มต้น นอกจากนี้ เมื่อตัวนับถึงค่าที่กำหนด เกมจะย้ายไปยังระดับใหม่ที่สูงขึ้น ฟังก์ชัน new_level() ตั้งค่าสำหรับระดับใหม่

//****************** การเปลี่ยนคะแนนเป็นโมฆะ change_balls(int ball) ( GAME1.balls=GAME1.balls+ball; if(GAME1.balls<0) start_game(); if(GAME1.balls>(GAME1.ระดับ+1)*100) new_level(GAME1.ระดับ); set_data_tablo(); -

ยกระดับไปอีกขั้น

เมื่อย้ายไปยังระดับใหม่ของเกม ค่าใหม่จะถูกตั้งค่าสำหรับความเร็วในการสร้างและความเร็วในการเคลื่อนที่ของวัตถุตัวเลข ในตอนแรกตั้งใจที่จะเปลี่ยนค่าอัตราการเปลี่ยนแปลงของตัวเลขของผู้เล่นและความเร็วในการเคลื่อนที่ของผู้เล่น แต่ในระหว่างการทดสอบเกม ฉันตัดสินใจละทิ้งสิ่งนี้ การดำเนินการตั้งค่าตัวแปรสำหรับระดับเกมใหม่จะดำเนินการในฟังก์ชัน new_level()

//****************** เปลี่ยนระดับเกมเป็นโมฆะ new_level(int tek_level) ( GAME1.level++; GAME1.vo_10=5000; GAME1.vo_11=2000-(GAME1. ระดับ -1)*100; GAME1.vo_12=1000-(GAME1.level-1)*100;

การแสดงข้อมูลเกมบนกระดานคะแนน

แผงข้อมูลผู้เล่นจะอยู่ที่ด้านล่างของหน้าจอ ค่าปัจจุบันของจำนวนคะแนนที่ได้และระดับของเกมจะแสดงที่นี่ เมื่อตัวนับคะแนนของผู้เล่นเปลี่ยนแปลง ฟังก์ชัน set_data_tablo() จะถูกเรียกใช้ ซึ่งจะเปลี่ยนค่าของจำนวนคะแนนที่ทำได้และระดับของเกมในตัวแปรของโครงสร้าง GAME และบนกระดานคะแนน

//****************** ส่งออกข้อมูลไปยังกระดานคะแนนเป็นโมฆะ set_data_tablo() ( TV.print(20,91,” ball= “); TV.print(70, 91 ,"ระดับ= "); TV.print(48,91,GAME1.balls); TV.print(98,91,GAME1.level);

เพลงประกอบเกม

สำหรับการออกแบบเสียงของเกม เราจะใช้ฟังก์ชันโทนเสียง (ความถี่ ระยะเวลา) ของไลบรารี TVOut เมื่อวัตถุตัวเลขมาถึงด้านล่างสุดของสนามแข่งขัน - TV.tone(294,200) (ฟังก์ชัน go_object()) เมื่อผู้เล่นและวัตถุตัวเลขชนกัน - TV.tone(740,200) (ฟังก์ชัน collision()) หากคุณต้องการแทรกแฟรกเมนต์จากการเล่นตามลำดับของโน้ตหลายตัวลงในโปรเจ็กต์ หลังจากส่งออกโน้ตแต่ละรายการด้วยคำสั่ง tone (ความถี่, ระยะเวลา) แล้ว คุณต้องแทรกการหน่วงเวลาด้วยคำสั่ง Delay() โดยมีระยะเวลาไม่น้อยกว่าระยะเวลา พารามิเตอร์ 6 - การเล่นตามลำดับของทั้งสอง แต่หยุดชั่วคราว

ทีวี.โทน(294,200); ทีวี.ดีเลย์(400); ทีวี.โทน(740,200);

ห่วงเกมหลัก

วงจรหลักของโปรแกรมประกอบด้วยการเรียกใช้ฟังก์ชันที่เราพิจารณา set_iam(), collision(), go_object(), set_new_object(), set_new_cursor() หลังจากช่วงระยะเวลาหนึ่งที่ตั้งไว้ในตัวแปร GAME.vk, GAME.vo_10, GAME .vo_11, GAME.vo_12

int game1() ( ในขณะที่(GAME1.balls>0 && GAME1.level<6) { long time2=millis(); if(time2-time11>GAME1.vk) (set_iam(); การชนกัน (); time11=time2; ) if(time2-time12>GAME1.vo_12) (go_object();time12=time2;) if(time2-time13>GAME1.vo_11) (set_new_object ();time13=time2;) ถ้า(time2-time14>GAME1.vo_10) (set_new_cursor();time14=time2;) TV.delay_frame(10); ) ถ้า(GAME1.balls<0) return 0; else if(GAME1.level>5) ส่งคืน 0; อย่างอื่นกลับ 1; -

เพิ่มเมนูสำหรับเลือกเกม

มาเพิ่มเมนูลงในร่างเพื่อแสดงเกมสามเกมที่คุณสามารถเพิ่มได้ด้วยตัวเอง

void loop() ( switch(menu(pmenu)) ( case 1:start_game(); while(game1()>0); break; default: break; ) ) //****** เมนูสำหรับเลือก int เกม เมนู (int poz) ( TV.clear_screen(); pmenu=max(poz,1); int pmenu1=pmenu; TV.println(60,30”เกม 1″); TV.println(60,50”เกม 2″); TV.println(60,70”เกม 3″); TV.draw_rect(50,5+20*pmenu,40,10,TV.delay(500); )==ต่ำ) ( ถ้า(อ่านแบบอะนาล็อก (A1)<100) pmenu=max(pmenu-1,1); else if(analogRead(A1)>900) เมนู = นาที (เมนู + 1,3); อื่น ; ถ้า(pmenu1!=pmenu) ( TV.delay(500); TV.draw_rect(50.5+20*pmenu1,40,10,BLACK,INVERT); TV.draw_rect(50.5+20*pmenu,40, 10,สีขาว, INVERT); pmenu1=pmenu; ) ) กลับเมนู; -

ข้อความจากผู้แปล:กาลครั้งหนึ่งเมื่อประเทศและต้นไม้มีขนาดใหญ่และจินตนาการของฉันไร้ขีด จำกัด ฉันมีความฝัน - ความสามารถในการแสดงภาพจากไมโครเครื่องคิดเลขที่ตั้งโปรแกรมได้ของฉัน Electronics MK-61 (ก็มีกราฟเส้นโค้งทุกประเภท , รูปภาพ) บนหน้าจอทีวี ช่วงเวลานั้นวุ่นวายในช่วงปลายยุคโซเวียตและไม่เพียงเท่านั้น เกมคอนโซลและไมโครคอมพิวเตอร์ส่วนตัว (“Pravets 8D” หรือ “Specialist” หรือ “Siknkler”) แต่ VCR ก็เป็นสิ่งแปลกใหม่เช่นกัน โดยทั่วไปผู้คนต้องการปรากฏการณ์และผู้ที่จำสิ่งพิมพ์ด้านการศึกษาและความบันเทิงสำหรับเครื่องคิดเลขแบบตั้งโปรแกรมได้ภายใต้ชื่อทั่วไป "เส้นทางสู่โลก" (นิตยสาร "เทคโนโลยี - เยาวชน") จะเข้าใจฉัน

กล่าวโดยสรุปในรูปแบบของนวนิยายวิทยาศาสตร์ที่มีโครงเรื่องที่ดีการเดินทางของคนรู้จักธรรมดา ๆ สองคน - นักบินอวกาศมืออาชีพและนักไซเบอร์เนติกส์คนสำคัญจากดวงจันทร์สู่โลก - ได้รับการอธิบาย สิ่งที่ทำให้โครงเรื่องทั้งหมดมีความได้เปรียบเป็นพิเศษคือความจริงที่ว่าพวกเขาเดินทางบนสิ่งที่เรียกว่า “ลูโนเล็ต” คือยานอวกาศขนาดเล็กที่มีเครื่องยนต์เคมี ออกแบบมาเพื่อการเคลื่อนที่ในสภาวะที่มองเห็นได้โดยตรงเหนือดวงจันทร์และเทห์ฟากฟ้าอื่นๆ คล้ายกับลูกบิลเลียดด้วยความโล่งใจง่ายๆ แต่ละประเด็นของวัฏจักรมีคำอธิบายทางคณิตศาสตร์ที่เรียบง่าย เป็นจริง แต่มีรากฐานที่ดีของการซ้อมรบแต่ละครั้ง ทั้งในสภาวะแรงโน้มถ่วงที่รุนแรง (ค่อนข้าง) ของเทห์ฟากฟ้าใกล้เคียง และเมื่อกระสุนปืนบนท้องฟ้าได้รับอิทธิพลจากวีรบุรุษแห่งแรงโน้มถ่วงของ โลกและดวงจันทร์พร้อมทั้งโปรแกรมคำนวณการบินขั้นต่อไป โดยทั่วไปการดูตัวเลขบนหน้าจอเครื่องคิดเลขยังไม่เพียงพอ แต่ฉันต้องการเส้นโค้งที่สวยงามบนหน้าจอ (เช่นใน MCC)

ในทางกลับกันอย่าลืมว่าแม้แต่ไมโครคอนโทรลเลอร์ดั้งเดิมของตระกูล Arduino ก็มีลำดับความสำคัญที่เหนือกว่าในด้านประสิทธิภาพไม่เพียง แต่กับไมโครโปรเซสเซอร์ของเรือธงในขณะนั้น - MK-52 และ MK-61 เท่านั้น แต่ยังรวมไปถึงความสามารถในการคำนวณของบางตัวด้วย คอนโซลเกม 8 บิตในภายหลัง (Atary 2600 และ Rambos อื่น ๆ ที่เหมาะสม)

โดยทั่วไปแล้ว การแนะนำจะยาวสักหน่อย ดังนั้นเรามาดูหัวข้อของบทเรียนวันนี้กันดีกว่า - ส่งออกภาพวิดีโอจาก Arduino ไปยังหน้าจอทีวี

น่าเสียดายที่คุณสมบัติการออกแบบของ Arduino ช่วยให้คุณสามารถส่งออกเฉพาะภาพขาวดำ (ขาวดำ) เท่านั้น แม้ว่าจะมีประโยชน์ในบางโครงการ และ CSV จะทำให้ noobs มีความสุขอย่างแน่นอน...

ขั้นตอนที่หนึ่ง ชิ้นส่วนและซอฟต์แวร์

คุณจะต้องการ:

ชิ้นส่วนและหน่วย:

  1. ไมโครคอนโทรลเลอร์ Arduino
  2. ทีวี (คุณไม่สามารถไปไหนได้หากไม่มีมัน)
  3. บอร์ดพัฒนาหรือโล่สำหรับ Arduino
  4. ตัวต้านทาน 2 ตัวที่มีค่าเล็กน้อย 470 โอห์มและ 1 Kom
  5. อะแดปเตอร์ติดตั้งแบบสองพินแบบตัวผู้ถึงตัวผู้ 2 ตัว
  6. ป้องกัน เคเบิลทีวีโดยมีทิวลิปอยู่ตรงปลาย

ซอฟต์แวร์:

  1. สภาพแวดล้อมการพัฒนา/เฟิร์มแวร์ Arduino ลิงค์อย่างเป็นทางการ

ขั้นตอนที่สอง การประกอบ

ในนามของผู้เขียนฉันต้องขออภัยสำหรับคุณภาพของภาพอะแดปเตอร์ทีวีที่เสร็จแล้วคุณภาพต่ำอย่างน่าขยะแขยง สิ่งนี้อธิบายได้จากข้อเท็จจริงที่ว่าเมื่อเขียนคำแนะนำคุณต้องเขียนคำแนะนำก่อนแล้วจึงเริ่มประกอบด้วยการบันทึกภาพถ่ายอย่างระมัดระวังในทุกขั้นตอน ในกรณีของเราทุกอย่างกลับกลายเป็นตรงกันข้ามดังนั้นจึงเป็นไปไม่ได้เลยที่จะเข้าใจสิ่งใดจากภาพที่ขุ่นมัวของอะแดปเตอร์ที่เสร็จแล้ว

จะดีกว่ามากว่าจะบัดกรีอะไรที่ไหนและอย่างไรอธิบาย แผนภาพวงจรยิ่งไปกว่านั้นประกอบด้วยเพียงบางส่วนเท่านั้น


พินเอาท์:

ซิงค์ - พินดิจิทัล 9 ของไมโครคอนโทรลเลอร์

วิดีโอ - เอาต์พุตดิจิตอล 8 ของไมโครคอนโทรลเลอร์

GND - พิน GND ของไมโครคอนโทรลเลอร์

ขั้นตอนที่สาม การเขียนโปรแกรม

ส่วนที่สนุกที่สุดคือการเขียนโปรแกรม

โดยพื้นฐานแล้วมันออกมาแล้ว เวอร์ชันใหม่อย่างไรก็ตาม ไลบรารีทีวีนั้นมีปัญหาและไม่เสถียรมากกว่า R5.91 ที่ผู้เขียนใช้ ดังนั้นจึงควรดาวน์โหลดไลบรารีจากลิงก์ด้านบน

โปรแกรม Tex สำหรับคนขี้เกียจที่ขี้เกียจเกินกว่าจะพิมพ์โค้ดซ้ำจากสำเนาหน้าจอ:

#รวม ออกทีวี;

ถ่าน x, y ที่ไม่ได้ลงนาม; การตั้งค่าเป็นโมฆะ () ( TV.start_render(_NTSC); ) โมฆะวนซ้ำ () ( TV.clear_screen (); TV.print_str (10, 10, "TVout FTW !!!"); TV.delay (60); )โดยถือว่ามีหลักการดำเนินงานขั้นพื้นฐานและ

  • start(mode) เริ่มแสดงข้อมูลบนหน้าจอ ความละเอียดมาตรฐาน - 128x96
  • start(mode,x,y) เริ่มแสดงข้อมูลบนหน้าจอ ความละเอียดถูกกำหนดโดยผู้ใช้โดยใช้อาร์กิวเมนต์ x,y
  • end() ล้างบัฟเฟอร์วิดีโอ
  • force_vscale(sfactor) บังคับจำนวนครั้งที่จะแสดงแต่ละบรรทัด
  • force_outstart(time) บังคับเวลาในการเริ่มเอาท์พุตบนบรรทัดที่ใช้งานอยู่
  • force_linestart(line) บังคับเส้นเพื่อเริ่มเอาท์พุต
  • set_vbi_hook(func) ตั้งค่าฟังก์ชันให้เรียกใช้หนึ่งครั้งต่อช่วงการเว้นแนวตั้ง
  • set_hbi_hook(func) ตั้งค่าฟังก์ชันให้เรียกใช้หนึ่งครั้งต่อช่วงการเว้นแนวนอน
  • hres() คำสั่งส่งกลับค่าความละเอียดแนวนอน
  • vsres() คำสั่งส่งคืนค่าความละเอียดแนวตั้ง
  • char_line() คำสั่งส่งคืนจำนวนอักขระที่จะพอดีกับบรรทัด
  • set_pixel(x,y,color) กำหนดสีพิกเซลตามพิกัดที่ระบุ
  • get_pixel(x,y) ตั้งค่าพิกเซลด้วยพิกัดที่กำหนดเป็นจุดอ้างอิง
  • fill(color) เติมหน้าจอด้วยสีที่ระบุ
  • clear_screen() ล้างหน้าจอ
  • invert() กลับภาพบนหน้าจอ
  • shift(ระยะทาง,ทิศทาง) เลื่อนหน้าจอตามระยะทางที่ระบุใน 6 ทิศทาง
  • Draw_line(x0,y0,x1,y1,color) สร้างเส้นจากพิกัด (x0,y0) ไปยังพิกัด (x1,y1)
  • Draw_row(row,x0,x1,color) เติมแถวด้วยพิกัดตั้งแต่ x0 ถึง x1 ด้วยสีที่กำหนด
  • Draw_column(column,y0,y1,color) เติมคอลัมน์ด้วยพิกัด y0 ถึง y1 ด้วยสีที่ระบุ
  • Draw_rect(x,y,w,h,color,fillcolor) วาดรูปสี่เหลี่ยมผืนผ้าที่มีจุดกำเนิดที่พิกัด (x,y) พร้อมขนาด (h,w) และเติมด้วยสีที่ระบุ
  • Draw_rect(x,y,w,h,color) วาดรูปสี่เหลี่ยมผืนผ้าที่มีจุดกำเนิดที่พิกัด (x,y) และขนาด (h,w)
  • Draw_circle(x,y,radius,color,fillcolor) วาดวงกลมที่มีศูนย์กลางที่ (x,y) พิกัดพร้อมรัศมี (RADIUS) แล้วเติมด้วยสีที่กำหนด
  • Draw_circle(x,y,radius,color) วาดวงกลมที่มีศูนย์กลางอยู่ที่พิกัด (x,y) พร้อมด้วยรัศมี (RADIUS)
  • bitmap(x,y,bmp,i,width,height) แสดงรูปภาพที่ระบุในพิกัด
  • print_char(x,y,c) พิมพ์อักขระที่พิกัด (x,y)
  • set_cursor(x,y) กำหนดตำแหน่งที่จะแสดงอักขระถัดไป
  • select_font(font) ตั้งค่าแบบอักษรสำหรับเอาต์พุตข้อความ
  • พิมพ์() พิมพ์ข้อความ
  • println() พิมพ์บรรทัดเดียว
  • printPGM() พิมพ์บรรทัดข้อความจากหน่วยความจำโปรแกรม
  • tone(ความถี่) เสียงที่มีความถี่ที่ระบุ
  • tone(ความถี่,ระยะเวลา) สัญญาณเสียงของความถี่และระยะเวลาที่กำหนด
  • noTone() หยุดเอาท์พุตโทนเสียง

ขั้นตอนที่สี่ เสร็จสิ้น

ในตอนกลางวันและในความฝัน ฉันมีความคิดที่จะสร้างกล่องรับสัญญาณควบคุมของตัวเอง จริงๆ แล้ว ตอนนั้นเองที่โลกแห่งวิศวกรรมวิทยุที่ร่ำรวยและมั่งคั่งเปิดกว้างให้กับฉัน เนื่องจากฉันไม่เคยจัดการกับการพัฒนาอุปกรณ์อิเล็กทรอนิกส์อย่างจริงจังมาก่อน ทางเลือกของฉันจึงตกเป็นตัวเลือกที่ง่ายกว่า - อาร์ดูโน่และรุ่นที่พบบ่อยที่สุดคือ อูโน่.

แผนการทำงาน

1. จัดการกับห้องสมุด
2. ประสานบอร์ดเอาต์พุตวิดีโอ
3. เขียนโค้ด
4. ตัดส่วนลำตัวออก

ส่วนประกอบภายนอกขั้นสุดท้ายไม่ได้มีความสำคัญเป็นพิเศษในกรณีของโครงการดังกล่าว

ขั้นตอนที่ 1 เรามาดูกันว่าอะไรคืออะไร

หลังจากท่องกูเกิ้ลอย่างสิ้นหวังเป็นเวลาหลายสิบนาที ฉันก็สรุปได้ว่าฉันไม่สามารถสร้างคอนโซลแบบ Dandy ได้ ฉันจะทำอะไรได้บ้าง ในเมื่อฉันรับมันมาเองแล้ว ฉันจะดูมันจนจบ

บนเว็บไซต์สำหรับโครงการ Arduino และอุปกรณ์อิเล็กทรอนิกส์ทางวิทยุโดยทั่วไป (ไม่ใช่โฆษณา) ฉันพบบทความเกี่ยวกับแนวคิดที่คล้ายกัน มีมติให้ใช้ห้องสมุด ออกทีวีเนื่องจากกล่องรับสัญญาณเป็นทีวี การติดตั้งและการทำงานต้องใช้เวลาเล็กน้อย

ฟังก์ชั่นห้องสมุดที่จำเป็น

ฟังก์ชั่นการตั้งค่าโหมด

การทำงาน เริ่ม()เริ่มต้นเอาต์พุตวิดีโอ (ความละเอียดหน้าจอเริ่มต้น 128x96)
ไวยากรณ์:
TVOut.begin(โหมด);
TVOut.begin (โหมด, x, y);

พารามิเตอร์:
โหมด – มาตรฐานสัญญาณวิดีโอ:
_PAL – โหมด PAL;
_NTSC – โหมด NTSC
ค่าส่งคืน:
0 – ในกรณีที่การเชื่อมต่อสำเร็จ 4 – ในกรณีที่เกิดความล้มเหลว (หน่วยความจำไม่เพียงพอสำหรับบัฟเฟอร์เอาต์พุต)

ฟังก์ชั่นการหน่วงเวลา

การทำงาน ล่าช้า()หน่วงเวลาภาพที่ส่งออก
ไวยากรณ์:

TVOut.ล่าช้า(มิลลิวินาที);
พารามิเตอร์:

ms – ความล่าช้าเป็น ms ด้วยความแม่นยำ: 20 ms สำหรับ PAL และ 16 ms สำหรับ NTSC

ฟังก์ชั่น Delay_frame() ทำหน้าที่หน่วงเวลาการแสดงรูปภาพ
ไวยากรณ์:

TVOut.delay_frame (เฟรม);
พารามิเตอร์:

เฟรม – จำนวนเฟรมสำหรับความล่าช้า...
คุณสมบัตินี้มีประโยชน์ในการลดหรือกำจัดการกะพริบของหน้าจอที่เกิดจากการรีเฟรชหน้าจอ

ฟังก์ชั่นการรับพารามิเตอร์

การทำงาน ชั่วโมง()ส่งกลับความละเอียดหน้าจอแนวนอน
ไวยากรณ์:

TVOut.hrs();
พารามิเตอร์:

เลขที่
ค่าส่งคืน:

ถ่านที่ไม่ได้ลงนาม - ความละเอียดหน้าจอแนวนอน

ฟังก์ชัน vsres() ส่งกลับความละเอียดแนวตั้งของหน้าจอ
ไวยากรณ์:

TVOut.vres();
พารามิเตอร์:

เลขที่
ค่าส่งคืน:

ถ่านที่ไม่ได้ลงนาม – ความละเอียดหน้าจอแนวตั้ง

การทำงาน char_line()ส่งคืนจำนวนอักขระสูงสุดที่เป็นไปได้ในหนึ่งบรรทัดเมื่อส่งออก ข้อมูลข้อความ.
ไวยากรณ์:

ทีวีเอาท์. char_line();
พารามิเตอร์:

เลขที่
ค่าส่งคืน:

ถ่านที่ไม่ได้ลงนาม – จำนวนอักขระ

ฟังก์ชั่นกราฟิกพื้นฐาน

การทำงาน set_pixel()ตั้งค่าสีของพิกเซลของหน้าจอ ณ จุดที่มีพิกัดที่กำหนด
ไวยากรณ์:

TVOut.set_pixel(x,y,สี);
พารามิเตอร์:

x,y – พิกัดพิกเซล
สี – สีพิกเซล:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี
การทำงาน get_pixel()รับสีของพิกเซลหน้าจอจากจุดที่มีพิกัดที่กำหนด
ไวยากรณ์:

TVOut.get_pixel(x,y);
พารามิเตอร์:

x,y – พิกัดพิกเซล
ค่าส่งคืน:

สี – สีพิกเซล:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี
ฟังก์ชัน fill() จะทำให้หน้าจอมีสีตามที่กำหนด
ไวยากรณ์:

TVOut.fill(สี);
พารามิเตอร์:

สี – สีเติม:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี
การทำงาน clear_screen()ล้างหน้าจอโดยเติมสีตามที่กำหนด
ไวยากรณ์:

TVOut.clear_screen(สี);
พารามิเตอร์:

สี – สีเติม:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี

การทำงาน กลับด้าน()กลับเนื้อหาบนหน้าจอ
ไวยากรณ์:

TVOut.กลับด้าน();
พารามิเตอร์:

เลขที่
ฟังก์ชั่น shift_direction() เลื่อนเนื้อหาของหน้าจอ
ไวยากรณ์:

TVOut.shift_direction(ระยะทาง, ทิศทาง);
พารามิเตอร์:

ระยะทาง – ระยะทางเพื่อเลื่อนเนื้อหาบนหน้าจอ
ทิศทาง – ทิศทางการเปลี่ยน:
ขึ้น=0 – ขึ้น;
ลง=1 – ลง;
ซ้าย=2 – ซ้าย;
RIGHT=3 – ไปทางขวา

การทำงาน Draw_line()เชื่อมต่อสองจุดบนหน้าจอด้วยเส้น
ไวยากรณ์:

TVOut.draw_line(x0,y0,x1,y1,สี);
พารามิเตอร์:

x0,y0 – พิกัดของจุดแรก
x1,y1 – พิกัดของจุดที่สอง
สี – สีเติม:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี
การทำงาน Draw_row()เติมเส้นด้วยสีที่ระบุระหว่างจุดสองจุดบนเส้น
ไวยากรณ์:

TVOut.draw_row(แถว,x0,x1,สี);
พารามิเตอร์:

แถว – พิกัดแนวตั้งของแถว
x1,x2 – พิกัดแนวนอนของจุดเส้น;
สี – สีเติม:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี
ฟังก์ชัน Draw_column() เติมแถวด้วยสีที่ระบุระหว่างจุดสองจุดในคอลัมน์
ไวยากรณ์:

TVOut.draw_column(คอลัมน์,y0,y1,สี);
พารามิเตอร์:

คอลัมน์ – พิกัดแนวนอนของคอลัมน์
y1,y2 – พิกัดแนวตั้งของจุดคอลัมน์
สี – สีเติม:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี
การทำงาน Draw_rect()วาดรูปสี่เหลี่ยมบนหน้าจอ
ไวยากรณ์:

TVOut.draw_rect(x,y,w,h,สี);
TVOut.draw_rect(x,y,w,h,สี,สีเติม);

พารามิเตอร์:

x,y – พิกัดของจุดซ้ายบน;
W,H คือความกว้างและความสูงของรูปสี่เหลี่ยมผืนผ้าที่วาด
สี – สีของเส้นขอบสี่เหลี่ยม:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี
fillcolor – สีเติมสี่เหลี่ยม:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี
การทำงาน Draw_circle()วาดวงกลมบนหน้าจอ
ไวยากรณ์:

TVOut.draw_circle(x,y,r,สี);
TVOut.draw_circle(x,y,r,สี,สีเติม);

พารามิเตอร์:

x,y – พิกัดของจุดศูนย์กลางวงกลม
r คือรัศมีของวงกลม
สี – สีของเส้นขอบวงกลม:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี
fillcolor – สีเติมวงกลม:
0 – สีดำ;
1 – สีขาว;
2 – สลับสี
การทำงาน บิตแมป()แสดงภาพแรสเตอร์บนหน้าจอ
ไวยากรณ์:

TVOut.bitmap(x,y,bmp,w,h);
พารามิเตอร์:

x,y – พิกัดมุมซ้ายบนของจุดเอาท์พุต
bmp – ตัวชี้ไปยังอาร์เรย์หน่วยความจำที่เก็บรูปภาพไว้
w,h – ความกว้าง, ความสูงของรูปภาพที่แสดง;
ด้านล่างนี้เราจะดูกระบวนการสร้างโค้ดสำหรับรูปภาพแรสเตอร์เอาต์พุต

ฟังก์ชันเอาต์พุตข้อมูลข้อความ

หากต้องการใช้ฟังก์ชันเอาต์พุตข้อมูลข้อความ คุณต้องเชื่อมต่อไฟล์ที่รวมอยู่ในไลบรารีหรือแบบอักษรที่กำหนดเอง หากต้องการเชื่อมต่อชุดแบบอักษรที่กำหนดเอง คุณต้องรวมไฟล์ส่วนหัวไว้ในร่าง:
#รวม
ไลบรารีประกอบด้วยชุดแบบอักษรต่อไปนี้:

ฟอนต์4x6;
ฟอนต์6x8;
ฟอนต์8x8;
แบบอักษร8x8ext.
การทำงาน เลือก_แบบอักษร()เลือกแบบอักษรสำหรับแสดงข้อมูลข้อความ
ไวยากรณ์:

TVOut.select_font(แบบอักษร);
พารามิเตอร์:

แบบอักษร – แบบอักษรที่รวมอยู่ในร่าง

ฟังก์ชัน print_char() พิมพ์อักขระลงบนหน้าจอ
ไวยากรณ์:

TVOut.print_char(x,y,ถ่าน);
พารามิเตอร์:

x,y – ตำแหน่งบนหน้าจอเพื่อแสดงสัญลักษณ์
ถ่าน – อักขระจากแบบอักษรปัจจุบัน

การทำงาน set_cursor()กำหนดตำแหน่งเคอร์เซอร์สำหรับแสดงข้อมูลข้อความบนหน้าจอ
ไวยากรณ์:

TVOut.set_cursor(x,y);
พารามิเตอร์:

x,y – พิกัดของเคอร์เซอร์
การทำงาน พิมพ์()แสดงสตริง อักขระ หรือตัวเลข
ไวยากรณ์:

TVOut.print(x,y,สตริง);
TVOut.print(x,y,ถ่าน,ฐาน);
TVOut.print(x,y,int,ฐาน)

พารามิเตอร์:

x,y – พิกัดเคอร์เซอร์
ฐาน – รูปแบบเอาต์พุต:
ไบต์ = 0;
ธันวาคม = 10 (ค่าเริ่มต้น);
ฐานสิบหก = 16.

การทำงาน พิมพ์ ()แสดงสตริง อักขระ หรือตัวเลขตามด้วยอักขระขึ้นบรรทัดใหม่:
ไวยากรณ์:

TVOut.println(x,y,สตริง);
TVOut.println(x,y,ถ่าน,ฐาน);
TVOut.println(x,y,int,ฐาน)

พารามิเตอร์:

x,y – พิกัดเคอร์เซอร์
ฐาน – รูปแบบเอาต์พุต:
ไบต์ = 0;
ธันวาคม = 10 (ค่าเริ่มต้น);
ฐานสิบหก = 16.

คุณสมบัติเอาต์พุตเสียง

ฟังก์ชั่นเอาต์พุตเสียงช่วยให้คุณสามารถส่งสัญญาณความถี่เฉพาะไปยังทีวีของคุณผ่านทางเอาต์พุตเสียงได้
การทำงาน โทน()สร้างสัญญาณเสียงความถี่หนึ่ง
ไวยากรณ์:

TVOut.tone(ความถี่,ระยะเวลา);
TVOut.tone(ความถี่)

พารามิเตอร์:

ความถี่ - ความถี่ของสัญญาณเสียง
ระยะเวลา – ระยะเวลาสัญญาณ
การทำงาน ไม่มีโทน()หยุดเอาต์พุตเสียง
ไวยากรณ์:

TVOut.noTone()

ขั้นตอนที่ 2 ประสานเอาต์พุตวิดีโอ

ก่อนอื่น เราต้องบัดกรีบอร์ดบางตัวเพื่อส่งสัญญาณวิดีโอผ่านเอาต์พุต AV แบบคอมโพสิต (RCA) เราประสานตามรูปแบบต่อไปนี้:


ลองวางตัวต้านทานสองตัวที่มีค่าเล็กน้อย 470 โอห์มและ 1,000 โอห์มขนานกันแล้วบัดกรี "บวก" จากสายทิวลิปเข้ากับพวกมัน ต่อไปเราจะนำลวดจากตัวต้านทาน 470 โอห์มไปยังพินที่เจ็ดของ Arduino เพราะ เขารับผิดชอบเอาต์พุตวิดีโอ ( วิดีโอ) และจากตัวต้านทานใน 1k โอห์มเราจะนำลวดไปที่พินที่เก้าเนื่องจากมีหน้าที่ในการซิงโครไนซ์ ( ซิงค์- และ "ลบ" จากสายทิวลิปถึง "กราวด์" บน Arduino รายละเอียดเพิ่มเติม ( ภาษาอังกฤษ)

ขั้นตอนที่ 3 เขียนโค้ด (เกม)

ฉันจะไม่อธิบายว่าจะเชื่อมต่ออะไรและอย่างไรเนื่องจากข้อมูลที่จำเป็นสามารถพบได้บนอินเทอร์เน็ตเช่นเคย ฉันกำลังอธิบายบางสิ่งที่หายากมากหรือไม่มีเลย

เริ่มต้นด้วย หน้าจอต้อนรับเราจะอยู่ที่ไหนถ้าไม่มีเขา? แต่มีคำถามสำคัญเกิดขึ้น: ปาฏิหาริย์นี้เรียกว่าอะไร? ฉันคิดเกี่ยวกับมันและมากับ - ชิโมะ- ฟังดูดีแม้จะเป็นภาษาจีนที่ก้าวหน้าทางเทคโนโลยี แต่ก็ไม่สำคัญ

มาเริ่มกันเลย ลากเส้นผ่านกึ่งกลางหน้าจอโดยใช้ ทีวี.draw_line(60,0,60,96,1);- ลูกบอลปรากฏขึ้นตรงกลางหน้าจอพอดี มาเขียนฟังก์ชันการเคลื่อนที่ของมันกันดีกว่า โมฆะ ballmove (int vel, int angle)- ติดตั้งโดยใช้ TV.set_pixel(x,y,1);ฉันตั้งชื่อตัวแปรแบบนั้น

ต่อไป ก่อนที่จะจัดการลูกบอล เราจะระบุการอัปเดตหน้าจอ หรือเพื่อให้ลูกบอลไม่ "สืบทอด" บนหน้าจอ ดังนั้นเมื่อย้ายไปยังตำแหน่งถัดไป คุณจะต้องทาสีทับอันก่อนหน้าด้วยสีดำ เมื่อต้องการทำเช่นนี้ เราต้องเขียนก่อนสิ่งอื่นใด TV.set_pixel(x,y,0);- หลังจากการเปลี่ยนแปลงตัวแปรพิกัดทั้งหมดแล้ว คุณต้องระบุการตั้งค่าตำแหน่งและการหน่วงเวลาสั้นๆ - ทีวี.ดีเลย์(50);- มันควรมีลักษณะดังนี้:

โมฆะ ballmove(int vel, int angle) ( TV.set_pixel(x,y,0); // การจัดการกับพิกัด TV.set_pixel(x,y,1); )

ตอนนี้เกี่ยวกับพิกัดเปลี่ยนแปลงไปเอง มีทั้งหมดแปดทิศ (1-8) แปรผันได้ มุมอินท์- จากนั้นเราก็ลบหรือบวกส่วนใดๆ ของตัวแปรออกไป ขึ้นอยู่กับการหมุน ความเร็วภายใน- ฉันทำสิ่งนี้:

ถ้า(มุม == 1) ( y -= vel; ) ถ้า(มุม == 3) ( x += vel; ) ถ้า(มุม == 5) ( y += vel; ) ถ้า(มุม == 7) ( x -= vel; ) if(มุม == 2) ( x += รอบ(vel/2); y -= รอบ(vel/2); ) ถ้า(มุม == 4) ( x += รอบ(vel/ 2); y += รอบ (vel/2); ) ถ้า (มุม == 6) ( x -= รอบ (vel/2); y += รอบ (vel/2); ) ถ้า (มุม == 8) ( x -= รอบ(vel/2); y -= รอบ (vel/2); )

ตอนนี้การเคลื่อนไหวของแร็กเกต นี่คือคำชี้แจงที่สำคัญ - ฉันใช้เฉพาะพิกัดตามเท่านั้น เนื่องจากตำแหน่งของไม้เทนนิสตาม xอย่าเปลี่ยน เราเขียนฟังก์ชันต่อไปนี้ โมฆะแร็กเก็ตย้าย ()- ต่อไปเราจะวาดแร็กเก็ตตัวแปร อินท์ yb1, อินท์ yb2, TV.draw_line(10, yb1+8, 10, yb1-8, 1);และ TV.draw_line(110, yb2+8, 110, yb2-8, 1);- การอัปเดตหน้าจอคือ "ไร้ร่องรอย" คล้ายกับกรณีของลูกบอล

แร็กเก็ตถูกควบคุมโดยใช้ปุ่ม การเชื่อมต่อปุ่มและพิน 2 และ 3 - แร็กเก็ตแรก 4 และ 5 - แร็กเก็ตที่สอง เราตรวจสอบการกดปุ่มและเปลี่ยนพิกัด

นี่คือฟังก์ชัน:

โมฆะแร็กเก็ตย้าย() ( TV.draw_line(10, yb1+8, 10, yb1-8, 0); TV.draw_line(110, yb2+8, 110, yb2-8, 0); if((yb1 - 8) > 1) ( if(digitalRead(2) == สูง) ( yb1 -= 2;) ) if((yb1 + 8)< 95) { if(digitalRead(3) == HIGH) {yb1 += 2;} } if((yb2 - 8) >1) ( if(digitalRead(4) == สูง) (yb2 -= 2; ) ) if((yb2 + 8)< 95) { if(digitalRead(5) == HIGH) {yb2 += 2;} } TV.draw_line(10, yb1+8, 10, yb1-8, 1); TV.draw_line(110, yb2+8, 110, yb2-8, 1); }

ตอนนี้เรากลับมาที่ ลูกบอล- ทีนี้ลองเขียนการชนและแรงผลักจากกำแพงและแร็กเก็ตกัน การทำงาน - โมฆะ ballcol()- ในการทำเช่นนี้ เราเพียงตรวจสอบตำแหน่งของมันโดยสัมพันธ์กับวัตถุ จากนั้นจึงตรวจสอบมุมของมัน จากนั้นเราเปลี่ยนมุมนี้เป็นมุมอื่น มุมนั้นเดาง่าย

มุมสะท้อนเท่ากับมุมตกกระทบ

มีข้อยกเว้นทางกายภาพบางประการสำหรับพื้นที่บางส่วนของไม้เทนนิส

โมฆะ ballcol() ( if(x == 1 || x == 119 || (x == 10 && y< (yb1 + 3) && y > < (yb2 + 3) && y > < (yb1 - 3) && y >(yb1 - 8)) ( a = 2; ) ถ้า(x == 10 && y > (yb1 + 3) && y< (yb1 + 8)) { a = 4; } if(x == 110 && y < (yb2 - 3) && y >(yb2 - 8)) ( a = 8; ) ถ้า(x == 110 && y > (yb2 + 3) && y< (yb2 + 8)) { a = 6; } if(y == 95 || y == 1) { if(a==1){a=5;}else if(a==2){a=4;}else if(a==3){a=7;}else if(a==4){a=2;}else if(a==5){a=1;}else if(a==6){a=8;}else if(a==7){a=3;}else if(a==8){a=6;} } }

ส่วนที่ยากที่สุดจบลงแล้ว หายใจได้สำเร็จ

ในขณะนี้ สิ่งที่เราต้องทำคือสร้างระบบการให้คะแนน ตัวจับเวลา และการรีสตาร์ท

เริ่มจากตัวจับเวลากันก่อน มีตัวแปรวินาที ลอย ts(มันถูกเก็บไว้อย่างแน่นอนตลอดเวลา) ตัวแปร int TM(จำนวนนาทีที่เราได้รับจาก ทีเอส- ตั้งค่า TMการดำเนินการ tm = ts/60;- และแสดงค่าบนหน้าจอ ทีวี.พิมพ์(81,1,tm); TV.print(97,1,"."); TV.print(100,1,int(ts-(tm*60)));.

มาต่อกันเลย เราเรียกฟังก์ชันรีสตาร์ท โมฆะรีสตาร์ท ()- ที่นี่เราจะคืนค่าเดิมของตัวแปร

การรีสตาร์ทเป็นโมฆะ() ( TV.clear_screen(); x = 60; y = 48; yb1 = 48; yb2 = 48; a = 8; ts = 900.0; c1 = 0; c2 = 0; )

ฉากสุดท้าย ระบบการให้คะแนน มันง่ายเกินไป เปิด Google แล้วพิมพ์คำว่า Rules of table Tennis เรากำลังมองหาสิ่งที่จะได้รับคะแนน เราพบส่วนที่เป็นบทลงโทษแล้วเราก็พบสิ่งต่อไปนี้ได้สำเร็จ: “แต้มนั้นถือว่าชนะหากคู่ต่อสู้ไม่มีเวลาสะท้อนลูกบอลที่ส่งไปให้เขาอย่างถูกต้องหลังจากการเด้งครั้งแรก” คำถามเกิดขึ้นจะนับการตีอย่างไรและอื่นๆ..แต่ไม่ต้องนับการตีด้วยซ้ำเพราะปิงปองของเรามีกราฟิกสองมิติ

เราหาทางออกจากสถานการณ์อย่างใจเย็นและเช่นเคยเพียงตรวจสอบพิกัดที่สัมพันธ์กับผนังด้านข้าง หากเกิดการชนกัน เราจะให้แต้มแก่ผู้เล่นที่อยู่ฝั่งตรงข้ามของสนาม การทำงาน - โมฆะ ballcount()- เมื่อหมดเวลาเราจะเปรียบเทียบคะแนนของผู้เล่นคนแรก (ตัวแปร อินท์ c1) และผู้เล่นคนที่สอง (ตัวแปร อินท์ c2) เราจะประกาศผู้ชนะ ชะลอ และเรียกการรีสตาร์ท

โมฆะ ballcount() ( if(x == 1) ( c2++; ) if(x == 119) ( c1++; ) if(c1 >< c2 && ts == 0) { TV.println(10, 45, "Player 2 won!"); delay(10000); restart(); } else if(c1 == c2 && ts == 0) { TV.println(10, 45, "You are equal"); delay(10000); restart(); }

แค่นั้นแหละเพื่อน ๆ เราได้เขียนโค้ดเกมเรียบร้อยแล้ว มันค่อนข้างตลกและคุณสามารถเล่นได้


สำหรับคนขี้เกียจผมจะเขียนโค้ดทั้งหมดเลย

สคริปต์เต็ม

มีทั้งหมด 218 เส้น #รวม #รวม< 0) { ts = 0; } TV.draw_rect(81,1,38,10,0,0); TV.print(81,1,tm); TV.print(97,1,"."); TV.print(100,1,int(ts-(tm*60))); ballcol(); /*if(ts < 600) { s = 4; } if(ts < 300) { s = 6; }*/ ballmove(s, a); TV.delay(50); if(digitalRead(6) == HIGH) { paused = true; delay(1000); } } else { TV.println(40,4,"pause"); if(digitalRead(6) == HIGH) { paused = false; delay(1000); TV.clear_screen(); } } } void ballscount() { if(x == 1) { c2++; } if(x == 119) { c1++; } if(c1 >ออกทีวี; int x, y, a, c1, c2, yb1, yb2, tm, tsh, s; ลอยที; บูลีนหยุดชั่วคราว = false; การตั้งค่าเป็นโมฆะ () ( TV.begin (NTSC, 120, 96); TV.clear_screen (); TV.select_font (font6x8); TV.println (0, 50, "ยินดีต้อนรับสู่ Shimo"); TV.delay (5000) ; TV.clear_screen(); y = 48; yb2 = 8; (60,0,60,96,1); ; ; ; TV.print(26,1,c2);< c2 && ts == 0) { TV.println(10, 45, "Player 2 won!"); delay(10000); restart(); } else if(c1 == c2 && ts == 0) { TV.println(10, 45, "You are equal"); delay(10000); restart(); } } void ballcol() { if(x == 1 || x == 119 || (x == 10 && y < (yb1 + 3) && y >c2 && ts == 0) ( TV.println (10, 45, "ผู้เล่น 1 ชนะ!"); ล่าช้า (10,000); รีสตาร์ท (); ) อื่นถ้า (c1< (yb2 + 3) && y >(yb2 - 3))) ( if(a==1)(a=5;)else if(a==2)(a=8;)else if(a==3)(a=7;)else if(a==4)(a=6;)else if(a==5)(a=1;)else if(a==6)(a=4;)else if(a==7)( a=3;)else if(a==8)(a=2;) ) ถ้า(x == 10 && y< (yb1 - 3) && y >(yb1 - 8)) ( a = 2; ) ถ้า(x == 10 && y > (yb1 + 3) && y< (yb1 + 8)) { a = 4; } if(x == 110 && y < (yb2 - 3) && y >(yb2 - 8)) ( a = 8; ) ถ้า(x == 110 && y > (yb2 + 3) && y< (yb2 + 8)) { a = 6; } if(y == 95 || y == 1) { if(a==1){a=5;}else if(a==2){a=4;}else if(a==3){a=7;}else if(a==4){a=2;}else if(a==5){a=1;}else if(a==6){a=8;}else if(a==7){a=3;}else if(a==8){a=6;} } } void racketsmove() { TV.draw_line(10, yb1+8, 10, yb1-8, 0); TV.draw_line(110, yb2+8, 110, yb2-8, 0); if((yb1 - 8) >1) ( if(digitalRead(2) == สูง) ( yb1 -= 2; ) ) if((yb1 + 8)< 95) { if(digitalRead(3) == HIGH) { yb1 += 2; } } if((yb2 - 8) >1) ( if(digitalRead(4) == สูง) ( yb2 -= 2; ) ) if((yb2 + 8)< 95) { if(digitalRead(5) == HIGH) { yb2 += 2; } } TV.draw_line(10, yb1+8, 10, yb1-8, 1); TV.draw_line(110, yb2+8, 110, yb2-8, 1); } void ballmove(int vel, int angle) { TV.set_pixel(x,y,0); if(angle == 1) { y -= vel; } if(angle == 3) { x += vel; } if(angle == 5) { y += vel; } if(angle == 7) { x -= vel; } if(angle == 2) { x += round(vel/2); y -= round(vel/2); } if(angle == 4) { x += round(vel/2); y += round(vel/2); } if(angle == 6) { x -= round(vel/2); y += round(vel/2); } if(angle == 8) { x -= round(vel/2); y -= round(vel/2); } TV.set_pixel(x,y,1); } void restart() { TV.clear_screen(); x = 60; y = 48; yb1 = 48; yb2 = 48; a = 8; ts = 900.0; c1 = 0; c2 = 0; }

ขั้นตอนที่ 4 ตัดลำตัวออก

ฉันตัดสินใจตัดตัวเครื่องโดยใช้เครื่องตัดเลเซอร์ (หรือเครื่องกัดฉันไม่แน่ใจ) จากไม้อัด 4 มม. ฉันวาดมันใน InkScape เลอะเทอะเล็กน้อยแล้วแปลงเป็นรูปแบบเครื่องกัด


สำหรับเกมแพด ฉันตัดกระดานเล็กๆ ออกแล้วเจาะรูสำหรับปุ่มต่างๆ มันดูดี แต่น่าเสียดายที่ฉันทำรูปถ่ายหาย

บทสรุป

ในกระบวนการทำงาน คอนโซลเกมโทรทัศน์สำหรับเล่นเกมแบบธรรมดาได้ถูกสร้างขึ้นบน Arduino ด้วย เกมมาตรฐานปิงปองพร้อมเกมแพดสองอันซึ่งเราสามารถเล่นได้และติดขัดด้วยซ้ำ

สวัสดี Geek Times!
วันนี้ฉันจะบอกคุณอย่างหนึ่งที่ไม่ดีนัก เรื่องราวที่น่าสนใจเกี่ยวกับวิธีที่ฉันสร้างคอนโซลเกมง่ายๆ โดยใช้ Arduino และสร้างเกมง่ายๆ สำหรับมันในเอนจิ้นเกมที่ฉันชื่นชอบ - Unity

เกมส์

เป็นเวลาเกือบสี่ปีแล้วที่ฉันพัฒนาเกมโดยใช้โปรแกรมเกมยอดนิยม Unity (ชื่อเดิม Unity3D) ในช่วงเวลานี้ฉันสามารถสร้างได้หลายอย่าง เกมเล็กๆสำหรับ อุปกรณ์เคลื่อนที่รวมถึงโครงการที่มีผู้ใช้หลายคนขนาดใหญ่
พื้นที่นี้น่าสนใจสำหรับฉันมากและทำให้ฉันยินดีเป็นอย่างยิ่งที่ได้ทำงานในพื้นที่นี้

อุปกรณ์

แต่บางครั้งคุณก็อยากลองอะไรใหม่ๆ และวันหนึ่งฉันก็ตัดสินใจลองใช้ Arduino
ฉันสนใจมากในการสร้างอุปกรณ์ของตัวเองและวิธีตั้งโปรแกรมอุปกรณ์เหล่านั้น ทำไมต้องอาร์ดิโน? มีโพสต์มากมายบนอินเทอร์เน็ตและแม้แต่ในฮับเดียวกันและ Geek Times เกี่ยวกับสาเหตุที่คุณควรซื้อ Arduino แต่ฉันทราบว่าสำหรับฉันปัจจัยชี้ขาดในการเลือก Arduino คือใช้งานง่าย

จะรวมสิ่งนี้ได้อย่างไร?

วันหนึ่งบนอินเทอร์เน็ต ฉันพบโพสต์เกี่ยวกับวิธีที่ผู้ใช้คนหนึ่งประกอบเกมคอนโซลง่ายๆ ของตัวเองโดยใช้ Arduino ติดตั้งจอ LCD ขนาดเล็ก 84x48 พิกเซล และเขียนเกมง่ายๆ สองสามเกมลงไป: Pong และ Arkanoid .
การพัฒนานี้ทำให้ฉันสนใจมาก และฉันตัดสินใจสร้างคอนโซลเกมเวอร์ชันของตัวเองโดยใช้ไมโครคอนโทรลเลอร์ atmega328

คอนโซลนั้นเอง

ก่อนอื่นเลย ฉันออกแบบและสร้าง LUT แผงวงจรพิมพ์สำหรับคอนโซลแบบพกพา นี่เป็นข้อผิดพลาด ก่อนอื่นฉันต้องทดสอบโปรแกรมบนบอร์ดดีบั๊ก เช่น Arduino uno เนื่องจากฉันไม่ได้ให้ความสามารถในการอัปโหลดโปรแกรมไปยังคอนโทรลเลอร์ได้อย่างรวดเร็วและสะดวก ฉันยังทำผิดพลาดในวงจรด้วย สิ่งนี้สามารถแก้ไขได้ด้วยสายไฟ แต่ก็ยังน่าเสียดาย
หลังจากที่ฉันรู้ว่าฉันผิด ฉันก็เชื่อมต่อปุ่มต่างๆ ผ่านบอร์ดเข้ากับ Arduino uno และฉันก็เชื่อมต่อหน้าจอโดยตรง
นี่คือสิ่งที่เกิดขึ้น:



และตอนนี้ถึงเกม

ในการสร้างเกม ฉันตัดสินใจใช้เอ็นจิ้นเกม Unity ฉันไม่ได้เขียนคอมไพเลอร์จาก Mono C# ลงในโปรแกรมสำหรับ Arduino แต่ฉันตัดสินใจเขียนชุดสคริปต์ที่คุณสามารถสร้างเกมได้อย่างง่ายดาย
ฉันแบ่งสคริปต์ทั้งหมดออกเป็น 3 กลุ่ม - การกระทำ เงื่อนไข และตัวรวม
ฉันคิดว่าไม่จำเป็นต้องอธิบายวัตถุประสงค์ของการกระทำและเงื่อนไข แต่ฉันจะอธิบายว่าทำไมจำเป็นต้องใช้ตัวรวม ตัวรวมจะตรวจสอบว่าตรงตามเงื่อนไขหรือไม่ จากนั้นจึงดำเนินการ
จากสคริปต์หรือการมีอยู่และการรวมกันอัลกอริธึมจะสร้างโปรแกรมสำหรับ Arduino

เกมประเภทไหน?

ฉันตัดสินใจที่จะเริ่มต้นด้วยสิ่งที่เรียบง่าย เกมที่ง่ายที่สุดที่คุณรู้จักคืออะไร? ถูกต้อง-ปอง. แต่ฉันตัดสินใจที่จะไม่ทำปิงปองจริงๆ แต่เป็นปิงปองสำหรับอันเดียว - มีแร็กเกตหนึ่งลูกลูกบอลและกำแพงแทนที่จะเป็นแร็กเก็ตตัวที่สอง
ฉันประกอบมันจากตัวสร้างที่เป็นลายลักษณ์อักษร คอมไพล์และอัพโหลดไปยังคอนโทรลเลอร์ ได้ผล!

ตอนนี้เรามาวางทุกอย่างตามลำดับ

เมื่อเกมเริ่มต้นขึ้นและฉันเล่นเกมได้เพียงพอแล้ว ฉันตัดสินใจว่ามันคุ้มค่าที่จะปรับปรุงกระดานใหม่โดยให้มันไป วิวสวยใช้ส่วนประกอบ smd และลบสิ่งที่ไม่จำเป็นทั้งหมดออก ฉันแก้ไขวงจรใหม่และสร้างบอร์ด
นี่คือสิ่งที่เกิดขึ้น



แหล่งที่มา

ซอร์สโค้ดนั้นง่ายมาก
สิ่งที่ Unity ทำคือในโปรแกรมแก้ไข ผู้ใช้ประกอบเกมจากอ็อบเจ็กต์ UI แนบสคริปต์ของการดำเนินการ เงื่อนไข และตัวรวมเข้ากับสิ่งเหล่านั้น
สิ่งที่คอมไพลเลอร์ทำ (สคริปต์ parser.cs) ก็คือมันจะรันผ่านออบเจ็กต์ทั้งหมด ดูสคริปต์ และเพิ่มโค้ดบางส่วนลงในข้อความของไฟล์ build.ino ที่รับผิดชอบในการรันแอนะล็อกของสคริปต์เหล่านี้ในไมโครคอนโทรลเลอร์

ลิงก์ไปยังแหล่งที่มา - drive.google.com/open?id=0B5INc3_98cSJMEMxZmlWUTh1Ukk
การรวบรวมเกิดขึ้นเมื่อเกมเริ่ม และบันทึกไว้ในโฟลเดอร์ Assets/build/text/built.ino
ต้องอัปโหลดภาพร่างนี้ไปยังตัวควบคุม

สรุปแล้ว

อยากจะบอกว่ามันน่าสนใจมาก
ฉันได้รับโอกาสในการรวมสองกิจกรรมของฉันเข้าด้วยกัน ได้แก่ การพัฒนาเกมและการสร้างอุปกรณ์
ฉันหวังว่าคุณจะสนใจสิ่งนี้เช่นกัน และตอนนี้คุณก็จะสร้างอุปกรณ์เจ๋ง ๆ ของคุณเองเช่นกัน =)