-
-
-
Tổng tiền thanh toán:
-

GAME-ST7565 - Làm Game xe tăng với Arduino
07/08/2019

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 .
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 :
- Phần 1: Hiệu ứng đồ họa Game trên lcd
- Phần 2: Chuyển động và lập trình cơ bản
- Phần 3: Quản lí các đối tượng Game
- Phần 4: Xử lí va chạm của của các đố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é.
- /////////
- ////////
- ////////
- // GAME NÀY ĐƯỢC VIẾT BỞI :PHÙNG THÁI SƠN-10:28pm 5/9/2016
- // GAME ĐƯỢC UP CHÍNH THỨC TẠI ARDUINO.VN 4/2/2017
- //SỬ DỤNG 6 BUTTON NỐI PULLUP
- // VÀO HÀM setup, ve_nen, ĐỂ CÀI ĐẶT THEO SỞ THÍCH NHÉ
- //không bấm quá nhiều nút cùng lúc
- #include "ST7565_homephone.h"
- // add a bitmap library of a 16x16 fruit icon
- #include "bmps.h"
- ST7565 lcd(3, 4, 5, 6);
- //cài đặt chân input
- #define fight_b A5
- #define select_b A4
- #define right_b A3
- #define up_b A2
- #define left_b A1
- #define down_b A0
- const static unsigned char __attribute__((progmem)) tank_ta_6x6[] = {
- /* page 0 (lines 0-7) */
- 0x3f, 0x3f, 0x3f, 0x3f, 0xc, 0xc,
- };
- const static unsigned char __attribute__((progmem)) tank_dich_6x6[] = {
- /* page 0 (lines 0-7) */
- 0x33, 0x33, 0x3f, 0x3f, 0xc, 0xc,
- };
- //số lượng tank lớn nhất , trong đó có cả tank ta
- //tank_dich_max là bao nhiêu tùy bạn 1,2,..,7.(5 thui)
- // mảng tĩnh sẽ ngốn Ram của bạn đấy
- #define tank_dich_max 20
- // 20 tank địch
- 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é)
- // (cứ mỗi x, y trong c[x][y] thì ta mới được 1 ô giá trị)
- // tổng cộng cần 5 tanks nhân 9 thuộc tính = 45 biến byte !
- // mảng đầu quy định biển số xe thứ i từ 0 (ta) 1,2,3,4,..,tank_dich_max (địch)
- // mảng sau quy định thuộc tính của xe thứ i, bao gồm
- //tank[i][0]: trạng thái xe còn hay mất
- // tank[i][1]: hoành độ xe i
- // tank[i][2]: tung độ xe i
- // tank[i][3]: hướng xe ĐÔNG-1, BẮC-2, TÂY-3, NAM-4
- //tank[i][4]: số bước chân (pixel) mà xe đã đi
- //tank[i][5]: hoành độ đạn đang bay của xe i
- //tank[i][6]: tung độ đạn đang bay của xe i, tung độ có chiều dương hướng xuống nhá
- //tank[i][7]: hướng viên đạn đang bay của xe i
- //tank[i][8]: trạng thái đạn còn hay mất
- // hướng ĐÔNG-1, BẮC-2, TÂY-3, NAM-4
- byte Xmin, Xmax, Ymin, Ymax; // giới hạn khung hình:biên
- unsigned int diem;
- unsigned int delay_toc_do;
- byte toc_do_dan, toc_do_dich, toc_do_ta;
- // Chương trình chạy 1 lần
- void setup()
- {
- //||||||||||||||||||||||||||||||||||||||
- //Serial.begin(9600);
- Serial.println(getMemoryFree()); //Kiểm tra RAM
- lcd.ON();
- lcd.SET(23, 0, 0, 0, 4);
- pinMode(left_b, INPUT_PULLUP);
- pinMode(down_b, INPUT_PULLUP);
- pinMode(right_b, INPUT_PULLUP);
- pinMode(up_b, INPUT_PULLUP);
- pinMode(fight_b, INPUT_PULLUP);
- pinMode(select_b, INPUT_PULLUP);
- //đặt ở chế độ sử dụng nội trở
- /*
- // 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
- pinMode(left_b,INPUT);
- pinMode(down_b,INPUT);
- pinMode(right_b,INPUT);
- pinMode(up_b,INPUT);
- pinMode(fight_b,INPUT);
- pinMode(select_b,INPUT);
- */
- //biên
- Xmin = 3; // min=1
- Xmax = 125; //max=127
- Ymin = 2; //min=1
- Ymax = 61; //max=62
- // chu kỳ delay, tốc đọ khung hình
- // auto chỉnh delay theo số lượng tank
- if (tank_dich_max <= 25) {
- //bạn đã cài tank_dich_max = bao nhiêu thế hử, 50 con sao?
- //sức chịu đựng của arduino cũng có hạn thui
- delay_toc_do = (50 - tank_dich_max * 2);
- }
- else {
- delay_toc_do = 5;
- }
- // tốc độ đạn, địch, ta
- toc_do_dan = 4;
- toc_do_dich = 1;
- toc_do_ta = 3;
- // điểm ban đầu
- diem = 0;
- /* BẬT CỔNG SERIAL ĐỂ XEM THÔNG BÁO
- // kiểm tra mảng
- Serial.begin(9600);
- // xuống dưới cùng phá ngoặc để mở thông báo */
- } // đóng set up
- 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
- lcd.rect(8, 22, 118, 11, BLACK);
- lcd.Asc_String(10, 23, Asc("A R D U I N O . V N"), BLACK);
- lcd.rect(58, 54, 70, 11, BLACK);
- lcd.Asc_String(60, 55, Asc("By Thai Son"), BLACK);
- lcd.display();
- //||||||||||||||||||||||||||||||||||||||||||
- };
- void ve_tank_dich(byte x, byte y, byte huong)
- {
- //buoc1: xóa
- xoa_xe(x, y);
- //bước 2: vẽ cái mới
- switch (huong) {
- case 1:
- // hướng đông
- lcd.fillrect(x, y, 4, 2, BLACK);
- lcd.fillrect(x + 2, y + 2, 4, 2, BLACK);
- lcd.fillrect(x, y + 4, 4, 2, BLACK);
- /*
- lcd.Plus_Bitmap(x,y,6,6,tank_dich_6x6,0,NO_MIRROR, 0);// không xoay ảnh
- //lúc chạy lúc không, có lẽ là do tốc độ độc dữ liệu trong bộ nhớ Flash
- */
- break;
- case 2:
- // hướng bắc
- lcd.fillrect(x, y + 2, 2, 4, BLACK);
- lcd.fillrect(x + 2, y, 2, 4, BLACK);
- lcd.fillrect(x + 4, y + 2, 2, 4, BLACK);
- /*
- lcd.Plus_Bitmap(x,y,6,6,tank_dich_6x6,90,NO_MIRROR, 0);// xoay ảnh 90
- //lúc chạy lúc không, có lẽ là do tốc độ độc dữ liệu trong bộ nhớ Flash
- */
- break;
- case 3:
- // hướng tây
- lcd.fillrect(x + 2, y, 4, 2, BLACK);
- lcd.fillrect(x, y + 2, 4, 2, BLACK);
- lcd.fillrect(x + 2, y + 4, 4, 2, BLACK);
- /*
- lcd.Plus_Bitmap(x,y,6,6,tank_dich_6x6,180,NO_MIRROR, 0);// xoay ảnh 90
- //lúc chạy lúc không, có lẽ là do tốc độ độc dữ liệu trong bộ nhớ Flash
- */
- break;
- case 4:
- // hướng nam
- lcd.fillrect(x, y, 2, 4, BLACK);
- lcd.fillrect(x + 2, y + 2, 2, 4, BLACK);
- lcd.fillrect(x + 4, y, 2, 4, BLACK);
- /*
- lcd.Plus_Bitmap(x,y,6,6,tank_dich_6x6,270,NO_MIRROR, 0);// xoay ảnh 90
- //lúc chạy lúc không, có lẽ là do tốc độ độc dữ liệu trong bộ nhớ Flash
- */
- break;
- default:
- break;
- } // đóng switch
- lcd.display();
- }; //đóng ve_tank_dich
- /*
- switch tương đương với dòng lệnh sau :
- switch chỉ chấp nhận 2 kiểu biến đưa vào
- là char hoặc int
- neu la char thi phai viet : case 'a':.....case'b':...
- if (huong==2){// hướng đông
- lcd.fillrect(x,y,4,2,BLACK);
- lcd.fillrect(x+2,y+2,4,2,BLACK);
- lcd.fillrect(x,y+4,4,2,BLACK);
- }
- if (huong==2){ // hướng bắc
- lcd.fillrect(x,y+2,2,4,BLACK);
- lcd.fillrect(x+2,y,2,4,BLACK);
- lcd.fillrect(x+4,y+2,2,4,BLACK);
- }
- if (huong==3){ // hướng tây
- lcd.fillrect(x+2,y,4,2,BLACK);
- lcd.fillrect(x,y+2,4,2,BLACK);
- lcd.fillrect(x+2,y+4,4,2,BLACK);
- }
- if (huong==4){ // hướng nam
- lcd.fillrect(x,y,2,4,BLACK);
- lcd.fillrect(x+2,y+2,2,4,BLACK);
- lcd.fillrect(x+4,y,2,4,BLACK);
- }
- */
- void ve_tank_ta(byte x, byte y, byte huong)
- {
- //buoc1: xóa
- xoa_xe(x, y);
- //bước 2: vẽ cái mới
- switch (huong) { // đổi về kiểu kí tự
- case 1:
- // hướng đông
- lcd.fillrect(x, y, 4, 2, BLACK);
- lcd.fillrect(x, y + 2, 6, 2, BLACK);
- lcd.fillrect(x, y + 4, 4, 2, BLACK);
- break;
- case 2:
- // hướng bắc
- lcd.fillrect(x, y + 2, 2, 4, BLACK);
- lcd.fillrect(x + 2, y, 2, 6, BLACK);
- lcd.fillrect(x + 4, y + 2, 2, 4, BLACK);
- break;
- case 3:
- // hướng tây
- lcd.fillrect(x + 2, y, 4, 2, BLACK);
- lcd.fillrect(x, y + 2, 6, 2, BLACK);
- lcd.fillrect(x + 2, y + 4, 4, 2, BLACK);
- break;
- case 4:
- // hướng nam
- lcd.fillrect(x, y, 2, 4, BLACK);
- lcd.fillrect(x + 2, y, 2, 6, BLACK);
- lcd.fillrect(x + 4, y, 2, 4, BLACK);
- break;
- default:
- break;
- } //đóng switch
- lcd.display();
- }; //đóng ve_tank_ta
- void no(byte x, byte y)
- {
- // nổ xe tăng
- //tạo một thảm hình vuông
- byte a, b;
- for (a = x - 2; a <= x + 6; a += 4) {
- for (b = y - 2; b <= y + 6; b += 4) {
- lcd.fillrect(a, b, 2, 2, BLACK);
- }
- }
- lcd.display();
- }; //đóng nổ xe tăng
- byte kiem_tra_vat_can(byte x, byte y, byte huong)
- {
- byte xi, yi;
- //đôi lúc phía trước có vật cản nhưng không quay đầu
- //đó là vì ở lần duyệt đầu return kết thúc for ngay lập tức và trả về 0
- // thế cũng hay, mình không muốn đổi lại code nữa
- switch (huong) { //đổi về kiểu char
- case 1:
- //phía dong_thì quét phía bên phải
- xi = x + 7;
- for (yi = y - 1; yi <= y + 5; yi++) {
- if (lcd.getpixel(xi, yi) == 1) {
- return 1;
- }
- else {
- return 0;
- }
- }
- break;
- case 2:
- //phía bắc_thì quét phía bên trên
- yi = y - 2;
- for (xi = x - 1; xi <= x + 6; xi++) {
- if (lcd.getpixel(xi, yi) == 1) {
- return 1;
- }
- else {
- return 0;
- }
- }
- break;
- case 3:
- //phía tây_thì quét phía bên trái
- xi = x - 2;
- for (yi = y - 1; yi <= y + 6; yi++) {
- if (lcd.getpixel(xi, yi) == 1) {
- return 1;
- }
- else {
- return 0;
- }
- }
- break;
- case 4:
- //phía nam_thì quét phía bên dưới
- yi = y + 7;
- for (xi = x - 1; xi < x + 6; xi++) {
- if (lcd.getpixel(xi, yi) == 1) {
- return 1;
- }
- else {
- return 0;
- }
- }
- break;
- default:
- break;
- } //đóng switch
- }; // đóng phát hiện vạt cản
- void nhich_ve_phia_truoc_dich(byte x, byte y, byte huong, byte i)
- {
- byte xi, yi, hi;
- // bước 1: xóa xe
- xoa_xe(x, y);
- //bước 2: vẽ xe mới
- switch (huong) {
- case 1:
- xi = x + toc_do_dich;
- yi = y;
- hi = 1;
- ve_tank_dich(xi, yi, hi); //nhích sang bên phải
- break;
- case 2:
- xi = x;
- yi = y - toc_do_dich;
- hi = 2;
- ve_tank_dich(xi, yi, hi); //nhích lên phía trên
- break;
- case 3:
- xi = x - toc_do_dich;
- yi = y;
- hi = 3;
- ve_tank_dich(xi, yi, hi); //nhích sang bên trái
- break;
- case 4:
- xi = x;
- yi = y + toc_do_dich;
- hi = 4;
- ve_tank_dich(xi, yi, hi); //nhích xuống phía dưới
- break;
- default:
- break;
- } //đóng switch
- //ghi vào mảng
- tank[i][1] = xi;
- tank[i][2] = yi;
- tank[i][3] = hi;
- }; // đóng nhích về phía trước
- void nhich_ve_phia_truoc_ta(byte x, byte y, byte huong)
- {
- byte xi, yi, hi;
- // bước 1: xóa xe
- xoa_xe(x, y);
- //bước 2: vẽ xe mới
- switch (huong) {
- case 1:
- xi = x + toc_do_ta;
- yi = y;
- hi = 1;
- ve_tank_ta(xi, yi, hi); //nhích sang bên phải
- break;
- case 2:
- xi = x;
- yi = y - toc_do_ta;
- hi = 2;
- ve_tank_ta(xi, yi, hi); //nhích lên phía trên
- break;
- case 3:
- xi = x - toc_do_ta;
- yi = y;
- hi = 3;
- ve_tank_ta(xi, yi, hi); //nhích sang bên trái
- break;
- case 4:
- xi = x;
- yi = y + toc_do_ta;
- hi = 4;
- ve_tank_ta(xi, yi, hi); //nhích xuống phía dưới
- break;
- default:
- break;
- } //đóng switch
- //ghi vào mảng
- tank[0][1] = xi;
- tank[0][2] = yi;
- tank[0][3] = hi;
- }; // đóng ta nhích về phía trước
- void ve_dan(byte x_dan, byte y_dan, byte huong_dan, byte i)
- {
- byte xi, yi, hi;
- //bước 1: xóa cái cũ
- xoa_dan(x_dan, y_dan);
- //bước 2: vẽ 1 cái mới
- switch (int(huong_dan)) {
- case 1:
- // đạn bay về bên phải
- xi = x_dan + toc_do_dan;
- yi = y_dan;
- hi = 1;
- lcd.fillrect(xi, yi, 2, 2, BLACK);
- break;
- case 2:
- // đạn bay về PHÍA trên
- xi = x_dan;
- yi = y_dan - toc_do_dan;
- hi = 2;
- lcd.fillrect(xi, yi, 2, 2, BLACK);
- break;
- case 3:
- // đạn bay về bên trái
- xi = x_dan - toc_do_dan;
- yi = y_dan;
- hi = 3;
- lcd.fillrect(xi, yi, 2, 2, BLACK);
- break;
- case 4:
- // đạn bay về phía dưới
- xi = x_dan;
- yi = y_dan + toc_do_dan;
- hi = 4;
- lcd.fillrect(xi, yi, 2, 2, BLACK);
- break;
- default:
- break;
- } //đóng switch
- lcd.display();
- //ghi vào mảng
- tank[i][5] = xi;
- tank[i][6] = yi;
- tank[i][7] = hi;
- }; // đóng vẽ đạn
- void xoa_dan(byte x_dan, byte y_dan)
- {
- // xóa một viên đạn ở tọa độ x,y bằng 1 hình chữ nhật màu trắng
- lcd.fillrect(x_dan, y_dan, 2, 2, WHITE);
- lcd.display();
- }; // đóng xóa đạn
- void xoa_xe(byte x, byte y)
- {
- // xóa một xe tăng ở tọa độ x,y bằng 1 hình chữ nhật màu trắng
- lcd.fillrect(x, y, 6, 6, WHITE); // xóa xe bằng một hình cn màu trắng
- lcd.display();
- }; // đóng xóa xe tăng
- byte doi_huong(byte huong)
- {
- // quy tắc đổi hướng: Quay sang bên trái của hướng hiện tại
- switch (huong) {
- case 1:
- return 2;
- break;
- case 2:
- return 3;
- break;
- case 3:
- return 4;
- break;
- case 4:
- return 1;
- break;
- default:
- break;
- } //dóng switch
- }; // đóng đổi hướng
- void ve_xe_dich_main(byte i)
- {
- byte chon_huong_tank, phat_hien, x_tank, y_tank, huong_tank, ton_tai;
- byte buoc_tank;
- byte x_dan, y_dan, huong_dan, ton_tai_dan;
- //duyệt xe địch từ thứ 1 đến tank_dich_max trong mảng
- ton_tai = tank[i][0];
- if (ton_tai == 0) {
- // nếu xe thứ i không có, hoặc chết rồi thì cần tạo xe mới
- lcd.Number_Long(Xmin + i * ((Xmax - Xmin) / tank_dich_max), Ymin / 8, i, ASCII_NUMBER, BLACK);
- // viết 1 chữ số ra màn hình/ (Ymin/8) là dòng thứ ?
- ve_tank_dich(Xmin + i * ((Xmax - Xmin) / tank_dich_max), Ymin + 10, i % 4 + 1);
- // vẽ xe có tọa độ theo biển số xe
- //i%4+1, nếu i=4 hoặc i=8 suy ra i%4=0,
- //mà hướng 1,2,3,4, nên phải +1 để khác 0
- tank[i][1] = Xmin + i * ((Xmax - Xmin) / tank_dich_max); //ghi vào mảng hoành độ khởi đầu
- tank[i][2] = Ymin + 10; // ghi vào mảng tung độ khởi đầu
- tank[i][3] = (i % 4 + 1); //ghi vào mảng hướng ban đầu
- tank[i][4] = 0; // xe chưa đi 1 "bước" nào cả
- tank[i][0] = 1; // tích vào bảng, rằng đã tồn tại xe i
- }
- else { // xe i này vẫn sống
- //lấy thông tin của xe
- x_tank = tank[i][1];
- y_tank = tank[i][2];
- huong_tank = tank[i][3];
- buoc_tank = tank[i][4];
- phat_hien = kiem_tra_vat_can(x_tank, y_tank, huong_tank);
- // đổi hướng hay không
- if ((x_tank <= Xmin) || (x_tank >= Xmax) || (y_tank <= Ymin) || (y_tank >= Ymax) || (phat_hien == 1)) {
- // nếu ở trên biên hoặc có vật cản thì phải quay về hướng ngược lại
- tank[i][3] = doi_huong(huong_tank); // ghi vào mảng
- }
- //di chuyển
- huong_tank = tank[i][3]; // Rồi lại gán
- //sau đó nhích về phía trước 1 pixel
- nhich_ve_phia_truoc_dich(x_tank, y_tank, huong_tank, i);
- tank[i][4] = buoc_tank + 1; // nhích về phía trước thì phải cộng thêm 1 "bước"
- buoc_tank = tank[i][4]; //rồi lại gán, muốn dùng thì phải gán
- //CHuẩn bị bắn
- // QUY ƯỚC: xe tăng thứ i sẽ di chuyển i*5 bước rồi bắn 1 lần
- // VÀ
- //QUY ƯỚC: xe chỉ được bắn khi viên đạn của xe đó đã bị mất
- ton_tai_dan = tank[i][8];
- if ((buoc_tank >= (i * 5)) && (ton_tai_dan == 0)) { //kiểm tra thỏa mãn
- //nạp đạn
- tank[i][7] = huong_tank; // đặt hướng đạn là hướng hiện tại của xe
- tank[i][5] = x_tank + 2; // viên đạn nằm bên trong xe
- tank[i][6] = y_tank + 2; // viên đạn nằm bên trong xe
- tank[i][4] = 0; // đặt lại bước = 0 (mất 1 ngày để tìm ra lỗi này, hic ^^)s
- tank[i][8] = 1; // tích vào mảng rằng viên đạn của xe i đã tồn tại
- }
- //vẽ đạn
- // lại gán
- if (ton_tai_dan == 1) {
- x_dan = tank[i][5];
- y_dan = tank[i][6];
- huong_dan = tank[i][7];
- //rồi mới vẽ
- ve_dan(x_dan, y_dan, huong_dan, i);
- } //đóng vẽ đạn
- } //đóng else if đầu
- } // đóng vẽ xe địch main
- void ve_xe_ta_main()
- {
- /*
- // DI CHUYỂN XE TA------------------------------------------------------
- */
- byte huong_tank_ta, x_tank_ta, y_tank_ta; //tank của ta
- byte huong_tank_ta_button;
- huong_tank_ta_button = lcd.pullup_4(right_b, up_b, left_b, down_b); // đọc giá trị diều khiển
- //lấy thông tin của xe tank
- x_tank_ta = tank[0][1];
- y_tank_ta = tank[0][2];
- huong_tank_ta = tank[0][3];
- /*buoc_tank=tank[i][4];
- */
- if (huong_tank_ta_button != 0) { // có 1 nút được nhấn
- if (huong_tank_ta_button != huong_tank_ta) {
- // nếu hướng cũ của xe khác với giá trị nút nhấn
- //thì đặt lại hướng của xe là giá trị nút nhấn
- //thế mới gọi là điều khiển chứ !
- tank[0][3] = huong_tank_ta_button;
- // gán
- huong_tank_ta = tank[0][3];
- // rồi vẽ
- ve_tank_ta(x_tank_ta, y_tank_ta, huong_tank_ta);
- }
- else {
- // ngược lại, nút ấn có vai trò di chuyển xe
- // nếu xe trong biên và không có vật cản thì mới được phép đi
- nhich_ve_phia_truoc_ta(x_tank_ta, y_tank_ta, huong_tank_ta);
- } // đóng else if ngoài
- } //dóng if ngoài
- /*
- // TA BẮN ĐẠN-----------------------------------------------------
- */
- //đạn của ta
- byte huong_dan_ta, x_dan_ta, y_dan_ta, ton_tai_dan_ta;
- byte OK_BAN;
- //QUY ƯỚC: xe chỉ được bắn khi viên đạn của xe đã bị mất + NHẤN NÚT
- ton_tai_dan_ta = tank[0][8];
- OK_BAN = digitalRead(fight_b); // nút fight có được nhấn hay không
- if ((OK_BAN == 0) && (ton_tai_dan_ta == 0)) {
- //NÚT fight đã nhấn
- //lấy thông tin của xe tank
- x_tank_ta = tank[0][1];
- y_tank_ta = tank[0][2];
- huong_tank_ta = tank[0][3];
- //nạp đạn
- tank[0][7] = huong_tank_ta; // đặt hướng đạn là hướng hiện tại của xe
- tank[0][5] = x_tank_ta + 2; // viên đạn nằm bên trong xe
- tank[0][6] = y_tank_ta + 2; // viên đạn nằm bên trong xe
- // nạp đạn xong
- tank[0][8] = 1; // viên đạn đã tồn tại
- } // đóng if bắn
- //gán
- ton_tai_dan_ta = tank[0][8];
- //vẽ đạn
- if (ton_tai_dan_ta == 1) {
- //lấy thông tin
- x_dan_ta = tank[0][5];
- y_dan_ta = tank[0][6];
- huong_dan_ta = tank[0][7];
- //vẽ đạn
- ve_dan(x_dan_ta, y_dan_ta, huong_dan_ta, 0); // số "0" ở cuối là biển số của xe ta
- } // đóng if vẽ
- } //đóng vẽ xe ta main
- void bang_diem(byte i)
- {
- lcd.Asc_String(10, 2, Asc("Diem:"), BLACK);
- lcd.Number_Long(35, 2, diem, ASCII_NUMBER, BLACK);
- lcd.Asc_String(10, 12, Asc("Thu pham:T"), BLACK);
- lcd.Number_Long(75, 12, i, ASCII_NUMBER, BLACK);
- lcd.display();
- //Reset tank[1+tank_dich_max][10]
- for (byte xxx = 0; xxx <= tank_dich_max; xxx++) {
- for (byte yyy = 0; yyy <= 10; yyy++) {
- tank[xxx][yyy] = 0;
- }
- }
- // reset diem
- diem = 0;
- } // dong bang diem
- void lap_vo_han()
- {
- // dừng dòng chảy chính bằng vòng lặp vô hạn
- //thoát lặp khi nút Fight được nhấn
- int y = 55;
- lcd.Asc_String(10, y + 2, Asc("Fight!"), BLACK);
- lcd.display();
- while (digitalRead(fight_b) != 0) {
- lcd.rect(8, 55, 40, 10, BLACK);
- lcd.display();
- if (digitalRead(fight_b) == 0) {
- break; // thoát ngay
- }
- delay(250);
- lcd.rect(8, y, 40, 10, DELETE);
- lcd.display();
- if (digitalRead(fight_b) == 0) {
- break; // thoát ngay
- }
- delay(250);
- }
- } //đóng lặp vô hạn
- /*====================================================
- * ===================================================
- * ĐÓNG KHAI BÁO CÁC HÀM+CÀI ĐẶT
- * ===================================================
- * VÀO VÒNG LẶP CỦA DÒNG CHẢY CHÍNH
- * ===================================================
- * ===================================================
- */
- void loop()
- {
- //goi doi tuong la game
- //Bắt đầu game, vẽ xe ta----------------------------------------
- byte xe_ta_ton_tai;
- xe_ta_ton_tai = tank[0][0];
- if (xe_ta_ton_tai == 0) {
- ve_tank_ta(30, 55, 2); // tại 30-55, đang hướng lên phía trên
- ve_nen(); //vẽ nền game
- tank[0][1] = 30; //ghi vào mảng hoành độ khởi đầu
- tank[0][2] = 55; // ghi vào mảng tung độ khởi đầu
- tank[0][3] = 2; //ghi vào mảng hướng ban đầu
- tank[0][4] = 0; // xe chưa đi 1 "bước" nào cả !
- tank[0][0] = 1; // tích vào bảng, rằng đã tồn tại xe ta
- }
- /*
- //VẼ XE ĐỊCH----------------------------------------------------------
- */
- for (byte i = 1; i <= tank_dich_max; i++) {
- //duyệt xe địch từ thứ 1 đến tank_dich_max trong mảng
- ve_xe_dich_main(i);
- //rồi lặp cho đủ tank_dich_max xe
- } // đóng for
- /*
- //VẼ XE TA----------------------------------------------------------
- */
- ve_xe_ta_main();
- /*
- // Xóa ĐẠN ĐỊCH VÀ TA
- // NẾU ĐẠN VƯỢT BIÊN THÌ ĐẠN BỊ XÓA-----------------------
- */
- for (byte i = 0; i <= tank_dich_max; i++) {
- byte X_DAN, Y_DAN;
- X_DAN = tank[i][5];
- Y_DAN = tank[i][6];
- if ((X_DAN <= Xmin) || (X_DAN >= Xmax) || (Y_DAN <= Ymin) || (Y_DAN >= Ymax)) {
- tank[i][8] = 0; // xóa tồn tại đạn
- xoa_dan(X_DAN, Y_DAN);
- // xóa tọa độ đạn
- //không cần đâu, nó sẽ được ghi đè
- //và bảo vệ bởi hàm kiểm tra tồn tại
- // nếu quá 224 thì nó bị quay về 0 nếu ta tiếp tục tăng giá trị cho nó
- }
- } //đóng for xóa đạn
- /*
- //KIỂM TRA VA CHẠM-------------------------------------------
- */
- // xét (tank_dich_max) xe địch và 1 viên đạn của ta
- //-------------------------------------------------
- int hieu_x_dich, hieu_y_dich;
- for (byte i = 1; i <= tank_dich_max; i++) {
- hieu_x_dich = tank[0][5] - tank[i][1];
- hieu_y_dich = tank[0][6] - tank[i][2];
- // nếu tọa độ đạn ta trừ tọa độ xe địch mà dương và <=5 và đạn còn tồn tại
- // dính đạn
- if ((hieu_x_dich >= 0) && (hieu_x_dich <= 5) && (hieu_y_dich >= 0) && (hieu_y_dich <= 5) && (tank[0][8] == 1)) {
- // vẽ một vụ nổ tại tọa độ xe đó
- no(tank[i][1], tank[i][2]);
- // khai tử xe tăng đó
- tank[i][0] = 0;
- // khai tử viên đạn cửa ta
- tank[0][8] = 0;
- //cộng điểm người chơi đạt được khi giết tank i
- diem++;
- } // đóng if
- } // đóng for
- // xét ta và (tank_dich_max) viên đạn cửa địch
- //--------------------------------------------------
- for (byte i = 1; i <= tank_dich_max; i++) {
- int hieu_x_ta, hieu_y_ta;
- // nếu tọa độ đạn địch trừ tọa độ xe ta mà dương và <=5
- // dính đạn
- hieu_x_ta = tank[i][5] - tank[0][1];
- hieu_y_ta = tank[i][6] - tank[0][2];
- if ((hieu_x_ta >= 0) && (hieu_x_ta <= 5) && (hieu_y_ta >= 0) && (hieu_y_ta <= 5)) {
- // vẽ một vụ nổ tại tọa độ xe đó
- no(tank[0][1], tank[0][2]);
- delay(1000);
- lcd.clear();
- //THUA CUỘC
- // BẢNG ĐIỂM
- ///---------------------------------------------
- bang_diem(i);
- //LẶP CÓ ĐIỀU KIỆN
- //Nhấn nút fight để chơi tiếp
- lap_vo_han();
- //-------------------------------------------
- //thoát lặp
- lcd.clear();
- goto the_end; // nhảy cóc tới nhãn the end cuối trang
- //nếu không có lệnh này, for sẽ lặp lại cho đến max con chạy
- //và ta sẽ phải nhấn giữ khá lâu
- } // đóng if
- } //đóng for kiểm tra va trạm
- /*
- // KẾT THÚC HÀM
- // KẾT THÚC 2 NGÀY LÀM VIỆC CHĂM CHỈ!
- // kiểm tra mảng
- //___________________________
- //__________________________
- Serial.print("DIEM CUA BAN :");
- Serial.println(diem);
- int aaa,bbb;
- Serial.println("___________YES/NO______X TANK____Y TANK__HUONG ____BUOC____X DAN____Y DAN_____HUONG_____YES/NO");
- // XE TĂNG SỐ 0 LÀ CỦA BẠN
- // 1,2,3,4 LÀ ĐỊCH
- // YES/NO : CÒN SỐNG HAY ĐÃ CHẾT
- // X, Y TANK: TỌA ĐỘ XE TĂNG ĐÓ
- // HUONG: HƯỚNG CỦA MŨI XE ĐÓ CHỈ ĐI ĐÂU (1->4) (ĐÔNG, BẮC, TÂY, NAM)
- // BUOC; XE ĐÓ ĐÃ ĐI ĐƯỢC BAO NHIÊU BƯỚC (RIÊNG XE MÌNH THÌ KHÔNG CẦN)
- // X,Y DAN: TỌA ĐỌ VIÊN ĐẠN CỦA XE TĂNG ĐÓ
- // HƯỚNG VIÊN ĐẠN
- // YES/NO: VIÊN ĐẠN CÒN HAY MẤT
- for(aaa=0; aaa<tank_dich_max; aaa++){
- Serial.print("XE SO:");
- Serial.print(aaa);
- for(bbb=0; bbb<10; bbb++){
- Serial.print("________");
- Serial.print(tank[aaa][bbb]);
- }
- Serial.println("");
- }
- // */
- //Serial.println( getMemoryFree()); //KIỂM TRA RAM
- the_end:
- //Serial.println( getMemoryFree()); //KIỂM TRA RAM
- delay(delay_toc_do);
- } //đóng loop
- int getMemoryFree()
- {
- //HÀM NÀY TRẢ VỀ SỐ RAM CÒN DƯ TRÊN ARDUINO
- extern int __heap_start;
- extern int* __brkval;
- return (int)SP - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
- //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
- }
- //////////
- /////////
- /////////
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); } }