Arduino製作俄羅斯方塊小遊戲(三)程序源碼


#include <avr/pgmspace.h>
#include <Wire.h>

#define u8 unsigned char

// 1. LCD顯示屏的接口定義
#define PIN_LCD_SDI 6
#define PIN_LCD_SCK 8
#define PIN_LCD_DCX  18
#define PIN_LCD_RST 13
#define PIN_LCD_CS  1
#define LCD_X_MAX 160-1
#define LCD_Y_MAX 80-1
u8 AllTetris[15][30] = { 0 };
char Position_x[7][4][4] =
{
  { {-1, 0, 1, 2}, {0, 0, 0, 0}, {-1, 0, 1, 2}, {0, 0, 0, 0} },
  { {0, 0, 0, 1}, {0, 1, 2, 0}, {-1, 0, 0, 0}, {-1, 0, 1, 1} },
  { {0, 0, 0, -1}, {-1, -1, 0, 1}, {0, 1, 0, 0}, {-1, 0, 1, 1} },
  { {0, 0, 1, 0}, {0, -1, 0, 1}, {0, -1, 0, 0}, {-1, 0, 1, 0} },
  { {-1, 0, 0, 1}, {1, 0, 1, 0}, {-1, 0, 0, 1}, {1, 0, 1, 0} },
  { {0, 1, -1, 0}, {0, 0, 1, 1}, {0, 1, -1, 0}, {0, 0, 1, 1} },
  { {0, 1, 0, 1}, {0, 1, 0, 1}, {0, 1, 0, 1}, {0, 1, 0, 1} }

};

char Position_y[7][4][4] =
{
  { {0, 0, 0, 0}, {1, 0, -1, -2}, {0, 0, 0, 0}, {1, 0, -1, -2} },
  { {1, 0, -1, -1}, {0, 0, 0, -1}, {1, 1, 0, -1}, {0, 0, 0, 1} },
  { {1, 0, -1, -1}, {1, 0, 0, 0}, {1, 1, 0, -1}, {0, 0, 0, -1} },
  { {1, 0, 0, -1}, {1, 0, 0, 0}, {1, 0, 0, -1}, {0, 0, 0, -1} },
  { {1, 1, 0, 0}, {1, 0, 0, -1}, {1, 1, 0, 0}, {1, 0, 0, -1} },
  { {1, 1, 0, 0}, {1, 0, 0, -1}, {1, 1, 0, 0}, {1, 0, 0, -1} },
  { {1, 1, 0, 0}, {1, 1, 0, 0}, {1, 1, 0, 0}, {1, 1, 0, 0} }
};

u8 Now_Form, Now_Shape;
u8 Now_x, Now_y;
u8 Next_Form, Next_Shape;
u8 LOSE = 0;
u8 rate = 1;
int Score = 0;
char lcd_buf[20];

/*以下均爲LCD示例裏的函數*/
/*****************************************/
PROGMEM prog_uchar font8x12[][12] = {
  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, //  
  {0x00,0x30,0x78,0x78,0x78,0x30,0x30,0x00,0x30,0x30,0x00,0x00}, // !
  {0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // "
  {0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00}, // #
  {0x30,0x30,0x7C,0xC0,0xC0,0x78,0x0C,0x0C,0xF8,0x30,0x30,0x00}, // $
  {0x00,0x00,0x00,0xC4,0xCC,0x18,0x30,0x60,0xCC,0x8C,0x00,0x00}, // %
  {0x00,0x70,0xD8,0xD8,0x70,0xFA,0xDE,0xCC,0xDC,0x76,0x00,0x00}, // &
  {0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '
  {0x00,0x0C,0x18,0x30,0x60,0x60,0x60,0x30,0x18,0x0C,0x00,0x00}, // (
  {0x00,0x60,0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x60,0x00,0x00}, // )
  {0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00}, // *
  {0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00}, // +
  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0x60,0x00}, // ,
  {0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00}, // -
  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0x00,0x00}, // .
  {0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00}, // /
  {0x00,0x7C,0xC6,0xD6,0xD6,0xD6,0xD6,0xD6,0xC6,0x7C,0x00,0x00}, // 0
  {0x00,0x10,0x30,0xF0,0x30,0x30,0x30,0x30,0x30,0xFC,0x00,0x00}, // 1
  {0x00,0x78,0xCC,0xCC,0x0C,0x18,0x30,0x60,0xCC,0xFC,0x00,0x00}, // 2
  {0x00,0x78,0xCC,0x0C,0x0C,0x38,0x0C,0x0C,0xCC,0x78,0x00,0x00}, // 3
  {0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x1E,0x00,0x00}, // 4
  {0x00,0xFC,0xC0,0xC0,0xC0,0xF8,0x0C,0x0C,0xCC,0x78,0x00,0x00}, // 5
  {0x00,0x38,0x60,0xC0,0xC0,0xF8,0xCC,0xCC,0xCC,0x78,0x00,0x00}, // 6
  {0x00,0xFE,0xC6,0xC6,0x06,0x0C,0x18,0x30,0x30,0x30,0x00,0x00}, // 7
  {0x00,0x78,0xCC,0xCC,0xEC,0x78,0xDC,0xCC,0xCC,0x78,0x00,0x00}, // 8
  {0x00,0x78,0xCC,0xCC,0xCC,0x7C,0x18,0x18,0x30,0x70,0x00,0x00}, // 9
  {0x00,0x00,0x00,0x38,0x38,0x00,0x00,0x38,0x38,0x00,0x00,0x00}, // :
  {0x00,0x00,0x00,0x38,0x38,0x00,0x00,0x38,0x38,0x18,0x30,0x00}, // ;
  {0x00,0x0C,0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x0C,0x00,0x00}, // <
  {0x00,0x00,0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00}, // =
  {0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00}, // >
  {0x00,0x78,0xCC,0x0C,0x18,0x30,0x30,0x00,0x30,0x30,0x00,0x00}, // ?
  {0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xC0,0xC0,0x7C,0x00,0x00}, // @
  {0x00,0x30,0x78,0xCC,0xCC,0xCC,0xFC,0xCC,0xCC,0xCC,0x00,0x00}, // A
  {0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0xFC,0x00,0x00}, // B
  {0x00,0x3C,0x66,0xC6,0xC0,0xC0,0xC0,0xC6,0x66,0x3C,0x00,0x00}, // C
  {0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00}, // D
  {0x00,0xFE,0x62,0x60,0x64,0x7C,0x64,0x60,0x62,0xFE,0x00,0x00}, // E
  {0x00,0xFE,0x66,0x62,0x64,0x7C,0x64,0x60,0x60,0xF0,0x00,0x00}, // F
  {0x00,0x3C,0x66,0xC6,0xC0,0xC0,0xCE,0xC6,0x66,0x3E,0x00,0x00}, // G
  {0x00,0xCC,0xCC,0xCC,0xCC,0xFC,0xCC,0xCC,0xCC,0xCC,0x00,0x00}, // H
  {0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00}, // I
  {0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00}, // J
  {0x00,0xE6,0x66,0x6C,0x6C,0x78,0x6C,0x6C,0x66,0xE6,0x00,0x00}, // K
  {0x00,0xF0,0x60,0x60,0x60,0x60,0x62,0x66,0x66,0xFE,0x00,0x00}, // L
  {0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0x00,0x00}, // M
  {0x00,0xC6,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0x00,0x00}, // N
  {0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00}, // O
  {0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0xF0,0x00,0x00}, // P
  {0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xCE,0xDE,0x7C,0x0C,0x1E,0x00}, // Q
  {0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0xE6,0x00,0x00}, // R
  {0x00,0x78,0xCC,0xCC,0xC0,0x70,0x18,0xCC,0xCC,0x78,0x00,0x00}, // S
  {0x00,0xFC,0xB4,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00}, // T
  {0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00}, // U
  {0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x00,0x00}, // V
  {0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0x6C,0x6C,0x6C,0x00,0x00}, // W
  {0x00,0xCC,0xCC,0xCC,0x78,0x30,0x78,0xCC,0xCC,0xCC,0x00,0x00}, // X
  {0x00,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x30,0x30,0x78,0x00,0x00}, // Y
  {0x00,0xFE,0xCE,0x98,0x18,0x30,0x60,0x62,0xC6,0xFE,0x00,0x00}, // Z
  {0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00}, // [
  {0x00,0x00,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,0x00}, /* \*/
  {0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00}, // ]
  {0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ^
  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00}, // _
  {0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // `
  {0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0x76,0x00,0x00}, // a
  {0x00,0xE0,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0xDC,0x00,0x00}, // b
  {0x00,0x00,0x00,0x00,0x78,0xCC,0xC0,0xC0,0xCC,0x78,0x00,0x00}, // c
  {0x00,0x1C,0x0C,0x0C,0x7C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00}, // d
  {0x00,0x00,0x00,0x00,0x78,0xCC,0xFC,0xC0,0xCC,0x78,0x00,0x00}, // e
  {0x00,0x38,0x6C,0x60,0x60,0xF8,0x60,0x60,0x60,0xF0,0x00,0x00}, // f
  {0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78}, // g
  {0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0xE6,0x00,0x00}, // h
  {0x00,0x18,0x18,0x00,0x78,0x18,0x18,0x18,0x18,0x7E,0x00,0x00}, // i
  {0x00,0x0C,0x0C,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0x78}, // j
  {0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0xE6,0x00,0x00}, // k
  {0x00,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00}, // l
  {0x00,0x00,0x00,0x00,0xFC,0xD6,0xD6,0xD6,0xD6,0xC6,0x00,0x00}, // m
  {0x00,0x00,0x00,0x00,0xF8,0xCC,0xCC,0xCC,0xCC,0xCC,0x00,0x00}, // n
  {0x00,0x00,0x00,0x00,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00}, // o
  {0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x7C,0x60,0xF0}, // p
  {0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x1E}, // q
  {0x00,0x00,0x00,0x00,0xEC,0x6E,0x76,0x60,0x60,0xF0,0x00,0x00}, // r
  {0x00,0x00,0x00,0x00,0x78,0xCC,0x60,0x18,0xCC,0x78,0x00,0x00}, // s
  {0x00,0x00,0x20,0x60,0xFC,0x60,0x60,0x60,0x6C,0x38,0x00,0x00}, // t
  {0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00}, // u
  {0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x00,0x00}, // v
  {0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0x6C,0x6C,0x00,0x00}, // w
  {0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x6C,0xC6,0x00,0x00}, // x
  {0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x0C,0x18,0xF0}, // y
  {0x00,0x00,0x00,0x00,0xFC,0x8C,0x18,0x60,0xC4,0xFC,0x00,0x00}, // z
  {0x00,0x1C,0x30,0x30,0x60,0xC0,0x60,0x30,0x30,0x1C,0x00,0x00}, // {
  {0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x00,0x00}, // |
  {0x00,0xE0,0x30,0x30,0x18,0x0C,0x18,0x30,0x30,0xE0,0x00,0x00}, // }
  {0x00,0x73,0xDA,0xCE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ~
  {0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0x00,0x00,0x00}, // 
};

struct T_color
{
	unsigned char red;
	unsigned char grn;
	unsigned char blu;
} lcd_front_color, lcd_back_color;

struct T_cursor
{
	unsigned char x;
	unsigned char y;
} lcd_cursor;


void lcd_spi_subop_wr(unsigned char fv_data)
{
	if (SPI2STATbits.SPITBE)
	{
		SPI2BUF = fv_data;
	}

	while (SPI2STATbits.SPIBUSY);
	fv_data = SPI2BUF;
}

void lcd_subop_chipSelect(void)
{
	digitalWrite(PIN_LCD_CS, LOW);
}

void lcd_subop_chipUnselect(void)
{
	digitalWrite(PIN_LCD_CS, HIGH);
}

void lcd_write_cmd(unsigned char fv_cmd)
{
	digitalWrite(PIN_LCD_DCX, LOW);
	lcd_spi_subop_wr(fv_cmd);
}

void lcd_write_data(unsigned char fv_data)
{
	digitalWrite(PIN_LCD_DCX, HIGH);
	lcd_spi_subop_wr(fv_data);
}

void lcd_init(void)
{
	// 端口初始化
	pinMode(PIN_LCD_SDI, OUTPUT);
	digitalWrite(PIN_LCD_SDI, LOW);
	pinMode(PIN_LCD_SCK, OUTPUT);
	digitalWrite(PIN_LCD_SCK, LOW);
	pinMode(PIN_LCD_DCX, OUTPUT);
	digitalWrite(PIN_LCD_DCX, LOW);
	pinMode(PIN_LCD_RST, OUTPUT);
	digitalWrite(PIN_LCD_RST, HIGH);
	pinMode(PIN_LCD_CS, OUTPUT);
	digitalWrite(PIN_LCD_CS, HIGH);

	// SPI2初始化
	SPI2CON = 0;
	SPI2CONbits.SMP = 1;
	SPI2CONbits.CKE = 1;
	SPI2CONbits.MSTEN = 1;
	SPI2CONbits.DISSDI = 1;

	SPI2BRG = 10 - 1;
	SPI2CONbits.ON = 1;

	// 端口映射(pps)
	mapPps(PIN_LCD_SDI, PPS_OUT_SDO2);

	digitalWrite(PIN_LCD_RST, LOW);
	delay(100);
	digitalWrite(PIN_LCD_RST, HIGH);
	delay(50);

	lcd_subop_chipSelect();
	lcd_write_cmd(0x11);
	lcd_subop_chipUnselect();
	delay(120);

	lcd_subop_chipSelect();
	lcd_write_cmd(0x21); // Display Inversion ON
	//lcd_write_cmd(0x20); // Display Inversion OFF
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xB1); //lcd_write_cmd(0xB1); 
	lcd_write_data(0x05); //lcd_write_data(0x05);
	lcd_write_data(0x3A); //lcd_write_data(0x3A);
	lcd_write_data(0x3A); //lcd_write_data(0x3A);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xB2); //lcd_write_cmd(0xB2);
	lcd_write_data(0x05); //lcd_write_data(0x05);
	lcd_write_data(0x3A); //lcd_write_data(0x3A);
	lcd_write_data(0x3A); //lcd_write_data(0x3A);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xB3); //lcd_write_cmd(0xB3); 
	lcd_write_data(0x05); //lcd_write_data(0x05);  
	lcd_write_data(0x3A); //lcd_write_data(0x3A);
	lcd_write_data(0x3A); //lcd_write_data(0x3A);
	lcd_write_data(0x05); //lcd_write_data(0x05);
	lcd_write_data(0x3A); //lcd_write_data(0x3A);
	lcd_write_data(0x3A);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xB4);
	lcd_write_data(0x03);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xC0);
	lcd_write_data(0x62);
	lcd_write_data(0x02);
	lcd_write_data(0x04);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xC1);
	lcd_write_data(0xC0);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xC2);
	lcd_write_data(0x0D);
	lcd_write_data(0x00);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xC3);
	lcd_write_data(0x8D);
	lcd_write_data(0x6A);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xC4);
	lcd_write_data(0x8D);
	lcd_write_data(0xEE);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xC5);  /*VCOM*/
	lcd_write_data(0x0E);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xE0);
	lcd_write_data(0x10);
	lcd_write_data(0x0E);
	lcd_write_data(0x02);
	lcd_write_data(0x03);
	lcd_write_data(0x0E);
	lcd_write_data(0x07);
	lcd_write_data(0x02);
	lcd_write_data(0x07);
	lcd_write_data(0x0A);
	lcd_write_data(0x12);
	lcd_write_data(0x27);
	lcd_write_data(0x37);
	lcd_write_data(0x00);
	lcd_write_data(0x0D);
	lcd_write_data(0x0E);
	lcd_write_data(0x10);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0xE1);
	lcd_write_data(0x10);
	lcd_write_data(0x0E);
	lcd_write_data(0x03);
	lcd_write_data(0x03);
	lcd_write_data(0x0F);
	lcd_write_data(0x06);
	lcd_write_data(0x02);
	lcd_write_data(0x08);
	lcd_write_data(0x0A);
	lcd_write_data(0x13);
	lcd_write_data(0x26);
	lcd_write_data(0x36);
	lcd_write_data(0x00);
	lcd_write_data(0x0D);
	lcd_write_data(0x0E);
	lcd_write_data(0x10);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0x3A);
	lcd_write_data(0x06);
	//lcd_write_data(0xc0); // 18bit mode
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0x36);
	//lcd_write_data(0xA8);//
	lcd_write_data(0b01101010);
	lcd_subop_chipUnselect();

	lcd_subop_chipSelect();
	lcd_write_cmd(0x29);
	lcd_subop_chipUnselect();

	lcd_cursor.x = 0;
	lcd_cursor.y = 0;
}

void lcd_subop_set_region(unsigned char fv_x_start, unsigned char fv_y_start, unsigned char fv_x_end, unsigned char fv_y_end)
{
	lcd_write_cmd(0x2a);
	lcd_write_data(0x00);
	lcd_write_data(fv_x_start + 1);
	lcd_write_data(0x00);
	lcd_write_data(fv_x_end + 1);

	lcd_write_cmd(0x2b);
	lcd_write_data(0x00);
	lcd_write_data(fv_y_start + 0x1A);
	lcd_write_data(0x00);
	lcd_write_data(fv_y_end + 0x1A);
}

void gui_setCursor(unsigned char fv_x, unsigned char fv_y)
{
	if ((fv_x <= LCD_X_MAX) && (fv_y <= LCD_Y_MAX))
	{
		lcd_cursor.x = fv_x;
		lcd_cursor.y = fv_y;
	}
}

void gui_set_frontColor(unsigned char fv_red, unsigned char fv_grn, unsigned char fv_blu)
{
	lcd_front_color.red = fv_red;
	lcd_front_color.grn = fv_grn;
	lcd_front_color.blu = fv_blu;
}

void gui_set_backColor(unsigned char fv_red, unsigned char fv_grn, unsigned char fv_blu)
{
	lcd_back_color.red = fv_red;
	lcd_back_color.grn = fv_grn;
	lcd_back_color.blu = fv_blu;
}

void gui_drawRec(struct T_color fv_color, unsigned char fv_x_start, unsigned char fv_y_start, unsigned char fv_x_end, unsigned char fv_y_end)
{
	if ((fv_x_start <= LCD_X_MAX) && (fv_x_end <= LCD_X_MAX) && (fv_y_start <= LCD_Y_MAX) && (fv_y_end <= LCD_Y_MAX))
	{
		lcd_subop_chipSelect();
		lcd_subop_set_region(fv_x_start, fv_y_start, fv_x_end, fv_y_end);
		lcd_write_cmd(0x2c);
		unsigned char fv_op_x, fv_op_y;
		for (fv_op_y = fv_y_start; fv_op_y <= fv_y_end; fv_op_y++)
			for (fv_op_x = fv_x_start; fv_op_x <= fv_x_end; fv_op_x++)
			{
				lcd_write_data(fv_color.red);
				lcd_write_data(fv_color.grn);
				lcd_write_data(fv_color.blu);
			}
		lcd_subop_chipUnselect();
	}
}

void lcd_putChar(unsigned char fv_char)
{
	unsigned char fv_x, fv_y;
	unsigned char fv_op_data;
	lcd_subop_chipSelect();
	lcd_subop_set_region(lcd_cursor.x, lcd_cursor.y - 11, lcd_cursor.x + 7, lcd_cursor.y);
	lcd_write_cmd(0x2c);

	for (fv_y = 0; fv_y < 12; fv_y++)
	{
		fv_op_data = pgm_read_byte_near(font8x12 + (fv_char - 0x20) * 12 + fv_y);
		for (fv_x = 0; fv_x < 8; fv_x++)
		{
			if (fv_op_data & 0x80)
			{
				// 數據是1,該點使用前景色繪製
				lcd_write_data(lcd_front_color.red);
				lcd_write_data(lcd_front_color.grn);
				lcd_write_data(lcd_front_color.blu);
			}
			else
			{
				// 數據是0,該點使用背景色繪製
				lcd_write_data(lcd_back_color.red);
				lcd_write_data(lcd_back_color.grn);
				lcd_write_data(lcd_back_color.blu);
			}
			fv_op_data <<= 1;
		}
	}
	lcd_subop_chipUnselect();
	lcd_cursor.x += 8;
	if (lcd_cursor.x > LCD_X_MAX)
		lcd_cursor.x = 0;
}

void gui_put_str(char *str_ptr, unsigned char str_len)
{
	if ((lcd_cursor.x <= (LCD_X_MAX - str_len * 8)) && (lcd_cursor.y >= 11))
	{
		unsigned char fv_op_num;
		for (fv_op_num = 0; fv_op_num < str_len; fv_op_num++)
		{
			lcd_putChar(str_ptr[fv_op_num]);
		}
	}
}
/***********************************************************************/

/*這兩個函數用於橫屏時顯示字符,光標位置爲字符的左上角,字符大小高12寬8*/
void lcd_putChar2(unsigned char fv_char)
{
	unsigned char fv_x, fv_y;
	unsigned char fv_op_data, fv_op_data2;
	lcd_subop_chipSelect();
	lcd_subop_set_region(lcd_cursor.x - 11, lcd_cursor.y, lcd_cursor.x, lcd_cursor.y + 7);
	lcd_write_cmd(0x2c);

	for (fv_y = 0; fv_y < 8; fv_y++)
	{
		for (fv_x = 0; fv_x <= 11; fv_x++)
		{
			fv_op_data = pgm_read_byte_near(font8x12 + (fv_char - 0x20) * 12 + 11 - fv_x);
			fv_op_data = fv_op_data << fv_y;
			if (fv_op_data & 0x80)
			{
				// 數據是1,該點使用前景色繪製
				lcd_write_data(lcd_front_color.red);
				lcd_write_data(lcd_front_color.grn);
				lcd_write_data(lcd_front_color.blu);
			}
			else
			{
				// 數據是0,該點使用背景色繪製
				lcd_write_data(lcd_back_color.red);
				lcd_write_data(lcd_back_color.grn);
				lcd_write_data(lcd_back_color.blu);
			}
		}
	}
	lcd_subop_chipUnselect();
	lcd_cursor.y += 8;
	if (lcd_cursor.y > LCD_Y_MAX)
		lcd_cursor.y = 0;
}

void gui_put_str2(char *str_ptr, unsigned char str_len)
{
	if ((lcd_cursor.y <= (LCD_Y_MAX - str_len * 8)) && (lcd_cursor.x >= 11))
	{
		unsigned char fv_op_num;
		for (fv_op_num = 0; fv_op_num < str_len; fv_op_num++)
		{
			lcd_putChar2(str_ptr[fv_op_num]);
		}
	}
}

//繪製矩形,顏色爲前景色
void lcd_drawRect(u8 fv_x_start, u8 fv_y_start, u8 fv_x_end, u8 fv_y_end)
{
	if ((fv_x_start <= LCD_X_MAX) && (fv_x_end <= LCD_X_MAX) && (fv_y_start <= LCD_Y_MAX) && (fv_y_end <= LCD_Y_MAX))
	{
		lcd_subop_chipSelect();
		lcd_subop_set_region(fv_x_start, fv_y_start, fv_x_end, fv_y_end);
		lcd_write_cmd(0x2c);
		unsigned char fv_op_x, fv_op_y;
		for (fv_op_y = fv_y_start; fv_op_y <= fv_y_end; fv_op_y++)
			for (fv_op_x = fv_x_start; fv_op_x <= fv_x_end; fv_op_x++)
			{
				lcd_write_data(lcd_front_color.red);
				lcd_write_data(lcd_front_color.grn);
				lcd_write_data(lcd_front_color.blu);
			}
		lcd_subop_chipUnselect();
	}
}

//繪製矩形,顏色爲給定顏色
void lcd_drawRect2(u8 fv_x_start, u8 fv_y_start, u8 fv_x_end, u8 fv_y_end, u8 fv_red = lcd_front_color.red, u8 fv_grn = lcd_front_color.grn, u8 fv_blu = lcd_front_color.blu)
{
	if ((fv_x_start <= LCD_X_MAX) && (fv_x_end <= LCD_X_MAX) && (fv_y_start <= LCD_Y_MAX) && (fv_y_end <= LCD_Y_MAX))
	{
		lcd_subop_chipSelect();
		lcd_subop_set_region(fv_x_start, fv_y_start, fv_x_end, fv_y_end);
		lcd_write_cmd(0x2c);
		unsigned char fv_op_x, fv_op_y;
		for (fv_op_y = fv_y_start; fv_op_y <= fv_y_end; fv_op_y++)
			for (fv_op_x = fv_x_start; fv_op_x <= fv_x_end; fv_op_x++)
			{
				lcd_write_data(fv_red);
				lcd_write_data(fv_grn);
				lcd_write_data(fv_blu);
			}
		lcd_subop_chipUnselect();
	}
}

//清除矩形區域(顏色與背景色相同)
void lcd_clearRect(u8 fv_x_start, u8 fv_y_start, u8 fv_x_end, u8 fv_y_end)
{
	if ((fv_x_start <= LCD_X_MAX) && (fv_x_end <= LCD_X_MAX) && (fv_y_start <= LCD_Y_MAX) && (fv_y_end <= LCD_Y_MAX))
	{
		lcd_subop_chipSelect();
		lcd_subop_set_region(fv_x_start, fv_y_start, fv_x_end, fv_y_end);
		lcd_write_cmd(0x2c);
		unsigned char fv_op_x, fv_op_y;
		for (fv_op_y = fv_y_start; fv_op_y <= fv_y_end; fv_op_y++)
			for (fv_op_x = fv_x_start; fv_op_x <= fv_x_end; fv_op_x++)
			{
				lcd_write_data(lcd_back_color.red);
				lcd_write_data(lcd_back_color.grn);
				lcd_write_data(lcd_back_color.blu);
			}
		lcd_subop_chipUnselect();
	}
}

//繪製遊戲的框架
void DrawFrame()
{
	lcd_drawRect(0, 0, 0 + 5 - 1, 79);
	lcd_drawRect(159 - 5 + 1, 0, 159, 79);
	lcd_drawRect(0, 0, 159, 0 + 4 - 1);
	lcd_drawRect(0, 79 - 4 + 1, 159, 79);
	lcd_clearRect(159 - 9 - 36, 2, 159 - 5 + 1, 78);
	lcd_drawRect(159 - 9 - 36, 0, 159 - 5 - 36, 79);

}

//用於點亮(x,y)處,此處座標爲遊戲內座標,非LCD的座標
//x,y的範圍如下:
//x:1 -> 12  y : 1 -> 25
void DrawBlock(u8 x, u8 y)
{
	if (x >= 1 && x <= 12 && y >= 1 && y <= 25)
		lcd_drawRect(6 * y - 1, 6 * x - 2, 6 * y + 3, 6 * x + 2);
	//這裏是在6*6的範圍內繪製了5*5的矩形,也就是上側和右側各留有一個像素的空隙,視覺效果會好一點
}

//用於熄滅(x,y)處
void ClearBlock(u8 x, u8 y)
{
	if (x >= 1 && x <= 12 && y >= 1 && y <= 25)
		lcd_clearRect(6 * y - 1, 6 * x - 2, 6 * y + 4, 6 * x + 3);
}

//繪製類型爲form,形狀爲shape,基點座標爲(x,y)的俄羅斯方塊
void DrawTetris(u8 x, u8 y, u8 form, u8 shape)
{
	u8 i;
	for (i = 0; i <= 3; i++)
	{
		DrawBlock(x + Position_x[form][shape][i], y + Position_y[form][shape][i]);
	}
}

//清除類型爲form,形狀爲shape,基點座標爲(x,y)的俄羅斯方塊
void ClearTetris(u8 x, u8 y, u8 form, u8 shape)
{
	u8 i;
	for (i = 0; i <= 3; i++)
	{
		ClearBlock(x + Position_x[form][shape][i], y + Position_y[form][shape][i]);
	}
}

//判斷是否可以放下類型爲form,形狀爲shape,基點座標爲(x,y)的俄羅斯方塊,可以返回1,不可以返回0
u8 Judge(u8 x, u8 y, u8 form, u8 shape)
{
	u8 i;
	u8 x1, y1;
	for (i = 0; i <= 3; i++)
	{
		x1 = x + Position_x[form][shape][i];
		y1 = y + Position_y[form][shape][i];

		if (y1 > 18)
			LOSE = 1;
		if (x1 < 1 || y1 < 1 || x1 > 12 || y1 > 18)
			return 0;
		if (AllTetris[x1][y1] == 1)
			return 0;
	}
	return 1;
}

//檢測是否可以消去一層,如果可以,消去
void Remove(u8 temp[15][30])
{
	char x, y = 1;
	char i, j;
	char sign;
	u8 AllSign = 0;
	u8 sum;
	u8 Line[30] = { 0 };

	//從第1層向上檢測每層是否可以消去
	while (y <= (Now_y + 2))
	{
		sign = 1;
		for (x = 1; x <= 12; x++)
		{
			if (AllTetris[x][y] == 0)
			{
				sign = 0;
				break;
			}
		}

		if (sign == 1)      //如果可以消去
		{
			Line[y] = 1;    //標記可消去的這一層
			AllSign++;      //可消去層的計數標記+1
			Score = Score + y * y;    //分數增加,消去的層數越高,分數越多

			/*可消去的那一層會有炫酷的閃爍(沒啥用,可以去掉)*/
			/***********************************/
			gui_set_frontColor(65, 105, 255);
			for (x = 1; x <= 12; x++)
				DrawBlock(x, y);
			delay(60);
			gui_set_frontColor(255, 0, 255);
			for (x = 1; x <= 12; x++)
				DrawBlock(x, y);
			delay(60);
			gui_set_frontColor(220, 20, 60);
			for (x = 1; x <= 12; x++)
				DrawBlock(x, y);
			delay(60);
			/********************************/

		}
		y++;
	}
	//如果計數爲0,不用消去,直接返回,這是普遍情況,所以先判斷,提高效率
	if (AllSign == 0)
		return;

	//AllTetris數組更新,去掉所有應消去層
	for (y = 1, i = 1; y <= 18; y++, i++)
	{
		if (Line[i] == 1)
		{
			y--;
			continue;
		}
		else
		{
			for (x = 1; x <= 12; x++)
				AllTetris[x][y] = temp[x][i];
		}

	}

	//LCD屏幕的顯示更新
	gui_set_frontColor(255, 255, 0);
	for (y = 1; y <= 18; y++)
	{
		for (x = 1; x <= 12; x++)
		{
			ClearBlock(x, y);
			if (AllTetris[x][y] == 1)
				DrawBlock(x, y);
		}
	}
	return;
}

//用於失敗後的炫酷顯示,不再贅述(失敗後所有中斷關閉)
void LoseResult()
{
	u8 i, j, k = 5;

	while (k > 0)
	{
		k--;
		gui_set_frontColor(255, 0, 0);
		for (i = 1; i <= 18; i++)
		{
			for (j = 1; j <= 12; j++)
			{
				DrawBlock(j, i);
			}
		}
		delay(20);

		gui_set_frontColor(0, 255, 0);
		for (i = 1; i <= 18; i++)
		{
			for (j = 1; j <= 12; j++)
			{
				DrawBlock(j, i);
			}
		}
		delay(20);

		gui_set_frontColor(0, 0, 255);
		for (i = 1; i <= 18; i++)
		{
			for (j = 1; j <= 12; j++)
			{
				DrawBlock(j, i);
			}
		}
		delay(20);
	}


	for (i = 1; i <= 18; i++)
	{
		for (j = 1; j <= 12; j++)
		{
			ClearBlock(j, i);
		}
	}
	gui_set_frontColor(100, 0, 200);
	gui_setCursor(100, 30);
	gui_put_str2("You", 3);
	delay(400);

	gui_setCursor(80, 30);
	gui_put_str2("Are", 3);
	delay(400);

	gui_setCursor(60, 33);
	gui_put_str2("So", 2);
	delay(400);

	gui_setCursor(40, 30);
	gui_put_str2("Cai", 3);
	delay(400);
	uint32_t status = disableInterrupts();
}

//遊戲主體部分
void Game()
{
	u8 i, j;
	int delay_time;

	//初始化新的俄羅斯方塊的參數
	Now_Form = Next_Form;
	Now_Shape = Next_Shape;
	Next_Form = random(7);
	Next_Shape = random(4);
	Now_x = 6;
	Now_y = 17;

	//遊戲速度隨分數增加而加快
	if (Score <= 20)
		delay_time = 260;
	else if (Score <= 50)
		delay_time = 230;
	else if (Score <= 100)
		delay_time = 210;
	else if (Score <= 200)
		delay_time = 170;
	else if (Score <= 500)
		delay_time = 150;

	//頂部分數顯示和下一個俄羅斯方塊的形狀顯示
	gui_set_frontColor(255, 0, 0);
	gui_setCursor(152, 6);
	sprintf(lcd_buf, "Score:%03d", Score * rate);
	gui_put_str2(lcd_buf, strlen(lcd_buf));
	gui_setCursor(135, 6);
	gui_put_str2("Next:", 5);
	DrawTetris(10, 22, Next_Form, Next_Shape);

	//俄羅斯方塊下落部分
	gui_set_frontColor(0, 255, 255);
	while (Judge(Now_x, Now_y, Now_Form, Now_Shape) == 1)   //若可以繼續下落
	{
		//如果按下 下 鍵, 以極快的速度下落至底部
		if (digitalRead(12) == 1)
		{
			while (digitalRead(12) == 1)
				;
			delay_time = 1;
		}
		DrawTetris(Now_x, Now_y, Now_Form, Now_Shape);        //繪製當前參數對應的俄羅斯方塊

		//如果按下暫停鍵,遊戲暫停,中斷關閉,直到再次按下暫停鍵
		if (digitalRead(17) == 1)
		{
			while (digitalRead(17) == 1)
				;
			delay(200);
			uint32_t status = disableInterrupts();
			//作弊碼hhh
			while (digitalRead(17) == 0)
			{
				if ((digitalRead(10) + digitalRead(11) + digitalRead(12) + digitalRead(14)) == 4)
					rate = 10;
			}

			restoreInterrupts(status);
			delay(500);
		}

		delay(delay_time);
		ClearTetris(Now_x, Now_y, Now_Form, Now_Shape);       //清除俄羅斯方塊
		Now_y--;
	}

	if (Now_y >= 17)      //如果俄羅斯方塊已經堆到頂部,遊戲結束
	{
		LOSE = 1;
		delay(1000);
		LoseResult();
		return;
	}
	Now_y++;        //while多減了一次,這裏加回來
	gui_set_frontColor(255, 255, 0);
	DrawTetris(Now_x, Now_y, Now_Form, Now_Shape);

	// AllTetris數組更新
	for (i = 0; i <= 3; i++)
	{
		AllTetris[Now_x + Position_x[Now_Form][Now_Shape][i]][Now_y + Position_y[Now_Form][Now_Shape][i]] = 1;
	}

	//底部俄羅斯方塊重新繪製,用於消除一個無傷大雅的BUG導致的錯誤顯示
	for (i = 1; i <= 18; i++)
	{
		for (j = 1; j <= 12; j++)
		{
			if (AllTetris[j][i] == 1)
				DrawBlock(j, i);
			else
				ClearBlock(j, i);
		}
	}
	Remove(AllTetris);
	ClearTetris(10, 22, Next_Form, Next_Shape);
}

//若按下 上 鍵, 俄羅斯方塊的Shape變化,並重新繪製
void __USER_ISR myISR_UP()
{
	u8 temp = Now_Shape;
	ClearTetris(Now_x, Now_y, Now_Form, Now_Shape);
	Now_Shape++;
	if (Now_Shape >= 4)
		Now_Shape = 0;
	if (Judge(Now_x, Now_y, Now_Form, Now_Shape) == 0)
	{
		Now_Shape = temp;
	}
	DrawTetris(Now_x, Now_y, Now_Form, Now_Shape);

	clearIntFlag(_EXTERNAL_4_IRQ);
	delay(10);
}

//若按下 左 鍵,判斷是否可移動, 如果可以,俄羅斯方塊左移,並重新繪製
void __USER_ISR myISR_LEFT()
{
	if (Judge(Now_x - 1, Now_y, Now_Form, Now_Shape) == 1)
	{
		ClearTetris(Now_x, Now_y, Now_Form, Now_Shape);
		Now_x--;
		DrawTetris(Now_x, Now_y, Now_Form, Now_Shape);
	}

	clearIntFlag(_EXTERNAL_1_IRQ);
	delay(10);
}

//若按下 右 鍵,判斷是否可移動, 如果可以,俄羅斯方塊右移,並重新繪製
void __USER_ISR myISR_RIGHT()
{
	if (Judge(Now_x + 1, Now_y, Now_Form, Now_Shape) == 1)
	{
		ClearTetris(Now_x, Now_y, Now_Form, Now_Shape);
		Now_x++;
		DrawTetris(Now_x, Now_y, Now_Form, Now_Shape);
	}

	clearIntFlag(_EXTERNAL_3_IRQ);
	delay(10);
}

void setup()
{
	/*IO口初始化,四個按鍵在不輸入時,下拉爲低電平*/
	pinMode(9, INPUT);
	pinMode(10, INPUT);
	pinMode(11, INPUT);
	pinMode(12, INPUT);
	pinMode(14, INPUT);
	pinMode(17, INPUT);

	CNPDAbits.CNPDA1 = 1;
	CNPDBbits.CNPDB0 = 1;
	CNPDBbits.CNPDB1 = 1;
	CNPDBbits.CNPDB3 = 1;

	//外部中斷的映射
	mapPps(10, PPS_IN_INT3);
	mapPps(11, PPS_IN_INT1);
	mapPps(14, PPS_IN_INT4);

	//外部中斷1,3,4設置爲上升沿產生中斷
	INTCONCLR = 0x0000001A;//1 1010

	//三個外部中斷的初始化
	setIntVector(_EXTERNAL_3_VECTOR, myISR_RIGHT);
	setIntPriority(_EXTERNAL_3_VECTOR, 4, 1);
	clearIntFlag(_EXTERNAL_3_IRQ);
	setIntEnable(_EXTERNAL_3_IRQ);

	setIntVector(_EXTERNAL_1_VECTOR, myISR_LEFT);
	setIntPriority(_EXTERNAL_1_VECTOR, 4, 2);
	clearIntFlag(_EXTERNAL_1_IRQ);
	setIntEnable(_EXTERNAL_1_IRQ);

	setIntVector(_EXTERNAL_4_VECTOR, myISR_UP);
	setIntPriority(_EXTERNAL_4_VECTOR, 4, 3);
	clearIntFlag(_EXTERNAL_4_IRQ);
	setIntEnable(_EXTERNAL_4_IRQ);

	//lcd初始化
	lcd_init();

	//遊戲參數初始化
	gui_set_backColor(0, 0, 0);
	lcd_clearRect(0, 0, 160 - 1, 80 - 1);
	gui_set_frontColor(0, 0, 255);
	DrawFrame();


	randomSeed(analogRead(9));    //讀取Pin9的模擬電壓值作爲隨機數種子
	Next_Form = random(7);
	Next_Shape = random(4);
}


void loop()
{
	if (LOSE == 0)
		Game();
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章