Nick Chung gửi vào
- 12221 lượt xem
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 .
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.
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é:
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 } ////////// ///////// /////////
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); } }
Tạm kết
Đây là file zip Game:
https://drive.google.com/file/d/0BzMEcyRK_uUFNFY0YzRSb1hyT0U/view?usp=sharing (mirror)
Hehe, làm Game vui phết các bạn ạ, chúc các bạn học C/C++ vui vẻ.