ST7565 | Làm game hứng trứng

Mô tả dự án: 

Xin chào các bạn, hôm nay mình sẽ viết bài về một project Game đầu tiên, một tựa game quen thuộc và đơn giản : Game hứng trứng.

Các bạn sẽ cực kì thích thú cho xem

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 up/down/right/left/ và fight/select.

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é:

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

Ý tưởng nhanh.

Trong game này, những quả trứng từ trên cao rơi xuống một cách ngẫu nhiên, người chơi điều khiển rỏ di chuyển qua trái qua phải, nếu hứng trúng một quả trứng người chơi sẽ được cộng thêm điểm, nếu để rơi, thì bị trừ điểm, trò chơi kết thúc khi số điểm bằng 0.

Nội dung chi tiết

Chiếc rổ được hai nhân vật Cả mẹo và Dần béo cầm chung, di chuyển trái phải nhờ điều khiển bằng nút bấm. Các quả trứng được tạo ra một cách radom với hoành độ và khoảng cách xuất hiện khác nhau.

Tạo một class Object cơ sở có chứa các thuộc tính về tọa độ, kích thước ảnh, sự tồn tại của trứng, biên, hướng.

Hàm set/get –ghi/đọc dữ liệu, hàm ve/xoa thực hiện vẽ và xóa ảnh bitmap

2 class egg và contruot (con trượt) kế thừa thuộc tính và phương thức từ Object.

B1: Test con trượt

Ảnh bitmap hai nhân vật cầm rổ: 

#include "ST7565_homephone.h"

#ifdef __AVR__
#include <avr/io.h>
#include <avr/pgmspace.h>
#endif

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
unsigned int timedelay;
/* Qủa trứng (7x7) pixel
*  */

const static unsigned char __attribute__((progmem)) trung_7x7[] = {
    0x1C, 0x22, 0x41, 0x41, 0x22, 0x1C,
};
/* Cả hai nhân vật 37x19
*
*/

const static unsigned char __attribute__((progmem)) ca_hai_37x19[] = {

    /* page 0 (lines 0-7) */
    0x80, 0x70, 0x88, 0x4, 0x4, 0x4, 0x98, 0xa4, 0xa4, 0x2c, 0x38, 0x20, 0xc0,
    0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x40, 0xb0, 0x50, 0x5c,
    0xa6, 0xa2, 0x5c, 0x44, 0x86, 0xf, 0xb2, 0x43, 0x80, 0x0,
    /* page 1 (lines 8-15) */
    0x1, 0x2, 0x5, 0x4, 0x8, 0x93, 0xfc, 0xf8, 0xf8, 0xf9, 0xf1, 0x31, 0x39,
    0x18, 0x3f, 0x43, 0xa5, 0x89, 0x91, 0xa5, 0x43, 0x3f, 0x18, 0x30, 0x70,
    0x64, 0x68, 0x68, 0xf8, 0x78, 0x78, 0xf7, 0xf0, 0xfa, 0xf4, 0xe3, 0xc0,
    /* page 2 (lines 16-23) */
    0x0, 0x0, 0x0, 0x0, 0x6, 0x5, 0x5, 0x5, 0x5, 0x1, 0x7, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x7,
    0x4, 0x0, 0x3, 0x7, 0x7, 0x7, 0x7,
};

/*LỚP CƠ SỎ-OBJECT)*/
class object {
 public:  // biến toàn cục
  byte Xmin = 0, Xmax = 127, Ymin = 0, Ymax = 63;  // biên
  byte x_ro = 60, y_ro = 40, width_ro = 30,
       high_ro = 10;  // tọa độ rỏ và kích thước rỏ
 public:
  // tập hàm ghi thông tin
  void set_ton_tai(boolean value) { ton_tai = value; }
  void set_x(byte value) { x = value; }
  void set_y(byte value) { y = value; }
  void set_huong(byte value) { huong = value; }
  // tập hàm lấy thông tin
  boolean get_ton_tai() { return ton_tai; }
  byte get_x() { return x; }
  byte get_y() { return y; }
  byte get_huong() { return huong; }

 private:
  // chỉ 2 tập hàm thành viên viên trên mới sử đụng được 4 tham số này:
  boolean ton_tai;
  byte x;
  byte y;
  byte huong;
};

void setup() {
  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);
  Serial.begin(9600);
  lcd.ON();
  lcd.SET(20, 0, 0, 0, 4);
  /*
  Serial.begin(9600);
  */
  // delay
  timedelay = 50;
  // tọa độ rỏ và kích thước rỏ mặc định để test
  // sẽ thay tọa độ rỏ là tọa độ con trượt ở phần sau
}

//=============================================
class contruot : public object {
 public:
  void xoa_con_truot(byte x, byte y) {
    // vẽ một hình chữ nhật màu trắng có kích thước bằng ảnh bitmap
    lcd.fillrect(x, y, 37, 19, DELETE);
    lcd.display();
  }
  void ve_con_truot(byte x, byte y) {
    // VẼ bitmap cho con trượt
    lcd.bitmap(x, y, 37, 19, ca_hai_37x19, BLACK);
    lcd.display();
  }
  contruot() {
    // hàm tạo constructer

    // đặt x, y, con trượt một giá trị cho trước
    set_x((Xmax - Xmin) / 2);
    set_y(Ymax - 18);
  }
  void di_con_truot() {
    // lấy thông tin
    byte x_moi, x_cu, y_cu;  // mới và cũ

    x_cu = get_x();
    y_cu = get_y();
    // vẽ
    ve_con_truot(x_cu, y_cu);
    //đọc giá trị 4 button
    if (lcd.pullup_4(right_b, up_b, left_b, down_b) == 1) {  // nút right

      xoa_con_truot(x_cu, y_cu);  // xóa ảnh cũ trên màn hình

      if (x_cu <= (Xmax - 10)) {  // trong biên
        x_moi = x_cu + 5;  // cộng hoành độ lên 5 đơn vị
      } else {
        x_moi = x_cu;
      }
      // vẽ ảnh con trượt
      ve_con_truot(x_moi, y_cu);
      set_x(x_moi);  // ghi lại thông tin hoành độ
    }

    if (lcd.pullup_4(right_b, up_b, left_b, down_b) == 3) {  // nút left

      xoa_con_truot(x_cu, y_cu);  // xóa ảnh cũ trên màn hình
      if (x_cu >= (Xmin + 10)) {  // trong biên
        x_moi = x_cu - 5;  // trừ hoành độ xuống 5 đơn vị
      } else {
        x_moi = x_cu;
      }
      // vẽ ảnh con trượt

      ve_con_truot(x_moi, y_cu);
      set_x(x_moi);  // ghi lại thông tin hoành độ
    }

  }  // di chuyển con chạy
};  // class
contruot Dan_va_Ca;  // tạo 1 con trượt là Dần và Cả= constructor
void loop() {
  // bước 1:

  Dan_va_Ca.di_con_truot();
  Serial.print(Dan_va_Ca.get_x());
  Serial.println(Dan_va_Ca.get_y());
  delay(50);
}

 

B2: Tạo trứng random

#include "ST7565_homephone.h"
#ifdef __AVR__
#include <avr/io.h>
#include <avr/pgmspace.h>
#endif

ST7565 lcd(3, 4, 5, 6);

unsigned int timedelay;
/* Qủa trứng (7x7) pixel
 *  */

const static unsigned char __attribute__((progmem)) trung_7x7[] = {
    0x1C, 0x22, 0x41, 0x41, 0x22, 0x1C,
};
/*LỚP CƠ SỎ-OBJECT)*/
class object {
 public:  // biến toàn cục
  byte Xmin = 0, Xmax = 127, Ymin = 0, Ymax = 63;  // biên
  byte x_ro = 60, y_ro = 40, width_ro = 30,
       high_ro = 10;  // tọa độ rỏ và kích thước rỏ
  // tọa độ rỏ và kích thước rỏ mặc định để test
  // sẽ thay tọa độ rỏ là tọa độ con trượt ở phần sau
 public:
  // tập hàm ghi thông tin
  void set_ton_tai(byte value) { ton_tai = value; }
  void set_x(byte value) { x = value; }
  void set_y(byte value) { y = value; }
  void set_huong(byte value) { huong = value; }

  // tập hàm lấy thông tin
  boolean get_ton_tai() { return ton_tai; }
  byte get_x() { return x; }
  byte get_y() { return y; }
  byte get_huong() { return huong; }

 private:
  // chỉ 2 tập hàm trên mới sử đụng được 4 tham số này
  boolean ton_tai;
  byte x;
  byte y;
  byte huong;
};
class egg : public object {
 public:
  egg() {
    // gán các thuộc tính khi tạo mới 1 quả trứng
    unsigned int seed;
    seed = millis();
    randomSeed(seed % 100);
    // tạo sinh số randomSeed bằng đồng hồ hệ thống
    byte x;
    byte y;
    x = random(Xmin + 10, Xmax - 10);
    y = random(Ymin + 1, Ymin + 15);
    // lưu thông tin vào
    set_x(x);
    set_y(y);
    // vẽ
    ve_trung(x, y);
  }
  void ve_trung(byte x, byte y) {
    // vẽ trứng
    lcd.bitmap(x, y, 7, 7, trung_7x7, BLACK);
    lcd.display();
  }

  void xoa_trung(byte x, byte y) {
    // xóa trứng bằng 1 hình chữ nhật màu trắng kích thước bằng quả trứng
    lcd.fillrect(x, y, 7, 7, DELETE);
    lcd.display();
  }
};
void setup() {
  Serial.begin(9600);
  lcd.ON();
  lcd.SET(20, 0, 0, 0, 4);
  /*
   Serial.begin(9600);
   */
  timedelay = 500;
  lcd.clear();
}
egg qua_trung[3];  // chúng ta cần tạo mới 3 quả trứng
// khi vừa tạo mới thì nó đã mang 2 thuộc tính x, y
void loop() {
  // delay
  for (byte i = 0; i < 3; i++) {  // duyệt 0,1,2
    Serial.print("(");
    Serial.print(qua_trung[i].get_x());
    Serial.print(",");
    Serial.print(qua_trung[i].get_y());
    Serial.print(")");
  }
  Serial.println("");
  delay(timedelay);
  lcd.clear();
}

B3: Xử lý trứng

#include "ST7565_homephone.h"
#ifdef __AVR__
#include <avr/io.h>
#include <avr/pgmspace.h>
#endif
ST7565 lcd(3, 4, 5, 6);
unsigned int timedelay;
/* Qủa trứng (7x7) pixel
 *  */
const static unsigned char __attribute__((progmem)) trung_7x7[] = {
    0x1C, 0x22, 0x41, 0x41, 0x22, 0x1C,
};
/*LỚP CƠ SỎ-OBJECT)*/
class object {
 public:  // biến toàn cục
  byte Xmin = 0, Xmax = 127, Ymin = 0, Ymax = 63;  // biên
  byte x_ro = 60, y_ro = 40, width_ro = 30,
       high_ro = 10;  // tọa độ rỏ và kích thước rỏ
  // tọa độ rỏ và kích thước rỏ mặc định để test
  // sẽ thay tọa độ rỏ là tọa độ con trượt ở phần sau
 public:
  // tập hàm ghi thông tin
  void set_ton_tai(boolean value) { ton_tai = value; }
  void set_x(byte value) { x = value; }
  void set_y(byte value) { y = value; }
  void set_huong(byte value) { huong = value; }
  // tập hàm lấy thông tin
  boolean get_ton_tai() { return ton_tai; }
  byte get_x() { return x; }
  byte get_y() { return y; }
  byte get_huong() { return huong; }
 private:
  // chỉ 2 tập hàm trên mới sử đụng được 4 tham số này
  boolean ton_tai;
  byte x;
  byte y;
  byte huong;
};
class egg : public object {
 public:
  void tao_trung() {
    // dành cho (1) , cái mà nó được gọi
    // gán các thuộc tính khi tạo mới 1 quả trứng
    unsigned int seed;
    seed = millis();
    randomSeed(seed % 100);
    // tạo sinh số randomSeed bằng đồng hồ hệ thống
    byte x;
    byte y;
    x = random(Xmin + 20, Xmax - 10);
    y = random(Ymin + 1, Ymin + 15);
    // lưu thông tin vào
    set_x(x);
    set_y(y);
    set_ton_tai(1);
    // vẽ
    ve_trung(x, y);
  }
  void ve_trung(byte x, byte y) {
    // vẽ trứng
    lcd.bitmap(x, y, 7, 7, trung_7x7, BLACK);
    lcd.display();
  }
  void xoa_trung(byte x, byte y) {
    // xóa trứng bằng 1 hình chữ nhật màu trắng kích thước bằng quả trứng
    lcd.fillrect(x, y, 7, 7, DELETE);
    lcd.display();
  }
  void di_chuyen_trung() {  // di chuyển trứng RƠI
    byte x_cu, y_cu, y_moi;  // giá trị cũ và mới
    if (get_ton_tai() == 1) {
      // nếu trứng đó tồn tại thì cho phép tiếp tục
      // lấy thông tin
      x_cu = get_x();
      y_cu = get_y();
      // xóa vị trí cũ
      xoa_trung(x_cu, y_cu);
      y_moi = y_cu + 2;  // di xuống
      // vẽ
      ve_trung(x_cu, y_moi);
      // lưu lại tt
      set_x(x_cu);
      set_y(y_moi);
    }  // if
  }
  boolean kiem_tra(byte x, byte y) {  // x,y tọa độ rỏ
    // kiểm tra xem quả trứng có rơi vào rỏ hay không
    // nếu hiệu tọa độ của trứng với rỏ mà DƯƠNG và NHỎ HƠN hoặc BẰNG kích..
    //..thước rỏ,thì trứng đã rơi vào trong rỏ
    //( trứng phải ở giữa rỏ)
    // do tọa độ của 2 vật này thuộc kiểu biến nguyên dương byte
    // do đó cần kiểu nguyên có phần âm (int ) để lưu hiệu
    int hieu_x, hieu_y;
    // hoành độ trứng trừ hoành độ rỏ
    hieu_x = (get_x() + 7) - x;  // cộng 7 vì:trứng phải ở giữa rỏ)
    hieu_y = get_y() - y;
    if ((hieu_x <= (width_ro)) && (hieu_x >= 0) && (hieu_y <= high_ro) &&
        (hieu_y >= 0)) {
      // thỏa mãn điều kiện
      return 1;  // trả về giá trị true
    } else {
      return 0;  // trả về giá trị false
    }
  }  // kiểm tra
  void xu_li_ve_trung(byte x, byte y) {  // x, y là tọa độ rỏ
    // bước 2:
    if (get_ton_tai() == 0) {
      // nếu quả trứng không tồn tại
      // thì phải tạo mới
      tao_trung();
    } else
        if (get_ton_tai() == 1) {  // trứng tồn tại
      if (kiem_tra(x, y) == 1) {  // nếu trứng vào rỏ
        // b1: xóa tồn tại quả trứng đó di
        set_ton_tai(0);
        // b2: cộng điểm
      }
      if (get_y() >= Ymax) {  // nếu trứng quá biên,(chạm đất, vỡ)
        // b1: xóa tồn tại quả trứng đó đi
        set_ton_tai(0);
      }
    }
    di_chuyen_trung();
  }
};
//=============================================
void setup() {
  Serial.begin(9600);
  lcd.ON();
  lcd.SET(20, 0, 0, 0, 4);
  /*
   Serial.begin(9600);
   */
  // delay
  timedelay = 50;
  // tọa độ rỏ và kích thước rỏ mặc định để test
  // sẽ thay tọa độ rỏ là tọa độ con trượt ở phần sau
}
// bước 1:
egg qua_trung[4];  // chúng ta cần tạo 4 quả trứng
object btc;  // biến toàn cục
void loop() {
  // khi vừa tạo mới thì nó đã mang 2 thuộc tính x, y
  for (byte i = 0; i < 4; i++) {  // duyệt 4 quả  0,1,2,3
    qua_trung[i].xu_li_ve_trung(btc.x_ro, btc.y_ro);
  }
  delay(200);
}

B4: Hoàn thiện

#include "ST7565_homephone.h"
#ifdef __AVR__
#include <avr/io.h>
#include <avr/pgmspace.h>
#endif
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
//
unsigned int timedelay;
/* Qủa trứng (7x7) pixel
 *  */
const static unsigned char __attribute__((progmem)) trung_7x7[] = {
    0x1C, 0x22, 0x41, 0x41, 0x22, 0x1C,
};
/* Cả hai nhân vật 37x19
 *
 */
const static unsigned char __attribute__((progmem)) ca_hai_37x19[] = {
    /* page 0 (lines 0-7) */
    0x80, 0x70, 0x88, 0x4, 0x4, 0x4, 0x98, 0xa4, 0xa4, 0x2c, 0x38, 0x20, 0xc0,
    0x0, 0x80, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x40, 0xb0, 0x50, 0x5c, 0xa6, 0xa2,
    0x5c, 0x44, 0x86,
    0xf, 0xb2, 0x43, 0x80, 0x0,
    /* page 1 (lines 8-15) */
    0x1, 0x2, 0x5, 0x4, 0x8, 0x93, 0xfc, 0xf8, 0xf8, 0xf9, 0xf1, 0x31, 0x39,
    0x18, 0x3f, 0x43,
    0xa5, 0x89, 0x91, 0xa5, 0x43, 0x3f, 0x18, 0x30, 0x70, 0x64, 0x68, 0x68,
    0xf8, 0x78, 0x78, 0xf7,
    0xf0, 0xfa, 0xf4, 0xe3, 0xc0,
    /* page 2 (lines 16-23) */
    0x0, 0x0, 0x0, 0x0, 0x6, 0x5, 0x5, 0x5, 0x5, 0x1, 0x7, 0x0, 0x0, 0x0, 0x0,
    0x0,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x7, 0x4,
    0x0,
    0x3, 0x7, 0x7, 0x7, 0x7,
};
void setup() {
  pinMode(select_b, INPUT_PULLUP);
  pinMode(down_b, INPUT_PULLUP);
  pinMode(up_b, INPUT_PULLUP);
  pinMode(left_b, INPUT_PULLUP);
  pinMode(right_b, INPUT_PULLUP);
  pinMode(fight_b, INPUT_PULLUP);
  lcd.ON();
  lcd.SET(23, 0, 0, 0, 4);
  /*
   Serial.begin(9600);
   */
  // delay
  timedelay = 20;
}
/*LỚP CƠ SỎ-OBJECT)*/
class object {
 public:  // biến toàn cục
  static int diem_ban_dau;
  static int diem;
  static int diem_cao;
  // static được hiểu nôm na là duy nhất cho dù có bao nhiêu đối tượng tạo ra..
  // khai báo static bên ngoài lớp
  byte Xmin = 0, Xmax = 127, Ymin = 0, Ymax = 63;  // biên
  byte width_ro = 12, high_ro = 10;  // tọa độ rỏ và kích thước rỏ
  // tập hàm ghi thông
  void set_ton_tai(boolean value) { ton_tai = value; }
  void set_x(byte value) { x = value; }
  void set_y(byte value) { y = value; }
  void set_huong(byte value) { huong = value; }
  // tập hàm lấy thông tin
  int get_diem_cao() { return diem_cao; }
  boolean get_ton_tai() { return ton_tai; }
  byte get_x() { return x; }
  byte get_y() { return y; }
  byte get_huong() { return huong; }
 private:
  // chỉ 2 tập hàm thành viên viên trên mới sử đụng được 4 tham số này:
  boolean ton_tai;
  byte x;
  byte y;
  byte huong;
};
int object::diem_ban_dau = 5;
int object::diem = diem_ban_dau;
int object::diem_cao = diem;
//=============================================
class contruot : public object {
 public:
  void xoa_con_truot(byte x, byte y) {
    // vẽ một hình chữ nhật màu trắng có kích thước bằng ảnh bitmap
    lcd.fillrect(x, y, 37, 19, DELETE);
    lcd.display();
  }
  void ve_con_truot(byte x, byte y) {
    // VẼ bitmap cho con trượt
    lcd.bitmap(x, y, 37, 19, ca_hai_37x19, BLACK);
    lcd.display();
  }
  contruot() {
    // hàm tạo constructer
    // đặt x, y, con trượt một giá trị cho trước
    set_x((Xmax - Xmin) / 2);
    set_y(Ymax - 18);
  }
  void di_con_truot() {
    // lấy thông tin
    byte x_moi, x_cu, y_cu;  // mới và cũ
    x_cu = get_x();
    y_cu = get_y();
    // vẽ
    ve_con_truot(x_cu, y_cu);
    //đọc giá trị 4 button
    if (lcd.pullup_4(right_b, up_b, left_b, down_b) == 1) {  // nút right
      xoa_con_truot(x_cu, y_cu);  // xóa ảnh cũ trên màn hình
      if (x_cu <= (Xmax - 10)) {  // trong biên
        x_moi = x_cu + 5;  // cộng hoành độ lên 5 đơn vị
      } else {
        x_moi = x_cu;
      }
      // vẽ ảnh con trượt
      ve_con_truot(x_moi, y_cu);
      set_x(x_moi);  // ghi lại thông tin hoành độ
    }
    if (lcd.pullup_4(right_b, up_b, left_b, down_b) == 3) {  // nút left
      xoa_con_truot(x_cu, y_cu);  // xóa ảnh cũ trên màn hình
      if (x_cu >= (Xmin + 10)) {  // trong biên
        x_moi = x_cu - 5;  // trừ hoành độ xuống 5 đơn vị
      } else {
        x_moi = x_cu;
      }
      // vẽ ảnh con trượt
      ve_con_truot(x_moi, y_cu);
      set_x(x_moi);  // ghi lại thông tin hoành độ
    }
  }  // di chuyển con chạy
};  // class
//===========================================================
class egg : public object {
 public:
  void tao_trung() {
    // dành cho (1) , cái mà nó được gọi
    // gán các thuộc tính khi tạo mới 1 quả trứng
    unsigned int seed;
    seed = millis();
    randomSeed(seed % 100);
    // tạo sinh số randomSeed bằng đồng hồ hệ thống
    byte x;
    byte y;
    x = random(Xmin + 20, Xmax - 10);
    y = random(Ymin + 1, Ymin + 15);
    // lưu thông tin vào
    set_x(x);
    set_y(y);
    set_ton_tai(1);
    // vẽ
    ve_trung(x, y);
  }
  void ve_trung(byte x, byte y) {
    // vẽ trứng
    lcd.bitmap(x, y, 7, 7, trung_7x7, BLACK);
    lcd.display();
  }
  void xoa_trung(byte x, byte y) {
    // xóa trứng bằng 1 hình chữ nhật màu trắng kích thước bằng quả trứng
    lcd.fillrect(x, y, 7, 7, DELETE);
    lcd.display();
  }
  void di_chuyen_trung() {  // di chuyển trứng RƠI
    byte x_cu, y_cu, y_moi;  // giá trị cũ và mới
    if (get_ton_tai() == 1) {
      // nếu trứng đó tồn tại thì cho phép tiếp tục
      // lấy thông tin
      x_cu = get_x();
      y_cu = get_y();
      // xóa vị trí cũ
      xoa_trung(x_cu, y_cu);
      y_moi = y_cu + 2;  // di xuống
      // vẽ
      ve_trung(x_cu, y_moi);
      // lưu lại tt
      set_x(x_cu);
      set_y(y_moi);
    }  // if
  }
  boolean kiem_tra(byte x, byte y) {  // x,y tọa độ rỏ
    // kiểm tra xem quả trứng có rơi vào rỏ hay không
    // nếu hiệu tọa độ của trứng với rỏ mà DƯƠNG và NHỎ HƠN hoặc BẰNG kích..
    //..thước rỏ,thì trứng đã rơi vào trong rỏ
    //( trứng phải ở giữa rỏ)
    // do tọa độ của 2 vật này thuộc kiểu biến nguyên dương byte
    // do đó cần kiểu nguyên có phần âm (int ) để lưu hiệu
    int hieu_x, hieu_y;
    // hoành độ trứng trừ hoành độ rỏ
    hieu_x = (get_x() + 7) - x;  // cộng 7 vì:trứng phải ở giữa rỏ)
    hieu_y = get_y() - y;
    if ((hieu_x <= (width_ro)) && (hieu_x >= 0) && (hieu_y <= high_ro) &&
        (hieu_y >= 0)) {
      // thỏa mãn điều kiện
      return 1;  // trả về giá trị true
    } else {
      return 0;  // trả về giá trị false
    }
  }  // kiểm tra
  void xu_li_ve_trung(byte x, byte y) {  // x, y là tọa độ rỏ
    // bước 2:
    if (get_ton_tai() == 0) {
      // nếu quả trứng không tồn tại
      // thì phải tạo mới
      tao_trung();
    } else
        if (get_ton_tai() == 1) {  // trứng tồn tại
      if (kiem_tra(x, y) == 1) {  // nếu trứng vào rỏ
        // xóa tồn tại quả trứng đó di
        set_ton_tai(0);
        diem++;
      }
      if (get_y() >= Ymax) {  // nếu trứng quá biên,(chạm đất, vỡ)
        // xóa tồn tại quả trứng đó đi
        set_ton_tai(0);
        diem--;
      }
    }
    di_chuyen_trung();
  }
};
//====================================================
class computer : public object {
 public:
  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
    lcd.asc_string(10, 54, asc("Fight!"), BLACK);
    while (digitalRead(fight_b) != 0) {
      lcd.rect(8, 53, 40, 10, BLACK);
      lcd.display();
      if (digitalRead(fight_b) == 0) {
        break;  // thoát ngay
      }
      delay(250);
      lcd.rect(8, 53, 40, 10, DELETE);
      lcd.display();
      if (digitalRead(fight_b) == 0) {
        break;  // thoát ngay
      }
      delay(250);
    }
  }  //đóng lặp vô hạn
  void in_diem() {
    if (diem >= diem_cao) {
      diem_cao = diem;
    }
    if (diem <= 0) {
      reset();
    }  // thua cuộc
    lcd.fillrect(Xmin + 5, Ymin, Xmax - Xmin, 8, DELETE);  // xóa ảnh cũ
    lcd.number_long(Xmin + 5, 0, diem, ASCII_NUMBER, BLACK);
    lcd.number_long(Xmax - 15, 0, diem_cao, ASCII_NUMBER, BLACK);
    lcd.display();
  }
  //=============================================
  void reset() {
    diem = diem_ban_dau;  // đặt lại điểm ban dau
    lap_vo_han();  // chờ nhấn nút fight
    lcd.clear();  // làm sạch màn hình
  }
};  // class
//====================================================
contruot Dan_va_Ca;  // tạo 1 con trượt là Dần và Cả= constructor
egg qua_trung[4];  // chúng ta cần tạo 4 quả trứng
computer c;
void loop() {
  byte x_ro, y_ro;
  // lấy tọa độ rổ-rổ là con trượt
  Dan_va_Ca.di_con_truot();
  x_ro =
      Dan_va_Ca.get_x() + 13;  // cộng 13 vì rổ cách gốc tọa độ bitmap từng đó
  y_ro =
      (Dan_va_Ca.get_y() + 5);  // cộng 5 vì rổ cách gốc tọa độ bitmap từng đó
  c.in_diem();  // in điểm
  for (byte i = 0; i < 4; i++) {  // duyệt 4 quả  0,1,2,3
    qua_trung[i].xu_li_ve_trung(x_ro, y_ro);
  }
  // nhấn fight để tăng tốc
  if (digitalRead(fight_b) == 1) {  // ko nhấn
    delay(timedelay);
  } else {
    delay(timedelay / 5);
  }
}

 

Tạm kết

Vì tất cả code được đặt trong một file duy nhất nên nó hơi dài  nhỉ frown. Code này mình nghĩ sao thì viết đó, miễn nó chạy là mình đã cảm thấy ok rồi, còn tối ưu hóa thì tạm nghỉ. Mời pà con Copy về chơi thử.

Tăng tốc game: nhấn nút FIGHT.

Thua cuộc nhấn FIGHT để chơi tiếp nhé.

Vẫn còn nhiều cái hay lắm, hãy đón đọc nhélaughcheeky...Hi vọng bạn thấy thích bài viết này. yesheart

Hẹn gặp mọi người ở bài tiếp theo.

Tác giả:  Thái Sơn.

 

lên
7 thành viên đã đánh giá bài viết này hữu ích.
Các dự án được truyền cảm hứng

Bộ điều khiển PID - ứng dụng phần 2 - xe dò line dùng thuật toán PID

Tiép nối bài viết về xe dò line cảm ơn Đỗ Hữu Toàn đã viết hộ mình phần 4. hôm nay mình sẽ làm cho chiếc xe dò line đi mượt và có hồn hơn 

lên
34 thành viên đã đánh giá bài viết này hữu ích.
Các bài viết cùng tác giả

GAME-ST7565 - Làm game đua xe RACING CAR 3D với arduino

OK,  hôm nay mình sẽ giới thiệu Game “3D Racing Car” – Đua xe 3D. Một trong những Game khá phức tạp mà mình từng viết trên Arduino với lcd ST7565.

lên
11 thành viên đã đánh giá bài viết này hữu ích.

GAME-ST7565 - Làm Game xe tăng với 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.

lên
4 thành viên đã đánh giá bài viết này hữu ích.