為使用51單片機的制作貪吃蛇的源代碼
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
51hei.png (17.59 KB, 下載次數: 55)
下載附件
2021-1-10 15:24 上傳
51hei.png (17.16 KB, 下載次數: 40)
下載附件
2021-1-10 15:25 上傳
單片機源程序如下:
- #include <12864.h>
- #include <tcs_resource.h>
- #define num 15
- //用來描述蛇在液晶上面一個點的結構體
- struct she
- {
- unsigned char x,y,value;
- unsigned char direction;
- };
- struct loop_queue //利用循環數組實現循環隊列,拐點不會超過15個。所以大小選15足以。
- {
- unsigned int front;
- unsigned int rear;
- unsigned int count;
- struct she dat[num];
- };
- //不熟悉數組實現循環隊列的可以在紙上畫一下操作過程
- struct she tou,wei,food; //蛇的頭尾節點 和食物點
- struct loop_queue queue;//循環隊列 蛇轉彎則形成拐點 將拐點入隊列 尾巴到達拐點則拐點出隊列
- unsigned char flag_exit_game; //返回標志 為1時 從貪吃蛇游戲返回菜單
- unsigned char flag_game_over; //結束標志 為1時 顯示游戲結束畫面 同時使返回標志為1
- unsigned char tcs_stop;//暫停標志
- unsigned char tcs_nd; //難度標志
- unsigned char tcs_dt; //地圖標志
- unsigned char tcs_key_flag; //貪吃蛇在一次移動中 只允許捕獲一次按鍵 也就是只能產生一個拐點
- unsigned char tcs_key_state; //用于按鍵狀態機的實現
- unsigned int tcs_df;//得分
- unsigned int tcs_highest_df;//最高得分···沒有使用這個 因為不知道要怎么在運行時寫單片機的ROM
-
- void tcs_game();
- void tcs_bianjie(unsigned int ); //貪吃蛇邊界
- void tcs_game_initial(); //游戲初始化
- void timer0_initial(); //定時器0初始化
- void timer1_initial();
- void food_produce(); //產生食物
- unsigned char test_point_exist(unsigned char x, unsigned char y, unsigned char value);
- void queue_initial(struct loop_queue *q);
- void queue_in(struct loop_queue *q,struct she h) ;
- struct she queue_out(struct loop_queue *q) ;
- void wei_you();
- void wei_xia();
- void wei_zuo();
- void wei_shang();
- void tcs_game()
- {
- struct she check; //用與暫存蛇即將移動的點 從而進行判斷
- unsigned char he;
- unsigned char hui,i;
- flag_exit_game=0;
- flag_game_over=0;
- tcs_key_state=0;
- tcs_df=0;
- tcs_stop=1;
- draw_lcd_picture(&tcs_picture[0]); //貪吃蛇游戲畫面
- delay_ms(2000);
- clear_lcd();//清屏12864
- tcs_bianjie(tcs_dt); //貪吃蛇游戲邊界
- tcs_game_initial();//貪吃蛇初始化 主要是設定頭蛇尾 并顯示蛇
- timer0_initial(); //定時器0工作在方式2 8位自動裝初值 只計數不中斷 用來產生隨機數
- timer1_initial(); //定時器1工作在方式1 16位 10ms中斷一次掃描鍵盤
- do
- {
- food_produce();//產生一個隨機數 即隨即產生x y value3個值確定一個點為食物
- he=test_point_exist(food.x,food.y,food.value);//檢測產生的點的地方是否已經有點存在
- }
- while(he==food.value);//如果隨機數產生在蛇的身體以及邊界上 則重新再產生一個
- draw_lcd_point(food.x,food.y,food.value);//顯示食物 先讀取這個點所在8位的情況 以免破壞現場
-
- queue_initial(&queue);//初始化循環隊列 使隊列空 front rear 即頭尾指針為0
- check.x=0;
- check.y=0;
- check.value=0;
- check.direction=0;
- for(i=0;i<num;i++)
- queue.dat[i]=check;
- while(1)
- {
- if(flag_exit_game==1)//如果游戲過程中按下返回鍵 則立即結束游戲 返回菜單
- break;
- if(flag_game_over==1)
- break;
-
- ET1=1; //允許掃描按鍵 貪吃蛇游戲難度決定蛇2次移動之間的間隔時間 也就是檢測按鍵的時間
- tcs_key_flag=0; //允許捕獲按鍵 在檢測按鍵時間內 只允許生產一個拐點 即捕獲到一個有效的
- //按鍵以后 就置一這個變量 不允許再增加拐點
- while(tcs_stop==0);
- switch(tcs_nd)
- {
- case 0: {delay_ms(10); break;}
- case 1: {delay_ms(50); break;}
- case 2: {delay_ms(100); break;}
- }
- ET1=0;
- switch(tou.direction)//這個switch用來根據頭的x y value值以及當前頭移動的方向
- //取出頭要到達的下一個點 存入check中 來判斷是否撞墻 吃到食物 什么的···
- {
- case 0: {
- check.x=tou.x;
- if(tou.y==63)
- check.y=0;
- else
- check.y=tou.y+1;
- check.value=tou.value;
- break ;
- }//->向右y+1 其他不變
- case 1: { //↓ 向下y不變
- check.y=tou.y;
- if(tou.value==0x80)// value==0x80 則 x+1 value=0x01
- {
- if(tou.x==7)
- check.x=0;
- else
- check.x=tou.x+1;
- check.value=0x01;
- }
- else
- {
- check.x=tou.x;
- check.value=tou.value<<1;
- }
- break ;
- }
- case 2: {
- check.x=tou.x;
- if(tou.y==0)
- check.y=63;
- else
- check.y=tou.y-1;
- check.value=tou.value;
- break ;
- }//<-向左y-1 其他不變
- case 3: { //↑ 向上y不變
- check.y=tou.y;
- if(tou.value==0x01)// value==0x01 則 x-1 value=0x80
- {
- if(tou.x==0)
- check.x=7;
- else
- check.x=tou.x-1;
- check.value=0x80;
- }
- else
- {
- check.x=tou.x;
- check.value=tou.value>>1;
- }
- break ;
- }
- }
-
- he=test_point_exist(check.x,check.y,check.value); // 檢測頭移動的下一個點是否幾經有點存在
- if(he==check.value) //如果前面的點已經存在 則可以是食物 或者是墻和蛇身
- {
- if( (check.x==food.x) && (check.y==food.y) && (check.value==food.value) )//吃到食物
- {
- tcs_df++;
- cs1=1; cs2=0;
- write_lcd_shuzi(2,32,tcs_shuzi[tcs_df/100] ); //顯示分數的百位
- write_lcd_shuzi(2,40,tcs_shuzi[ (tcs_df%100)/10] ); // 十
- write_lcd_shuzi(2,48,tcs_shuzi[tcs_df%10] ); // 個
- cs1=0; cs2=1;
- food.direction=tou.direction;//食物本沒有方向 但是為了下面的語句
- tou=food; //食物就成了頭···頭的方向依然不變
- hui=wei.direction; //先記錄下尾巴本來的移動方向
- wei.direction=611;//這次行動尾巴不動 這樣蛇身就自然加一了···611代表下面的尾巴不動
- do
- {
- food_produce();
- he=test_point_exist(food.x,food.y,food.value);
- }
- while(he==food.value);
- draw_lcd_point(food.x,food.y,food.value);//上面有說過 這個是產生并顯示食物
- }
- else//撞到身體或者墻
- {
- flag_game_over=1; // 游戲結束
- }
- }
- else //什么都么有遇到 繼續前進
- {
- check.direction=tou.direction;//這么做的理由同上 為了保持頭當前的移動方向
- tou=check;
- draw_lcd_point(tou.x,tou.y,tou.value);//畫出此時的頭
- }
- //下面是對尾巴的操作
-
- if ( (wei.x == queue.dat[queue.front].x) && ( wei.y==queue.dat[queue.front].y ) && ( wei.value== queue.dat[queue.front].value) ) //如果尾巴到達拐點
- {
- check=queue_out(&queue);
- wei.direction=check.direction; //尾巴按照拐點指示的方向走
- }
- else //如果沒有到達拐點 尾巴移動的方向不變
- {
-
- }
-
- switch( wei.direction ) //這個是尾巴的移動 以及尾巴節點數據的修改
- {
- case 0: { wei_you(); break; }
- case 1: { wei_xia(); break; }
- case 2: { wei_zuo(); break; }
- case 3: { wei_shang(); break; }
- case 611: { wei.direction=hui; break;} //這次移動 吃到實物 還原尾巴本來的移動方向
- }
- }
- TR0=0;
- TR1=0;
- ET1=0; //退出游戲時 關閉游戲過程中用到的定時器0和1 然后定時器中斷也要關閉
- }
- void timer0_initial()
- {
- TMOD=(0xf0 & TMOD) | 0x01; //定時器0 8位自動裝初值(TH0->TL0)定時器模式 用來產生隨機數
- TH0=0x00;
- TL0=0x00;
- TR0=1;
- }
- void timer1_initial()
- {
- EA=1;
- TMOD= (0x0f & TMOD) | 0x10 ; //定時器一16位定時器模式 10ms中斷一次 用來掃描鍵盤
- TH1=0xDC;//10ms中斷一次
- TL1=0x00;
- TR1=1;
- }
- void timer1() interrupt 3
- {
- unsigned char tou_last_direction; //記錄頭原來的移動方向
-
- TR1=0;
- TH1=0xDC;
- TL1=0x00;
- switch (tcs_key_state)
- {
- case 0: { // 按鍵初始態
- if ( (P2 & 0x7f) != 0x7f ) tcs_key_state = 1; // 鍵被按下,狀態轉換到鍵確認態
- else tcs_key_state = 0;
- break;
- }
-
- case 1: { // 按鍵確認態
- if ( (P2 & 0x7f) != 0x7f)
- {
- // 按鍵仍按下,此時確定記錄一次有效按鍵
- tcs_key_state = 2; // 狀態轉換到鍵釋放態
- if(tcs_key_flag==0)
- {
- tou_last_direction=tou.direction;
- switch(P2 & 0x7f)
- {
- case 0x6f: break; // 確定鍵 不進行任何操作
- case 0x5f: { flag_exit_game=1; break; }//返回鍵 結束游戲 返回菜單
- case 0x7e: { tou.direction=3;break; }//↑
- case 0x7b: { tou.direction=2;break; }//←
- case 0x7d: { tou.direction=1;break; }//↓
- case 0x77: { tou.direction=0;break; }//->
- case 0x3f: { if(tcs_stop==0) tcs_stop=1; else tcs_stop=0; break;}//暫停鍵
- }
-
- if( (tou.direction==tou_last_direction) || (tou.direction+tou_last_direction==2) || (tou.direction+tou_last_direction==4) )
- //如果本來就是按此方向移動 或者按鍵給的方向與蛇移動方向相反 則不做任何操作 此次按鍵無效
- {
- tou.direction=tou_last_direction; // 還原頭的移動方向
- }
- else //否則記錄此頭結點成為拐點
- {
- queue_in(&queue,tou);
- tcs_key_flag=1; //已經捕獲到一次按鍵信息 這次移動拐點已經產生 關閉捕獲鍵盤
- }
- }
- }
- else
- {
- tcs_key_state = 0; // 按鍵已抬起,轉換到按鍵初始態
- break;
- }
- }
- case 2: { //等待按鍵彈起狀態
- if ( (P2 & 0x7f) == 0x7f) tcs_key_state=0; //按鍵已釋放,轉換到按鍵初始態
- else tcs_key_state = 2;
- break;
- }
- }
- TR1=1;
- }
- void food_produce()
- {
- unsigned char j1,j2;
- unsigned char code a[]={0x01,0x02,0x04,0x08, 0x10,0x20,0x40,0x80,0x01,0x02,0x04,0x08, 0x10,0x20,0x40,0x80};
- unsigned char code b[]={0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7};
-
- j1 = TL0 & 0x0f; //取TL0的低四位
- food.value = a[j1]; //用0-15的數確定食物的value值
-
- j2 = (TL0 & 0xf0)>>4; //取TL0的高4位
- food.x=b[j2]; //同理確定食物的x值
-
- j2=j1+j2; // 0-30
-
- food.y=j2 +( TL0 & 0x0f ) + ( (TL0 & 0xf0)>>4 ) + 1;//3次0-15的值和一次1-16的值相加,產生1-61的數
- }
- unsigned char test_point_exist(unsigned char x, unsigned char y, unsigned char value)
- {
- unsigned char he;
- set_lcd_xy(x,y);
- he=read_lcd_dat();
- he=read_lcd_dat();
- he=he&value; //如果液晶上這個點是亮的 則he為value 若不亮則為 0
- return (he);
- }
- void tcs_game_initial()
- {
- unsigned char i;
- cs1=0; cs2=1;
- tou.x=0;
- tou.y=5;
- tou.value=0x08; //初始化頭
- tou.direction=0; // 初始化頭移動方向為向右
- wei.x=0;
- wei.y=1;
- wei.value=0x08; //初始化蛇尾
- wei.direction=0;
-
- for(i=wei.y;i<=tou.y;i++)
- draw_lcd_point(tou.x,i,tou.value);//形成蛇
- }
- void tcs_bianjie(unsigned int he)
- {
- unsigned char i;
- cs1=0; cs2=1;
- set_lcd_xy(0,0);
- for(i=0;i<=63;i++)
- write_lcd_dat(0x01);
- set_lcd_xy(7,0);
- for(i=0;i<=63;i++)
- write_lcd_dat(0x80);
-
- for(i=0;i<=7;i++)
- {
- set_lcd_xy(i,0);
- write_lcd_dat(0xff);
- set_lcd_xy(i,63);
- write_lcd_dat(0xff);
- }
- if(he==2)
- {
-
- unsigned char i,j;
- for(i=0;i<8;i++)
- {
- cs1=0;cs2=1;
- set_lcd_xy(i,0);
- for(j=0;j<64;j++)
- write_lcd_dat(tcs_dt2[i*64+j]);
- }
- }
-
- if(he==3)
- {
- unsigned char i,j;
- for(i=0;i<8;i++)
- {
- cs1=0;cs2=1;
- set_lcd_xy(i,0);
- for(j=0;j<64;j++)
- write_lcd_dat(tcs_dt3[i*64+j]);
- }
- }
- if(he==4)
- {
- unsigned char i,j;
- for(i=0;i<8;i++)
- {
- cs1=0;cs2=1;
- set_lcd_xy(i,0);
- for(j=0;j<64;j++)
- write_lcd_dat(tcs_dt4[i*64+j]);
- }
- }
- cs1=1; cs2=0;
- write_lcd_hanzi(0,0,df[0]);
- write_lcd_hanzi(0,16,df[1]);
- write_lcd_shuzi(2,32,tcs_shuzi[tcs_df/100] ); //顯示分數的百位
- write_lcd_shuzi(2,40,tcs_shuzi[ (tcs_df%100)/10] ); // 十
- write_lcd_shuzi(2,48,tcs_shuzi[tcs_df%10] ); // 個
- write_lcd_hanzi(4,0,jb[0]);
- write_lcd_hanzi(4,16,jb[1]);
- switch(tcs_nd)
- {
- case 0 : { write_lcd_hanzi(6,32,tcs_bt[0]); write_lcd_hanzi(6,48,tcs_bt[1]); break;}
- case 1 : { write_lcd_hanzi(6,32,tcs_kn[0]); write_lcd_hanzi(6,48,tcs_kn[1]); break;}
- case 2 : { write_lcd_hanzi(6,32,tcs_jd[0]); write_lcd_hanzi(6,48,tcs_jd[1]); break;}
- }
- }
- void queue_initial(struct loop_queue *q)
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有資料51hei提供下載:
貪吃蛇.zip
(201.45 KB, 下載次數: 47)
2021-1-10 10:50 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|