/***********************************************************功能說明:貪吃蛇編譯環境:keil4MCU :STC89C52RC時鐘頻率: 22.1184MHz注意:該例程中“過關”不能在keil4編譯環境中正常顯示************************************************************//***************************************************************** /^\/^\ _|__| O| \/ /~ \_/ \ \____|__________/ \ \_______ \ `\ \ \ | | \ / / \ / / \\ / / \ \ / / \ \ / / _----_ \ \ / / _-~ ~-_ | | ( ( _-~ _--_ ~-_ _/ | \ ~-____-~ _-~ ~-_ ~-_-~ / ~-_ _-~ ~-_ _-~ ~--______-~ ~-___-~ *****************************************************************/#include "stc.h"#include "Lcd12864.h"#include "Key.h"#define uchar unsigned char#define uint unsigned intstatic unsigned long Seed = 1;#define A 48271L#define M 2147483647L#define Q (M / A)#define R (M % A)/************************************偽隨機數發生器*************************************/double Random(void){ long TmpSeed; TmpSeed=A*(Seed%Q)-R*(Seed/Q); if(TmpSeed>=0) Seed=TmpSeed; else Seed=TmpSeed+M; return (double)Seed/M;}/**************************************為偽隨機數發生器播種***************************************/void InitRandom(unsigned long InitVal){ Seed=InitVal;}//延時子程序void delay(unsigned int t){ unsigned int i,j; for(i=0;i<t;i++) for(j=0;j<10;j++); }/*********************************初始化MPU**********************************/void InitCpu(void){ TMOD=0x01; TH0=0; TL0=0; TR0=1; ET0=1; EA=1;}#define N 25struct Food{ unsigned char x; unsigned char y; unsigned char yes;}food;//食物結構體struct Snake{ unsigned char x[N]; unsigned char y[N]; unsigned char node; unsigned char direction; unsigned char life;}snake;//蛇結構體unsigned char Flag=0;unsigned char Score=0;unsigned char Speed=5; //speed越大,速度越慢unsigned char KeyBuffer=0;#define FUNC 1 //(P3^1)表示級別#define UP 2 //(P3^3)表示左#define DOWN 3 //(P3^5)表示右#define LEFT 4 //(P3^4)表示下#define RIGHT 5 //(P3^2)表示上#define PASSSCORE 20 //預定義過關成績void Timer0Int(void) interrupt 1{ switch(OSReadKey()) { case 5: KeyBuffer=FUNC; //表示級別 /*if(++Speed>=10) Speed=1; Flag|=1<<1;//速度變化標志置1*/ break; case 21: KeyBuffer=DOWN; //表示右 /*if(snake.direction!=2) snake.direction=1;*/ break; case 13: KeyBuffer=UP; //表示左 /*if(snake.direction!=1) snake.direction=2;*/ break; case 9: KeyBuffer=RIGHT; //表示上 /*if(snake.direction!=4) snake.direction=3;*/ break; case 17: KeyBuffer=LEFT; //表示下 /*if(snake.direction!=3) snake.direction=4;*/ break; default: break; }}/******************************畫墻壁,初始化界面*******************************/void DrawBoard(void){ unsigned char n; for(n=0;n<31;n++) { Lcd_Rectangle(3*n,0,3*n+2,2,1); Lcd_Rectangle(3*n,60,3*n+2,62,1); } for(n=0;n<21;n++) { Lcd_Rectangle(0,3*n,2,3*n+2,1); Lcd_Rectangle(90,3*n,92,3*n+2,1); } Lcd_HoriLine(93,31,35,1); Lcd_HoriLine(93,63,35,1);}/***************************打印成績****************************/void PrintScore(void){ unsigned char Str[3]; Lcd_WriteStr(6,0,"成績"); Str[0]=(Score/10)|0x30;//十位 Str[1]=(Score%10)|0x30;//個位 Str[2]=0; Lcd_WriteStr(7,1,Str);}/********************************打印速度級別*********************************/void PrintSpeed(void){ unsigned char Str[2]; Lcd_WriteStr(6,2,"級別"); Str[0]=Speed|0x30; Str[1]=0; Lcd_WriteStr(7,3,Str);}/***********************************游戲結束處理************************************/void GameOver(void){ unsigned char n; Lcd_Rectangle(food.x,food.y,food.x+2,food.y+2,0);//消隱出食物 for(n=1;n<snake.node;n++) { Lcd_Rectangle(snake.x[n],snake.y[n],snake.x[n]+2,snake.y[n]+2,0);//消隱食物,蛇頭已到墻壁內,故不用消去 } if(snake.life==0)//如果蛇還活著 Lcd_WriteStr(2,1,"過關"); else //如果蛇死了 Lcd_WriteStr(2,1,"輸了"); Lcd_WriteStr(1,2,"游戲結束");}/********************************游戲的具體過程,也是貪吃蛇算法的關鍵部分*********************************/void GamePlay(void){ unsigned char n; InitRandom(TL0); food.yes=1;//1表示需要出現新事物,0表示已經存在食物尚未吃掉 snake.life=0;//表示蛇還活著 snake.direction=DOWN; snake.x[0]=6;snake.y[0]=6; snake.x[1]=3;snake.y[1]=6; snake.node=2; PrintScore(); PrintSpeed(); while(1) { if(food.yes==1) { while(1) { food.x=Random()*85+3; food.y=Random()*55+3;//獲得隨機數 while(food.x%3!=0) food.x++; while(food.y%3!=0) food.y++; for(n=0;n<snake.node;n++)//判斷產生的食物坐標是否和蛇身重合 { if((food.x==snake.x[n])&&(food.y==snake.y[n])) break; } if(n==snake.node) { food.yes=0; break;//產生有效的食物坐標 } } } if(food.yes==0) { Lcd_Rectangle(food.x,food.y,food.x+2,food.y+2,1); } for(n=snake.node-1;n>0;n--) { snake.x[n]=snake.x[n-1]; snake.y[n]=snake.y[n-1]; } switch(snake.direction) { case DOWN:snake.x[0]+=3;break; case UP:snake.x[0]-=3;break; case RIGHT:snake.y[0]-=3;break; case LEFT:snake.y[0]+=3;break; default:break; } for(n=3;n<snake.node;n++)//從第三節開始判斷蛇頭是否咬到自己 { if(snake.x[n]==snake.x[0]&&snake.y[n]==snake.y[0]) { GameOver(); snake.life=1; break; } } if(snake.x[0]<3||snake.x[0]>=90||snake.y[0]<3||snake.y[0]>=60)//判蛇頭是否撞到墻壁 { GameOver(); snake.life=1; } if(snake.life==1) break;//蛇死,則跳出while(1)循環 if(snake.x[0]==food.x&&snake.y[0]==food.y)//判蛇是否吃到食物 { Lcd_Rectangle(food.x,food.y,food.x+2,food.y+2,0);//消隱食物 snake.x[snake.node]=200; snake.y[snake.node]=200;//產生蛇新的節坐標先放在看不見的位置 snake.node++;//蛇節數加1 food.yes=1;//食物標志置1 if(++Score>=PASSSCORE) { PrintScore(); GameOver(); break; } PrintScore(); } for(n=0;n<snake.node;n++) { Lcd_Rectangle(snake.x[n],snake.y[n],snake.x[n]+2,snake.y[n]+2,1); }//根據蛇的節數畫出蛇 delay(Speed*1000); //調速 delay(Speed*1000); Lcd_Rectangle(snake.x[snake.node-1],snake.y[snake.node-1],snake.x[snake.node-1]+2,snake.y[snake.node-1]+2,0); switch(KeyBuffer) { case FUNC: KeyBuffer=0; if(++Speed>=10) Speed=1; PrintSpeed(); break; case DOWN: KeyBuffer=0; if(snake.direction!=UP) snake.direction=DOWN; break; case UP: KeyBuffer=0; if(snake.direction!=DOWN) snake.direction=UP; break; case RIGHT: KeyBuffer=0; if(snake.direction!=LEFT) snake.direction=RIGHT; break; case LEFT: KeyBuffer=0; if(snake.direction!=RIGHT) snake.direction=LEFT; break; default: break; } }//結束while(1)}void Main(){ InitCpu();//初始化CPU Lcd_Reset(); //初始化LCD屏 Lcd_WriteStr(2,1,"航峰興業"); delay(5000); delay(5000); Lcd_WriteCmd(0x01); //清除顯示,并且設定地址指針為00H Lcd_Clear(0);//清屏 DrawBoard();//畫界面 GamePlay();//玩游戲 GameOver();//游戲結束 while(1);//要想重玩,只能重啟,可繼續完善該游戲 |