GAME-ST7565 - Làm Game xe tăng với Arduino

07/08/2019
game-st7565-lam-game-xe-tang-voi-arduino

Hôm nay sẽ là Game xe tăng – TANK WAR – tựa Game quen thuộc nhưng đầy hấp hẫn. Điểm đặc biệt là bạn có chơi ở chế độ cân TEAM 1-25 cực FUN devil.

1

TANK WAR

Sử dụng 4 nút điều khiển hướng để di chuyển xe tăng của ta, nhấn OK để khai hỏa.

Thuộc tính: Mỗi xe tăng chỉ được bắn 1 phát một cho đến khi đạn bay đến hết Biên thì mới được phép khai hỏa lần 2. Tốc độ của đạn và xe tăng của ta nhanh hơn so với địch.

Hỗ trợ xây xựng MAP theo sở thích, có thể tùy chỉnh số lượng địch là các ưu điểm của phiên bản này.

2

Chuẩn bị phần cứng.

Tải về thư viện đồ họa

Bạn hãy tải về thư viện tại bài viết

ST7565 | Hướng dẫn sử dụng glcd ST7565 homephone và chia sẻ thư viện

Chuẩn bị phần cứng

  • Arduino chip atm328 trở lên, mình sử dụng arduino uno r3
  • Lcd st7565 128x64 homephone spi
  • Nút bấm: 6 nút

Nối mạch

Bạn hãy tham khảo cách nối mạch và nút bấm tại bài viết giới thiệu lcd nhé:

3

CODE

Bạn có thể cần đọc các bài viết về quản lí đối tượng Game :

Các kĩ năng lập trình mình sẽ không giới thiệu nữa.

Đây là Soure code hoàn thiện cuối cùng của mình, các bạn tải về rồi chiến thui.

Mình cũng đã ghi chú rất chi tiết trong quá trình làm game, hãy đọc nó để hiểu thêm ý tưởng của mình nhé.

  1. /////////
  2.  
  3. ////////
  4. ////////
  5. // GAME NÀY ĐƯỢC VIẾT BỞI :PHÙNG THÁI SƠN-10:28pm 5/9/2016
  6. // GAME ĐƯỢC UP CHÍNH THỨC TẠI ARDUINO.VN 4/2/2017
  7. //SỬ DỤNG 6 BUTTON NỐI PULLUP
  8. // VÀO HÀM setup, ve_nen, ĐỂ CÀI ĐẶT THEO SỞ THÍCH NHÉ
  9. //không bấm quá nhiều nút cùng lúc
  10. #include "ST7565_homephone.h"
  11. // add a bitmap library of a 16x16 fruit icon
  12. #include "bmps.h"
  13. ST7565 lcd(3, 4, 5, 6);
  14. //cài đặt chân input
  15. #define fight_b A5
  16. #define select_b A4
  17. #define right_b A3
  18. #define up_b A2
  19. #define left_b A1
  20. #define down_b A0
  21.  
  22. const static unsigned char __attribute__((progmem)) tank_ta_6x6[] = {
  23.  
  24. /* page 0 (lines 0-7) */
  25. 0x3f, 0x3f, 0x3f, 0x3f, 0xc, 0xc,
  26. };
  27. const static unsigned char __attribute__((progmem)) tank_dich_6x6[] = {
  28.  
  29. /* page 0 (lines 0-7) */
  30. 0x33, 0x33, 0x3f, 0x3f, 0xc, 0xc,
  31. };
  32. //số lượng tank lớn nhất , trong đó có cả tank ta
  33. //tank_dich_max là bao nhiêu tùy bạn 1,2,..,7.(5 thui)
  34. // mảng tĩnh sẽ ngốn Ram của bạn đấy
  35. #define tank_dich_max 20
  36. // 20 tank địch
  37. byte tank[1 + tank_dich_max][10]; // ma trận mảng xe tăng ( mảng 2 chiều), (mảng tĩnh nhé)
  38. // (cứ mỗi x, y trong c[x][y] thì ta mới được 1 ô giá trị)
  39. // tổng cộng cần 5 tanks nhân 9 thuộc tính = 45 biến byte !
  40. // mảng đầu quy định biển số xe thứ i từ 0 (ta) 1,2,3,4,..,tank_dich_max (địch)
  41. // mảng sau quy định thuộc tính của xe thứ i, bao gồm
  42. //tank[i][0]: trạng thái xe còn hay mất
  43. // tank[i][1]: hoành độ xe i
  44. // tank[i][2]: tung độ xe i
  45. // tank[i][3]: hướng xe ĐÔNG-1, BẮC-2, TÂY-3, NAM-4
  46. //tank[i][4]: số bước chân (pixel) mà xe đã đi
  47. //tank[i][5]: hoành độ đạn đang bay của xe i
  48. //tank[i][6]: tung độ đạn đang bay của xe i, tung độ có chiều dương hướng xuống nhá
  49. //tank[i][7]: hướng viên đạn đang bay của xe i
  50. //tank[i][8]: trạng thái đạn còn hay mất
  51. // hướng ĐÔNG-1, BẮC-2, TÂY-3, NAM-4
  52.  
  53. byte Xmin, Xmax, Ymin, Ymax; // giới hạn khung hình:biên
  54.  
  55. unsigned int diem;
  56.  
  57. unsigned int delay_toc_do;
  58. byte toc_do_dan, toc_do_dich, toc_do_ta;
  59. // Chương trình chạy 1 lần
  60. void setup()
  61. {
  62. //||||||||||||||||||||||||||||||||||||||
  63. //Serial.begin(9600);
  64. Serial.println(getMemoryFree()); //Kiểm tra RAM
  65.  
  66. lcd.ON();
  67. lcd.SET(23, 0, 0, 0, 4);
  68.  
  69. pinMode(left_b, INPUT_PULLUP);
  70. pinMode(down_b, INPUT_PULLUP);
  71. pinMode(right_b, INPUT_PULLUP);
  72. pinMode(up_b, INPUT_PULLUP);
  73. pinMode(fight_b, INPUT_PULLUP);
  74. pinMode(select_b, INPUT_PULLUP);
  75. //đặt ở chế độ sử dụng nội trở
  76. /*
  77. // nếu muốn dùng điện trở ngoài thì xóa bên trên đi, copy -dán đoạn này thay vào
  78. pinMode(left_b,INPUT);
  79. pinMode(down_b,INPUT);
  80. pinMode(right_b,INPUT);
  81. pinMode(up_b,INPUT);
  82. pinMode(fight_b,INPUT);
  83. pinMode(select_b,INPUT);
  84. */
  85. //biên
  86. Xmin = 3; // min=1
  87. Xmax = 125; //max=127
  88. Ymin = 2; //min=1
  89. Ymax = 61; //max=62
  90. // chu kỳ delay, tốc đọ khung hình
  91. // auto chỉnh delay theo số lượng tank
  92.  
  93. if (tank_dich_max <= 25) {
  94. //bạn đã cài tank_dich_max = bao nhiêu thế hử, 50 con sao?
  95. //sức chịu đựng của arduino cũng có hạn thui
  96. delay_toc_do = (50 - tank_dich_max * 2);
  97. }
  98. else {
  99. delay_toc_do = 5;
  100. }
  101. // tốc độ đạn, địch, ta
  102. toc_do_dan = 4;
  103. toc_do_dich = 1;
  104. toc_do_ta = 3;
  105. // điểm ban đầu
  106. diem = 0;
  107. /* BẬT CỔNG SERIAL ĐỂ XEM THÔNG BÁO
  108. // kiểm tra mảng
  109. Serial.begin(9600);
  110. // xuống dưới cùng phá ngoặc để mở thông báo */
  111. } // đóng set up
  112. void ve_nen()
  113. {
  114. //||||||||||||||||||||||||||||||||||||||||||
  115. //Bạn có thể vẽ bất cứ thứ gì lên màn hình khi nó
  116. //start game vào đây
  117. lcd.rect(8, 22, 118, 11, BLACK);
  118. lcd.Asc_String(10, 23, Asc("A R D U I N O . V N"), BLACK);
  119. lcd.rect(58, 54, 70, 11, BLACK);
  120. lcd.Asc_String(60, 55, Asc("By Thai Son"), BLACK);
  121.  
  122. lcd.display();
  123.  
  124. //||||||||||||||||||||||||||||||||||||||||||
  125. };
  126. void ve_tank_dich(byte x, byte y, byte huong)
  127. {
  128.  
  129. //buoc1: xóa
  130. xoa_xe(x, y);
  131. //bước 2: vẽ cái mới
  132. switch (huong) {
  133. case 1:
  134. // hướng đông
  135.  
  136. lcd.fillrect(x, y, 4, 2, BLACK);
  137. lcd.fillrect(x + 2, y + 2, 4, 2, BLACK);
  138. lcd.fillrect(x, y + 4, 4, 2, BLACK);
  139. /*
  140. lcd.Plus_Bitmap(x,y,6,6,tank_dich_6x6,0,NO_MIRROR, 0);// không xoay ảnh
  141. //lúc chạy lúc không, có lẽ là do tốc độ độc dữ liệu trong bộ nhớ Flash
  142. */
  143.  
  144. break;
  145. case 2:
  146. // hướng bắc
  147. lcd.fillrect(x, y + 2, 2, 4, BLACK);
  148. lcd.fillrect(x + 2, y, 2, 4, BLACK);
  149. lcd.fillrect(x + 4, y + 2, 2, 4, BLACK);
  150. /*
  151. lcd.Plus_Bitmap(x,y,6,6,tank_dich_6x6,90,NO_MIRROR, 0);// xoay ảnh 90
  152. //lúc chạy lúc không, có lẽ là do tốc độ độc dữ liệu trong bộ nhớ Flash
  153. */
  154. break;
  155.  
  156. case 3:
  157. // hướng tây
  158. lcd.fillrect(x + 2, y, 4, 2, BLACK);
  159. lcd.fillrect(x, y + 2, 4, 2, BLACK);
  160. lcd.fillrect(x + 2, y + 4, 4, 2, BLACK);
  161. /*
  162. lcd.Plus_Bitmap(x,y,6,6,tank_dich_6x6,180,NO_MIRROR, 0);// xoay ảnh 90
  163. //lúc chạy lúc không, có lẽ là do tốc độ độc dữ liệu trong bộ nhớ Flash
  164. */
  165. break;
  166.  
  167. case 4:
  168. // hướng nam
  169. lcd.fillrect(x, y, 2, 4, BLACK);
  170. lcd.fillrect(x + 2, y + 2, 2, 4, BLACK);
  171. lcd.fillrect(x + 4, y, 2, 4, BLACK);
  172. /*
  173. lcd.Plus_Bitmap(x,y,6,6,tank_dich_6x6,270,NO_MIRROR, 0);// xoay ảnh 90
  174. //lúc chạy lúc không, có lẽ là do tốc độ độc dữ liệu trong bộ nhớ Flash
  175. */
  176. break;
  177. default:
  178. break;
  179. } // đóng switch
  180. lcd.display();
  181.  
  182. }; //đóng ve_tank_dich
  183. /*
  184. switch tương đương với dòng lệnh sau :
  185. switch chỉ chấp nhận 2 kiểu biến đưa vào
  186. là char hoặc int
  187. neu la char thi phai viet : case 'a':.....case'b':...
  188. if (huong==2){// hướng đông
  189. lcd.fillrect(x,y,4,2,BLACK);
  190. lcd.fillrect(x+2,y+2,4,2,BLACK);
  191. lcd.fillrect(x,y+4,4,2,BLACK);
  192. }
  193. if (huong==2){ // hướng bắc
  194. lcd.fillrect(x,y+2,2,4,BLACK);
  195. lcd.fillrect(x+2,y,2,4,BLACK);
  196. lcd.fillrect(x+4,y+2,2,4,BLACK);
  197. }
  198.  
  199. if (huong==3){ // hướng tây
  200. lcd.fillrect(x+2,y,4,2,BLACK);
  201. lcd.fillrect(x,y+2,4,2,BLACK);
  202. lcd.fillrect(x+2,y+4,4,2,BLACK);
  203. }
  204.  
  205. if (huong==4){ // hướng nam
  206. lcd.fillrect(x,y,2,4,BLACK);
  207. lcd.fillrect(x+2,y+2,2,4,BLACK);
  208. lcd.fillrect(x+4,y,2,4,BLACK);
  209. }
  210. */
  211.  
  212. void ve_tank_ta(byte x, byte y, byte huong)
  213. {
  214. //buoc1: xóa
  215. xoa_xe(x, y);
  216. //bước 2: vẽ cái mới
  217. switch (huong) { // đổi về kiểu kí tự
  218. case 1:
  219. // hướng đông
  220. lcd.fillrect(x, y, 4, 2, BLACK);
  221. lcd.fillrect(x, y + 2, 6, 2, BLACK);
  222. lcd.fillrect(x, y + 4, 4, 2, BLACK);
  223. break;
  224. case 2:
  225. // hướng bắc
  226. lcd.fillrect(x, y + 2, 2, 4, BLACK);
  227. lcd.fillrect(x + 2, y, 2, 6, BLACK);
  228. lcd.fillrect(x + 4, y + 2, 2, 4, BLACK);
  229. break;
  230.  
  231. case 3:
  232. // hướng tây
  233. lcd.fillrect(x + 2, y, 4, 2, BLACK);
  234. lcd.fillrect(x, y + 2, 6, 2, BLACK);
  235. lcd.fillrect(x + 2, y + 4, 4, 2, BLACK);
  236. break;
  237.  
  238. case 4:
  239. // hướng nam
  240. lcd.fillrect(x, y, 2, 4, BLACK);
  241. lcd.fillrect(x + 2, y, 2, 6, BLACK);
  242. lcd.fillrect(x + 4, y, 2, 4, BLACK);
  243. break;
  244. default:
  245. break;
  246. } //đóng switch
  247. lcd.display();
  248.  
  249. }; //đóng ve_tank_ta
  250. void no(byte x, byte y)
  251. {
  252. // nổ xe tăng
  253. //tạo một thảm hình vuông
  254. byte a, b;
  255.  
  256. for (a = x - 2; a <= x + 6; a += 4) {
  257.  
  258. for (b = y - 2; b <= y + 6; b += 4) {
  259. lcd.fillrect(a, b, 2, 2, BLACK);
  260. }
  261. }
  262.  
  263. lcd.display();
  264. }; //đóng nổ xe tăng
  265. byte kiem_tra_vat_can(byte x, byte y, byte huong)
  266. {
  267. byte xi, yi;
  268.  
  269. //đôi lúc phía trước có vật cản nhưng không quay đầu
  270. //đó là vì ở lần duyệt đầu return kết thúc for ngay lập tức và trả về 0
  271. // thế cũng hay, mình không muốn đổi lại code nữa
  272. switch (huong) { //đổi về kiểu char
  273.  
  274. case 1:
  275. //phía dong_thì quét phía bên phải
  276. xi = x + 7;
  277. for (yi = y - 1; yi <= y + 5; yi++) {
  278. if (lcd.getpixel(xi, yi) == 1) {
  279. return 1;
  280. }
  281. else {
  282. return 0;
  283. }
  284. }
  285. break;
  286. case 2:
  287. //phía bắc_thì quét phía bên trên
  288. yi = y - 2;
  289. for (xi = x - 1; xi <= x + 6; xi++) {
  290. if (lcd.getpixel(xi, yi) == 1) {
  291. return 1;
  292. }
  293. else {
  294. return 0;
  295. }
  296. }
  297.  
  298. break;
  299. case 3:
  300. //phía tây_thì quét phía bên trái
  301. xi = x - 2;
  302. for (yi = y - 1; yi <= y + 6; yi++) {
  303. if (lcd.getpixel(xi, yi) == 1) {
  304. return 1;
  305. }
  306. else {
  307. return 0;
  308. }
  309. }
  310. break;
  311. case 4:
  312.  
  313. //phía nam_thì quét phía bên dưới
  314. yi = y + 7;
  315. for (xi = x - 1; xi < x + 6; xi++) {
  316. if (lcd.getpixel(xi, yi) == 1) {
  317. return 1;
  318. }
  319. else {
  320. return 0;
  321. }
  322. }
  323. break;
  324. default:
  325. break;
  326. } //đóng switch
  327. }; // đóng phát hiện vạt cản
  328.  
  329. void nhich_ve_phia_truoc_dich(byte x, byte y, byte huong, byte i)
  330. {
  331. byte xi, yi, hi;
  332. // bước 1: xóa xe
  333. xoa_xe(x, y);
  334. //bước 2: vẽ xe mới
  335. switch (huong) {
  336. case 1:
  337. xi = x + toc_do_dich;
  338. yi = y;
  339. hi = 1;
  340. ve_tank_dich(xi, yi, hi); //nhích sang bên phải
  341. break;
  342.  
  343. case 2:
  344.  
  345. xi = x;
  346. yi = y - toc_do_dich;
  347. hi = 2;
  348. ve_tank_dich(xi, yi, hi); //nhích lên phía trên
  349.  
  350. break;
  351.  
  352. case 3:
  353. xi = x - toc_do_dich;
  354. yi = y;
  355. hi = 3;
  356. ve_tank_dich(xi, yi, hi); //nhích sang bên trái
  357.  
  358. break;
  359.  
  360. case 4:
  361. xi = x;
  362. yi = y + toc_do_dich;
  363. hi = 4;
  364. ve_tank_dich(xi, yi, hi); //nhích xuống phía dưới
  365. break;
  366. default:
  367. break;
  368. } //đóng switch
  369.  
  370. //ghi vào mảng
  371. tank[i][1] = xi;
  372. tank[i][2] = yi;
  373. tank[i][3] = hi;
  374.  
  375. }; // đóng nhích về phía trước
  376.  
  377. void nhich_ve_phia_truoc_ta(byte x, byte y, byte huong)
  378. {
  379.  
  380. byte xi, yi, hi;
  381. // bước 1: xóa xe
  382. xoa_xe(x, y);
  383. //bước 2: vẽ xe mới
  384. switch (huong) {
  385.  
  386. case 1:
  387. xi = x + toc_do_ta;
  388. yi = y;
  389. hi = 1;
  390. ve_tank_ta(xi, yi, hi); //nhích sang bên phải
  391. break;
  392. case 2:
  393.  
  394. xi = x;
  395. yi = y - toc_do_ta;
  396. hi = 2;
  397. ve_tank_ta(xi, yi, hi); //nhích lên phía trên
  398.  
  399. break;
  400.  
  401. case 3:
  402. xi = x - toc_do_ta;
  403. yi = y;
  404. hi = 3;
  405. ve_tank_ta(xi, yi, hi); //nhích sang bên trái
  406. break;
  407.  
  408. case 4:
  409. xi = x;
  410. yi = y + toc_do_ta;
  411. hi = 4;
  412. ve_tank_ta(xi, yi, hi); //nhích xuống phía dưới
  413. break;
  414. default:
  415. break;
  416. } //đóng switch
  417. //ghi vào mảng
  418. tank[0][1] = xi;
  419. tank[0][2] = yi;
  420. tank[0][3] = hi;
  421. }; // đóng ta nhích về phía trước
  422. void ve_dan(byte x_dan, byte y_dan, byte huong_dan, byte i)
  423. {
  424. byte xi, yi, hi;
  425.  
  426. //bước 1: xóa cái cũ
  427. xoa_dan(x_dan, y_dan);
  428. //bước 2: vẽ 1 cái mới
  429. switch (int(huong_dan)) {
  430. case 1:
  431. // đạn bay về bên phải
  432.  
  433. xi = x_dan + toc_do_dan;
  434. yi = y_dan;
  435. hi = 1;
  436. lcd.fillrect(xi, yi, 2, 2, BLACK);
  437. break;
  438. case 2:
  439. // đạn bay về PHÍA trên
  440.  
  441. xi = x_dan;
  442. yi = y_dan - toc_do_dan;
  443. hi = 2;
  444. lcd.fillrect(xi, yi, 2, 2, BLACK);
  445. break;
  446. case 3:
  447. // đạn bay về bên trái
  448.  
  449. xi = x_dan - toc_do_dan;
  450. yi = y_dan;
  451. hi = 3;
  452. lcd.fillrect(xi, yi, 2, 2, BLACK);
  453. break;
  454. case 4:
  455. // đạn bay về phía dưới
  456.  
  457. xi = x_dan;
  458. yi = y_dan + toc_do_dan;
  459. hi = 4;
  460. lcd.fillrect(xi, yi, 2, 2, BLACK);
  461. break;
  462. default:
  463. break;
  464. } //đóng switch
  465. lcd.display();
  466.  
  467. //ghi vào mảng
  468. tank[i][5] = xi;
  469. tank[i][6] = yi;
  470. tank[i][7] = hi;
  471.  
  472. }; // đóng vẽ đạn
  473.  
  474. void xoa_dan(byte x_dan, byte y_dan)
  475. {
  476.  
  477. // xóa một viên đạn ở tọa độ x,y bằng 1 hình chữ nhật màu trắng
  478. lcd.fillrect(x_dan, y_dan, 2, 2, WHITE);
  479. lcd.display();
  480. }; // đóng xóa đạn
  481.  
  482. void xoa_xe(byte x, byte y)
  483. {
  484. // xóa một xe tăng ở tọa độ x,y bằng 1 hình chữ nhật màu trắng
  485.  
  486. lcd.fillrect(x, y, 6, 6, WHITE); // xóa xe bằng một hình cn màu trắng
  487. lcd.display();
  488. }; // đóng xóa xe tăng
  489.  
  490. byte doi_huong(byte huong)
  491. {
  492. // quy tắc đổi hướng: Quay sang bên trái của hướng hiện tại
  493. switch (huong) {
  494. case 1:
  495. return 2;
  496. break;
  497. case 2:
  498. return 3;
  499. break;
  500. case 3:
  501. return 4;
  502. break;
  503. case 4:
  504. return 1;
  505. break;
  506. default:
  507. break;
  508. } //dóng switch
  509. }; // đóng đổi hướng
  510.  
  511. void ve_xe_dich_main(byte i)
  512. {
  513.  
  514. byte chon_huong_tank, phat_hien, x_tank, y_tank, huong_tank, ton_tai;
  515. byte buoc_tank;
  516. byte x_dan, y_dan, huong_dan, ton_tai_dan;
  517. //duyệt xe địch từ thứ 1 đến tank_dich_max trong mảng
  518. ton_tai = tank[i][0];
  519. if (ton_tai == 0) {
  520. // nếu xe thứ i không có, hoặc chết rồi thì cần tạo xe mới
  521. lcd.Number_Long(Xmin + i * ((Xmax - Xmin) / tank_dich_max), Ymin / 8, i, ASCII_NUMBER, BLACK);
  522. // viết 1 chữ số ra màn hình/ (Ymin/8) là dòng thứ ?
  523. ve_tank_dich(Xmin + i * ((Xmax - Xmin) / tank_dich_max), Ymin + 10, i % 4 + 1);
  524. // vẽ xe có tọa độ theo biển số xe
  525. //i%4+1, nếu i=4 hoặc i=8 suy ra i%4=0,
  526. //mà hướng 1,2,3,4, nên phải +1 để khác 0
  527.  
  528. tank[i][1] = Xmin + i * ((Xmax - Xmin) / tank_dich_max); //ghi vào mảng hoành độ khởi đầu
  529. tank[i][2] = Ymin + 10; // ghi vào mảng tung độ khởi đầu
  530. tank[i][3] = (i % 4 + 1); //ghi vào mảng hướng ban đầu
  531. tank[i][4] = 0; // xe chưa đi 1 "bước" nào cả
  532. tank[i][0] = 1; // tích vào bảng, rằng đã tồn tại xe i
  533. }
  534. else { // xe i này vẫn sống
  535. //lấy thông tin của xe
  536. x_tank = tank[i][1];
  537. y_tank = tank[i][2];
  538. huong_tank = tank[i][3];
  539. buoc_tank = tank[i][4];
  540. phat_hien = kiem_tra_vat_can(x_tank, y_tank, huong_tank);
  541. // đổi hướng hay không
  542.  
  543. if ((x_tank <= Xmin) || (x_tank >= Xmax) || (y_tank <= Ymin) || (y_tank >= Ymax) || (phat_hien == 1)) {
  544.  
  545. // nếu ở trên biên hoặc có vật cản thì phải quay về hướng ngược lại
  546. tank[i][3] = doi_huong(huong_tank); // ghi vào mảng
  547. }
  548.  
  549. //di chuyển
  550. huong_tank = tank[i][3]; // Rồi lại gán
  551. //sau đó nhích về phía trước 1 pixel
  552. nhich_ve_phia_truoc_dich(x_tank, y_tank, huong_tank, i);
  553. tank[i][4] = buoc_tank + 1; // nhích về phía trước thì phải cộng thêm 1 "bước"
  554. buoc_tank = tank[i][4]; //rồi lại gán, muốn dùng thì phải gán
  555. //CHuẩn bị bắn
  556. // QUY ƯỚC: xe tăng thứ i sẽ di chuyển i*5 bước rồi bắn 1 lần
  557. // VÀ
  558. //QUY ƯỚC: xe chỉ được bắn khi viên đạn của xe đó đã bị mất
  559. ton_tai_dan = tank[i][8];
  560. if ((buoc_tank >= (i * 5)) && (ton_tai_dan == 0)) { //kiểm tra thỏa mãn
  561. //nạp đạn
  562. tank[i][7] = huong_tank; // đặt hướng đạn là hướng hiện tại của xe
  563. tank[i][5] = x_tank + 2; // viên đạn nằm bên trong xe
  564. tank[i][6] = y_tank + 2; // viên đạn nằm bên trong xe
  565. tank[i][4] = 0; // đặt lại bước = 0 (mất 1 ngày để tìm ra lỗi này, hic ^^)s
  566. tank[i][8] = 1; // tích vào mảng rằng viên đạn của xe i đã tồn tại
  567. }
  568. //vẽ đạn
  569. // lại gán
  570. if (ton_tai_dan == 1) {
  571. x_dan = tank[i][5];
  572. y_dan = tank[i][6];
  573. huong_dan = tank[i][7];
  574. //rồi mới vẽ
  575. ve_dan(x_dan, y_dan, huong_dan, i);
  576.  
  577. } //đóng vẽ đạn
  578. } //đóng else if đầu
  579.  
  580. } // đóng vẽ xe địch main
  581. void ve_xe_ta_main()
  582. {
  583.  
  584. /*
  585. // DI CHUYỂN XE TA------------------------------------------------------
  586. */
  587. byte huong_tank_ta, x_tank_ta, y_tank_ta; //tank của ta
  588. byte huong_tank_ta_button;
  589. huong_tank_ta_button = lcd.pullup_4(right_b, up_b, left_b, down_b); // đọc giá trị diều khiển
  590.  
  591. //lấy thông tin của xe tank
  592. x_tank_ta = tank[0][1];
  593. y_tank_ta = tank[0][2];
  594. huong_tank_ta = tank[0][3];
  595. /*buoc_tank=tank[i][4];
  596. */
  597. if (huong_tank_ta_button != 0) { // có 1 nút được nhấn
  598. if (huong_tank_ta_button != huong_tank_ta) {
  599. // nếu hướng cũ của xe khác với giá trị nút nhấn
  600. //thì đặt lại hướng của xe là giá trị nút nhấn
  601. //thế mới gọi là điều khiển chứ !
  602. tank[0][3] = huong_tank_ta_button;
  603. // gán
  604. huong_tank_ta = tank[0][3];
  605. // rồi vẽ
  606. ve_tank_ta(x_tank_ta, y_tank_ta, huong_tank_ta);
  607. }
  608. else {
  609. // ngược lại, nút ấn có vai trò di chuyển xe
  610.  
  611. // nếu xe trong biên và không có vật cản thì mới được phép đi
  612. nhich_ve_phia_truoc_ta(x_tank_ta, y_tank_ta, huong_tank_ta);
  613.  
  614. } // đóng else if ngoài
  615. } //dóng if ngoài
  616. /*
  617. // TA BẮN ĐẠN-----------------------------------------------------
  618. */
  619. //đạn của ta
  620. byte huong_dan_ta, x_dan_ta, y_dan_ta, ton_tai_dan_ta;
  621. byte OK_BAN;
  622.  
  623. //QUY ƯỚC: xe chỉ được bắn khi viên đạn của xe đã bị mất + NHẤN NÚT
  624.  
  625. ton_tai_dan_ta = tank[0][8];
  626. OK_BAN = digitalRead(fight_b); // nút fight có được nhấn hay không
  627. if ((OK_BAN == 0) && (ton_tai_dan_ta == 0)) {
  628. //NÚT fight đã nhấn
  629.  
  630. //lấy thông tin của xe tank
  631. x_tank_ta = tank[0][1];
  632. y_tank_ta = tank[0][2];
  633. huong_tank_ta = tank[0][3];
  634. //nạp đạn
  635. tank[0][7] = huong_tank_ta; // đặt hướng đạn là hướng hiện tại của xe
  636. tank[0][5] = x_tank_ta + 2; // viên đạn nằm bên trong xe
  637. tank[0][6] = y_tank_ta + 2; // viên đạn nằm bên trong xe
  638. // nạp đạn xong
  639. tank[0][8] = 1; // viên đạn đã tồn tại
  640. } // đóng if bắn
  641. //gán
  642. ton_tai_dan_ta = tank[0][8];
  643. //vẽ đạn
  644. if (ton_tai_dan_ta == 1) {
  645.  
  646. //lấy thông tin
  647. x_dan_ta = tank[0][5];
  648. y_dan_ta = tank[0][6];
  649. huong_dan_ta = tank[0][7];
  650. //vẽ đạn
  651. ve_dan(x_dan_ta, y_dan_ta, huong_dan_ta, 0); // số "0" ở cuối là biển số của xe ta
  652. } // đóng if vẽ
  653.  
  654. } //đóng vẽ xe ta main
  655. void bang_diem(byte i)
  656. {
  657.  
  658. lcd.Asc_String(10, 2, Asc("Diem:"), BLACK);
  659. lcd.Number_Long(35, 2, diem, ASCII_NUMBER, BLACK);
  660.  
  661. lcd.Asc_String(10, 12, Asc("Thu pham:T"), BLACK);
  662.  
  663. lcd.Number_Long(75, 12, i, ASCII_NUMBER, BLACK);
  664. lcd.display();
  665.  
  666. //Reset tank[1+tank_dich_max][10]
  667. for (byte xxx = 0; xxx <= tank_dich_max; xxx++) {
  668. for (byte yyy = 0; yyy <= 10; yyy++) {
  669. tank[xxx][yyy] = 0;
  670. }
  671. }
  672. // reset diem
  673. diem = 0;
  674.  
  675. } // dong bang diem
  676.  
  677. void lap_vo_han()
  678. {
  679. // dừng dòng chảy chính bằng vòng lặp vô hạn
  680. //thoát lặp khi nút Fight được nhấn
  681.  
  682. int y = 55;
  683. lcd.Asc_String(10, y + 2, Asc("Fight!"), BLACK);
  684. lcd.display();
  685. while (digitalRead(fight_b) != 0) {
  686. lcd.rect(8, 55, 40, 10, BLACK);
  687. lcd.display();
  688. if (digitalRead(fight_b) == 0) {
  689.  
  690. break; // thoát ngay
  691. }
  692. delay(250);
  693.  
  694. lcd.rect(8, y, 40, 10, DELETE);
  695. lcd.display();
  696.  
  697. if (digitalRead(fight_b) == 0) {
  698. break; // thoát ngay
  699. }
  700. delay(250);
  701. }
  702. } //đóng lặp vô hạn
  703.  
  704. /*====================================================
  705. * ===================================================
  706. * ĐÓNG KHAI BÁO CÁC HÀM+CÀI ĐẶT
  707. * ===================================================
  708. * VÀO VÒNG LẶP CỦA DÒNG CHẢY CHÍNH
  709. * ===================================================
  710. * ===================================================
  711. */
  712.  
  713. void loop()
  714.  
  715. {
  716. //goi doi tuong la game
  717.  
  718. //Bắt đầu game, vẽ xe ta----------------------------------------
  719.  
  720. byte xe_ta_ton_tai;
  721. xe_ta_ton_tai = tank[0][0];
  722. if (xe_ta_ton_tai == 0) {
  723. ve_tank_ta(30, 55, 2); // tại 30-55, đang hướng lên phía trên
  724. ve_nen(); //vẽ nền game
  725. tank[0][1] = 30; //ghi vào mảng hoành độ khởi đầu
  726. tank[0][2] = 55; // ghi vào mảng tung độ khởi đầu
  727. tank[0][3] = 2; //ghi vào mảng hướng ban đầu
  728. tank[0][4] = 0; // xe chưa đi 1 "bước" nào cả !
  729. tank[0][0] = 1; // tích vào bảng, rằng đã tồn tại xe ta
  730. }
  731. /*
  732. //VẼ XE ĐỊCH----------------------------------------------------------
  733. */
  734.  
  735. for (byte i = 1; i <= tank_dich_max; i++) {
  736.  
  737. //duyệt xe địch từ thứ 1 đến tank_dich_max trong mảng
  738. ve_xe_dich_main(i);
  739. //rồi lặp cho đủ tank_dich_max xe
  740. } // đóng for
  741.  
  742. /*
  743. //VẼ XE TA----------------------------------------------------------
  744. */
  745. ve_xe_ta_main();
  746.  
  747. /*
  748. // Xóa ĐẠN ĐỊCH VÀ TA
  749. // NẾU ĐẠN VƯỢT BIÊN THÌ ĐẠN BỊ XÓA-----------------------
  750. */
  751. for (byte i = 0; i <= tank_dich_max; i++) {
  752. byte X_DAN, Y_DAN;
  753. X_DAN = tank[i][5];
  754. Y_DAN = tank[i][6];
  755. if ((X_DAN <= Xmin) || (X_DAN >= Xmax) || (Y_DAN <= Ymin) || (Y_DAN >= Ymax)) {
  756. tank[i][8] = 0; // xóa tồn tại đạn
  757. xoa_dan(X_DAN, Y_DAN);
  758. // xóa tọa độ đạn
  759. //không cần đâu, nó sẽ được ghi đè
  760. //và bảo vệ bởi hàm kiểm tra tồn tại
  761. // nếu quá 224 thì nó bị quay về 0 nếu ta tiếp tục tăng giá trị cho nó
  762. }
  763.  
  764. } //đóng for xóa đạn
  765.  
  766. /*
  767. //KIỂM TRA VA CHẠM-------------------------------------------
  768. */
  769. // xét (tank_dich_max) xe địch và 1 viên đạn của ta
  770. //-------------------------------------------------
  771. int hieu_x_dich, hieu_y_dich;
  772. for (byte i = 1; i <= tank_dich_max; i++) {
  773. hieu_x_dich = tank[0][5] - tank[i][1];
  774. hieu_y_dich = tank[0][6] - tank[i][2];
  775. // nếu tọa độ đạn ta trừ tọa độ xe địch mà dương và <=5 và đạn còn tồn tại
  776. // dính đạn
  777. if ((hieu_x_dich >= 0) && (hieu_x_dich <= 5) && (hieu_y_dich >= 0) && (hieu_y_dich <= 5) && (tank[0][8] == 1)) {
  778. // vẽ một vụ nổ tại tọa độ xe đó
  779. no(tank[i][1], tank[i][2]);
  780. // khai tử xe tăng đó
  781. tank[i][0] = 0;
  782. // khai tử viên đạn cửa ta
  783. tank[0][8] = 0;
  784. //cộng điểm người chơi đạt được khi giết tank i
  785. diem++;
  786. } // đóng if
  787. } // đóng for
  788.  
  789. // xét ta và (tank_dich_max) viên đạn cửa địch
  790. //--------------------------------------------------
  791. for (byte i = 1; i <= tank_dich_max; i++) {
  792.  
  793. int hieu_x_ta, hieu_y_ta;
  794. // nếu tọa độ đạn địch trừ tọa độ xe ta mà dương và <=5
  795. // dính đạn
  796. hieu_x_ta = tank[i][5] - tank[0][1];
  797. hieu_y_ta = tank[i][6] - tank[0][2];
  798.  
  799. if ((hieu_x_ta >= 0) && (hieu_x_ta <= 5) && (hieu_y_ta >= 0) && (hieu_y_ta <= 5)) {
  800. // vẽ một vụ nổ tại tọa độ xe đó
  801. no(tank[0][1], tank[0][2]);
  802. delay(1000);
  803.  
  804. lcd.clear();
  805.  
  806. //THUA CUỘC
  807. // BẢNG ĐIỂM
  808. ///---------------------------------------------
  809.  
  810. bang_diem(i);
  811.  
  812. //LẶP CÓ ĐIỀU KIỆN
  813. //Nhấn nút fight để chơi tiếp
  814.  
  815. lap_vo_han();
  816. //-------------------------------------------
  817.  
  818. //thoát lặp
  819. lcd.clear();
  820.  
  821. goto the_end; // nhảy cóc tới nhãn the end cuối trang
  822. //nếu không có lệnh này, for sẽ lặp lại cho đến max con chạy
  823. //và ta sẽ phải nhấn giữ khá lâu
  824. } // đóng if
  825.  
  826. } //đóng for kiểm tra va trạm
  827.  
  828. /*
  829.  
  830. // KẾT THÚC HÀM
  831. // KẾT THÚC 2 NGÀY LÀM VIỆC CHĂM CHỈ!
  832. // kiểm tra mảng
  833. //___________________________
  834. //__________________________
  835. Serial.print("DIEM CUA BAN :");
  836.  
  837. Serial.println(diem);
  838. int aaa,bbb;
  839.  
  840. Serial.println("___________YES/NO______X TANK____Y TANK__HUONG ____BUOC____X DAN____Y DAN_____HUONG_____YES/NO");
  841. // XE TĂNG SỐ 0 LÀ CỦA BẠN
  842. // 1,2,3,4 LÀ ĐỊCH
  843. // YES/NO : CÒN SỐNG HAY ĐÃ CHẾT
  844. // X, Y TANK: TỌA ĐỘ XE TĂNG ĐÓ
  845. // HUONG: HƯỚNG CỦA MŨI XE ĐÓ CHỈ ĐI ĐÂU (1->4) (ĐÔNG, BẮC, TÂY, NAM)
  846. // BUOC; XE ĐÓ ĐÃ ĐI ĐƯỢC BAO NHIÊU BƯỚC (RIÊNG XE MÌNH THÌ KHÔNG CẦN)
  847. // X,Y DAN: TỌA ĐỌ VIÊN ĐẠN CỦA XE TĂNG ĐÓ
  848. // HƯỚNG VIÊN ĐẠN
  849. // YES/NO: VIÊN ĐẠN CÒN HAY MẤT
  850. for(aaa=0; aaa<tank_dich_max; aaa++){
  851. Serial.print("XE SO:");
  852. Serial.print(aaa);
  853. for(bbb=0; bbb<10; bbb++){
  854. Serial.print("________");
  855. Serial.print(tank[aaa][bbb]);
  856. }
  857. Serial.println("");
  858. }
  859. // */
  860.  
  861. //Serial.println( getMemoryFree()); //KIỂM TRA RAM
  862.  
  863. the_end:
  864.  
  865. //Serial.println( getMemoryFree()); //KIỂM TRA RAM
  866. delay(delay_toc_do);
  867. } //đóng loop
  868. int getMemoryFree()
  869. {
  870. //HÀM NÀY TRẢ VỀ SỐ RAM CÒN DƯ TRÊN ARDUINO
  871. extern int __heap_start;
  872. extern int* __brkval;
  873. return (int)SP - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
  874. //mấy cái __heap_start, __brkval là những thanh ghi của cấu trúc harvard (cấu trúc của các vđk). VXL như intel, arm,.. dùng cấu trúc john von neuman
  875. }
  876.  
  877. //////////
  878. /////////
  879. /////////

 

4

Cài map

Bạn có thể thay thế hàm ve_nen() bằng các hàm sau để tạo Map.

Map matrix

void ve_nen()
{
    //||||||||||||||||||||||||||||||||||||||||||
    //Bạn có thể vẽ bất cứ thứ gì lên màn hình khi nó
    //start game vào đây
    for (int x = 0; x < Xmax; x += 10) {
        for (int y = 15; y < 60; y += 10) {
            lcd.FillRect(x, y, 5, 5, BLACK);
            lcd.display();
            delay(30);
        }
    }
}

Map thành phố - Random

void ve_nen()
{
    //||||||||||||||||||||||||||||||||||||||||||
    //Bạn có thể vẽ bất cứ thứ gì lên màn hình khi nó
    //start game vào đây
    int x, y, size_brick;
    for (int i = 0; i < 50; i++) {
        // 50 viên gạch
        randomSeed(millis()); // lấy random từ đồng hồ
        x = random(Xmin, Xmax);
        y = random(Ymin, Ymax - 15);
        size_brick = random(3, 10);
        lcd.FillRect(x, y, size_brick, size_brick, BLACK);
        lcd.display();
        delay(30);
    }
}

Map rừng rậm - Random

void ve_nen()
{

    //||||||||||||||||||||||||||||||||||||||||||
    //Bạn có thể vẽ bất cứ thứ gì lên màn hình khi nó
    //start game vào đây

    int x, y, R;
    for (int i = 0; i < 25; i++) {
        // 50 viên gạch
        randomSeed(millis()); // lấy random từ đồng hồ
        x = random(Xmin, Xmax);
        y = random(Ymin, Ymax);
        R = random(3, 10);
        lcd.FillCircle(x, y, R, BLACK);
        lcd.display();
        delay(30);
    }
}
Bình luận
Nội dung này chưa có bình luận, hãy gửi bình luận đầu tiên của bạn.
VIẾT BÌNH LUẬN CỦA BẠN