风波邪人

幸福,幸福就是心里有那么一个人,不管你走到哪儿,也不管她走到哪儿,心里永远想着她

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

#ifndef _MAIN_H

#define _MAIN_H

#include <reg52.h>

#define LcdDataPort P2   //数据端口

#ifndef UCHAR_DEF

#define UCHAR_DEF

typedef unsigned char uchar;

#endif

sbit Reset = P3^0;   //复位

sbit RS = P3^1;    //指令数据选择

sbit E = P3^2;    //指令数据控制

sbit CS1 = P3^4;   //左屏幕选择,低电平有效

sbit CS2 = P3^5;   //右屏幕选择

sbit RW = P3^3;    //读写控制

sbit busy = P2^7;   //忙标志

void SetOnOff(uchar onoff);  //开关显示

void SelectScreen(uchar screen);//选择屏幕

void ClearScreen(uchar screen); //清屏

void Show1616(uchar lin,uchar colum,uchar *address);//显示一个汉字

void CheckState();   //判断状态

void LcdDelay(unsigned int time); //延时

void WriteData(uchar dat); //写数据

void SendCommand(uchar command); //写指令

void SetLine(uchar line);  //置行地址

void SetColum(uchar colum);//置列地址

void SetStartLine(uchar startline);//置显示起始行

void InitLcd();    //初始化

void ResetLcd();   //复位

#endif

/*********************************************************************/

/***********************************lcd.c****************************************/

void CheckState()

{

E = 1;

RS = 0;

RW = 1;

LcdDataPort = 0xff;

while(!busy);

}

void LcdDelay(unsigned int time)

{

while(time --);

}

void WriteData(uchar dat)

{

CheckState();

E = 1;

RS = 1;

RW = 0;

LcdDataPort = dat;

E = 0;

}

void SendCommand(uchar command)

{

CheckState();

E = 1;

RW = 0;

RS = 0;

LcdDataPort = command;

E = 0;

}

void SelectScreen(uchar screen) //0-全屏,1-左屏,2-右屏

{

switch(screen)

{

  case 0 :

   CS1 = 0;

   LcdDelay(2);

   CS2 = 1;

   LcdDelay(2);

   break;

  case 1 :

   CS1 = 1;

   LcdDelay(2);

   CS2 = 0;

   LcdDelay(2);

   break;

  case 2 :

   CS1 = 0;

   LcdDelay(2);

   CS2 = 0;

   LcdDelay(2);

   break;

}

}

void ClearScreen(uchar screen)  // screen 0-全屏,1-左屏,2-右屏

{

uchar i,j;

SelectScreen(screen);

for(i = 0;i < 8;i ++)

{

  SetLine(i);

  SetColum(0);

  for(j = 0;j < 64; j ++)

   WriteData(0);

}

}

void SetLine(uchar line)  //line -> 0 : 7

{

line = line & 0x07;

line = line | 0xb8;   //1011 1xxx

SendCommand(line);

}

void SetColum(uchar colum) //colum -> 0 :63

{

colum = colum & 0x3f;

colum = colum | 0x40;  //01xx xxxx

SendCommand(colum);

}

void SetStartLine(uchar startline) //startline -> 0 : 63

{

startline = startline & 0x3f;

startline = startline | 0xc0; //11xxxxxx

SendCommand(startline);

}

void SetOnOff(uchar onoff) //1-开显示 0-关

{

if(onoff == 1)

  SendCommand(0x3f);   //0011 111x

else

  SendCommand(0x3e);

}

void ResetLcd()

{

Reset = 0;

LcdDelay(2);

Reset = 1;

LcdDelay(2);

RS0 = 0;

LcdDelay(2);

RS1 = 0;

LcdDelay(2);

SetOnOff(1);

}

void InitLcd()

{

ResetLcd();

SetOnOff(0);

ClearScreen(2);

SetLine(0);

SetColum(0);

SetStartLine(0);

SetOnOff(1);

}

void Show1616(uchar lin,uchar colum,uchar *address)

{

uchar i;

SetLine(lin);

SetColum(colum);

for(i = 0;i < 16;i ++)

  WriteData(*(address ++));

SetLine(lin + 1);

SetColum(colum);

for(i = 0;i < 16;i ++)

  WriteData(*(address ++));

}

/*******************************************************************************/ 

/********************************main.c***********************************************/

#include <reg52.h>

const uchar code HZ_tab[] = {44

};

void main()

{

uchar i,line,colum ;

uchar *address ;

InitLcd(); 

while(1)

{

  colum = 16;

  line = 1;

  address = HZ_tab;

  SetOnOff(0);                //关显示

  for(i = 1;i < 7;i ++)

  {

   if(i < 4)

    SelectScreen(0);

   else

    SelectScreen(1);

   Show1616(line,colum ,address);  

   colum += 16;

   if(colum >63)

    colum = 0;

   address += 32;       //向DDRAM中写入数据

  }

  line = 5;

  colum = 0;

  for(i = 0;i <8; i ++)

  {

   if(i < 4)

    SelectScreen(0);

   else

    SelectScreen(1);

   Show1616(line,colum ,address);

   colum += 16;

   if(colum >63)

    colum = 0;

   address += 32;

  } 

  SelectScreen(2);

  SetOnOff(1);    // 开显示

  for(i = 0;i < 50;i ++)  //延时

   LcdDelay(30000);

}

}

 

 

 

/************说明******************************

此程序包含一个俄罗斯方块.c 文件和一个12864.h 文件

********************俄罗斯方块.c文件**************************/

#include "reg51.h"

#include "12864.h"

#define uchar unsigned char

#define uint unsigned int

static unsigned long Seed = 1;

#define A 48271L

#define M 2147483647L

#define Q (M / A)

#define R (M % A)

sbit K1=P3^4;

sbit K2=P3^5;

sbit K3=P3^6;

sbit K4=P3^7;

unsigned int idata num[19+2]={

0xfff,//第1行,最下面

0x801,0x801,0x801,0x801,0x801,0x801,0x801,0x801,0x801,0x801,

0x801,0x801,0x801,0x801,0x801,0x801,0x801,0x801,0x801,//第2行到第20行共19行

0xfff//第21行,最上面

};//定义共21行,其中num[0]为下墙壁行,num[20]为上墙壁行,每行12格,最左一格为左墙壁列,最右一格为右墙壁列

unsigned char code Block[28][2]={

/*

*   口     口口口   口口

*   口     口         口      口

*   口口              口  口口口      

*/

{0x88,0xc0},{0xe8,0x00},{0x62,0x20},{0x02,0xe0},

/*

*   口        口口 口口口

*   口 口     口       口

* 口口 口口口 口    

*/

{0x22,0x60},{0x08,0xe0},{0xc8,0x80},{0xe2,0x00},  

/*

*   口

*   口口         口口

*     口       口口

*/

{0x8c,0x40},{0x6c,0x00},{0x8c,0x40},{0x6c,0x00},

/*

*   口        口口

* 口口          口口

* 口

*/

{0x4c,0x80},{0xc6,0x00},{0x4c,0x80},{0xc6,0x00},  

/*

*          口                口

*   口     口口   口口口   口口

* 口口口   口       口       口

*/

{0x04,0xe0},{0x8c,0x80},{0xe4,0x00},{0x26,0x20},

/*口

* 口

* 口       口口口口

* 口

*/

{0x44,0x44},{0x0f,0x00},{0x44,0x44},{0x0f,0x00},  

/*

* 口口

* 口口

*/  

{0x06,0x60},{0x06,0x60},{0x06,0x60},{0x06,0x60}

};

#define PASSSCORE 20

struct Jimu

{

unsigned int dat;

char x;

unsigned char y;

unsigned char type;

unsigned char change;

}Sign[3];//积木结构体

unsigned char SysFlag=0;

#define NEWSIGNFLAG 0

#define DEADFLAG 1

#define PAUSEFLAG 2

unsigned char Score=0;

unsigned char Level=1;

unsigned char DelayCnt=5;

/*********************************************************/

#define N 25

/************************************

伪随机数发生器

*************************************/

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=0x0;

TH0=0;

TL0=0;

TR0=1;

ET0=1;

EX1=1;

EA=1;

    TCON|=0x04;

}

/****************************

welcome  游戏选择界面

/**********************/

void welcome()

{

Lcd_WriteStr(0,0,"欢迎来玩");

Lcd_WriteStr(0,1,"俄罗斯方块");

Lcd_WriteStr(0,2,"设置按K1");

Lcd_WriteStr(0,2,"开玩按K2");

}

/*************俄罗斯方块部分 

/******************************

画墙壁,初始化界面

*******************************/

void DrawBoard(void)

{

unsigned char n;

for(n=0;n<12;n++) ////画上下两边的墙壁

{

Lcd_Rectangle(3*n,0,3*n+2,2,1);////在最上面一行画个2*2的方块

Lcd_Rectangle(3*n,60,3*n+2,62,1);////在最下面一行画个2*2的方块

}

for(n=0;n<20;n++) ////画左右两边的墙壁

{

Lcd_Rectangle(0,3*n,2,3*n+2,1); ////在左面画2*2的方块

Lcd_Rectangle(33,3*n,35,3*n+2,1);////在右面画2*2的方块

}

Lcd_WriteStr(4,0,"经典游戏");

Lcd_WriteStr(3,2,"Score:");

Lcd_WriteStr(3,3,"Level:");

}

/***********************************

游戏结束处理

************************************/

void GameOver(void)

{

if((SysFlag&(1<<DEADFLAG))!=0)

Lcd_WriteStr(3,1,"You Fail");////SysFlag=2

else

Lcd_WriteStr(3,1,"You Pass");////SysFlag=1或=0

}

unsigned int code MaskTab[16]={

0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,

0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000

};

/**********************************

根据积木图标左下坐标X,Y来画出积木图标

***********************************/

void DrawSign(struct Jimu Temp,unsigned char DrawMode)

{

unsigned char m,n;

for(m=0;m<4;m++)

for(n=0;n<4;n++)

{

if((Temp.dat&MaskTab[4*m+n])!=0)

Lcd_Rectangle(Temp.x+n*3,Temp.y-2-3*m,Temp.x+n*3+2,Temp.y-3*m,DrawMode);

}

}

/********************************

将积木图标值融入num数据中

也即把积木图标固定,无法再下降

*********************************/

void FixSign(void)

{

unsigned char m,n;

for(m=0;m<4;m++)//行循环

for(n=0;n<4;n++)//列循环

{

if((Sign[0].dat&MaskTab[4*m+n])!=0)

{

num[20-(Sign[0].y-2)/3+m]|=MaskTab[11-Sign[0].x/3-n];

}

}

}

/********************************

判断积木图标中方块是否与障碍方块重合

*********************************/

unsigned char CheckIf(void)

{

unsigned char m,n;

for(m=0;m<4;m++)//行循环

for(n=0;n<4;n++)//列循环

{

if((Sign[1].dat&MaskTab[4*m+n])!=0)

{

if((num[20-(Sign[1].y-2)/3+m]&MaskTab[11-Sign[1].x/3-n])!=0)

return 0;

}

}

return 1;

}

/********************************

判断积木图标是否可以继续下降一格

********************************/

unsigned char CheckIfDown(void)

{

Sign[1]=Sign[0];//

Sign[1].y+=3;//假设下降一格

return CheckIf();

}

/********************************

判断积木图标是否可以向左移动

*********************************/

unsigned char CheckIfLeft(void)

{

Sign[1]=Sign[0];

Sign[1].x-=3;

return CheckIf();

}

/********************************

判断积木图标是否可以向右移动

*********************************/

unsigned char CheckIfRight(void)

{

Sign[1]=Sign[0];

Sign[1].x+=3;

return CheckIf();

}

/********************************

判断是否可以旋转

*********************************/

unsigned char CheckIfRoll(void)

{

unsigned char i;

unsigned int Temp;

Sign[1]=Sign[0];

if(++Sign[1].change>3)

Sign[1].change=0;

   i=Sign[1].type*4+Sign[1].change;

Temp=(unsigned int)Block[i][0]<<8;

Temp=Temp|Block[i][1];

Sign[1].dat=Temp;

return CheckIf();

}

/********************************

寻找满格的行并做消除处理

最多寻找4个满行并做消除

*********************************/

void DelFull(void)

{

unsigned char m,n;

unsigned char Temp;

unsigned char Flag=0;

Temp=(Sign[0].y-2)/3;

if(Temp>=20)//防止越过了下边界

Temp=1;

else

Temp=20-Temp;

////Temp为积木的最下边界,即最下一行

for(n=Temp+3;n>=Temp;n--)//积木图标的最顶行开始寻找满行比较有利于运算

{

if(num[n]==0xfff)

{

Flag=1;

for(m=n+1;m<=19;m++)

{

num[m-1]=num[m];

}

num[m]=0x801;

Score++;//每找到一个满行,则分数加1

}

}

if(Flag)//为加速而设置并判断的标志,有已固定的积木有满格消行变化则重画积木界面

{

/*行*/for(m=Temp;m<=19;m++)//为加速,不必要重第一行重画起,只需要从积木图标最下行开始往上的重画

/*列*/for(n=1;n<=10;n++)

{

if((num[m]&MaskTab[n])==0)

{

if(Lcd_ReadPixel(30-(n-1)*3,57-(m-1)*3)!=0)

//为加速而做的读象素操作

////如果该像素为1,即为黑点

{

Lcd_Rectangle(30-(n-1)*3,57-(m-1)*3,30-(n-1)*3+2,57-(m-1)*3+2,0);

}////将给像素设置为0,即为空白

}

  else

{

if(Lcd_ReadPixel(30-(n-1)*3,57-(m-1)*3)==0)//为加速而做的读象素操作

{  ////如果该像素为0

Lcd_Rectangle(30-(n-1)*3,57-(m-1)*3,30-(n-1)*3+2,57-(m-1)*3+2,1);

}  ////将给像素设置为1

}

}

}

}

/*******************************

随机产生一个积木图标放到预产生区域并显示出来

********************************/

void CreatSign(void)

{

unsigned char n;

unsigned int Temp;

DrawSign(Sign[2],0);//先清除

n=Random()*28;

Temp=(unsigned int)Block[n][0]<<8;  ////产生积木图形的高八位

Temp=Temp|Block[n][1];  ////产生积木图形的第八位

Sign[2].dat=Temp;

Sign[2].x=45;

Sign[2].y=4*3+2;

Sign[2].type=n/4;////什么意思

Sign[2].change=n%4;

DrawSign(Sign[2],1);//后画出

}

void PrintScore(void)

{

unsigned char Str[3];

Str[0]=(Score/10)|0x30;

Str[1]=(Score%10)|0x30;

Str[2]=0;

Lcd_WriteStr(6,2,Str);

}

void PrintLevel(void)

{

unsigned char Str[3];

Str[0]=(Level/10)|0x30;

Str[1]=(Level%10)|0x30;

Str[2]=0;

Lcd_WriteStr(6,3,Str);

}

/********************************

游戏的具体过程,也是俄罗斯方块算法的关键部分

*********************************/

void GamePlay(void)

{

unsigned char m,n; 

unsigned int Temp;

SysFlag|=1<<NEWSIGNFLAG;//刚开始初始化为需要产生新的积木图标  ////SysFlag=1

InitRandom(TL0);  ////用以产生随即数

Lcd_WriteStr(3,1,"Playing");

PrintScore();

PrintLevel();

CreatSign();////先清空积木显示区域,在随即产生一个类型的积木

while(1)

{

if((SysFlag&(1<<NEWSIGNFLAG))==1)//判是否需要产生新的积木图标

{////SysFlag=1时产生新积木

SysFlag&=~(1<<NEWSIGNFLAG);   ////SysFlag=0

Sign[0]=Sign[2];

CreatSign();

Sign[0].x=12;

Sign[0].y=14;

for(m=0;m<4;m++)//行循环

{

for(n=0;n<4;n++)//列循环

{

if((Sign[0].dat&MaskTab[15-m*4-n])==0) ////从最高位开始倒序测试

break;////测试Sign[0].dat的每一位,如果为该位为1,则继续测试下一位

////若为0,则直接测试下半字节  

}

if(n==4)  ////如果在半个字节里面每一位数据都是1,则将纵坐标-3,即向上移动一个小方格

Sign[0].y-=3;

}//将积木图标出现置顶

for(m=0;m<4;m++)//行循环

for(n=0;n<4;n++)//列循环

{

if((Sign[0].dat&MaskTab[4*m+n])!=0)////从最低位开始顺序测试

{

if((num[20-(Sign[0].y-2)/3+m]&MaskTab[11-Sign[0].x/3-n])!=0)

////2为上墙壁,(Sign[0].y-2)/3为积木的总高度

////num[20-(Sign[0].y-2)/3+m] 从下往上变化

////MaskTab[11-Sign[0].x/3-n]为从4*4积木的最右边往积木的最左边变化

SysFlag|=1<<DEADFLAG; ////SysFlag=2;

}

}

if((SysFlag&(1<<DEADFLAG))!=0)

break;//如果产生新的积木图标中的方块与已固定好的方块重合,则死亡。游戏结束

DrawSign(Sign[0],1);

}

if((CheckIfLeft())&&(K3==0)) //左

{

DrawSign(Sign[0],0);

Sign[0].x-=3;

DrawSign(Sign[0],1);

}  

if((CheckIfRight())&&(K4==0))  //右

{

DrawSign(Sign[0],0);

Sign[0].x+=3;

DrawSign(Sign[0],1);

}

if((CheckIfDown())&&(K2==0))//下

{

DrawSign(Sign[0],0);

Sign[0].y+=3;

DrawSign(Sign[0],1);

if((CheckIfRoll())&&(K1==0)) //翻转

{

DrawSign(Sign[0],0);

if(++Sign[0].change>3)

Sign[0].change=0;

  m=Sign[0].type*4+Sign[0].change;

////将Block数组中的元素分为7类,type为该类型;该类型分为4种,change为种类

////所以,change加1之后就表示翻转之后的积木形态

Temp=(unsigned int)Block[m][0]<<8;

Temp=Temp|Block[m][1]; ////读取翻转之后积木形态的dat数据

Sign[0].dat=Temp;   ////赋dat值给积木结构体的dat

DrawSign(Sign[0],1);  ////画出翻转后的积木

}

////2

if((SysFlag&(1<<PAUSEFLAG))!=0)

continue;

Delay(500);

if(++DelayCnt>=2*(11-Level))

{

DelayCnt=0;

if(CheckIfDown())//判断是否能继续下降一格

{

DrawSign(Sign[0],0);

Sign[0].y+=3;

DrawSign(Sign[0],1);

}

else

{

FixSign();  ////将积木移入num数组中

DelFull(); ////消行处理

PrintScore();

if(Score>=PASSSCORE)

{

SysFlag&=~(1<<DEADFLAG); ////SysFlag=1或=0

break;//跳出玩游戏过程

}

SysFlag|=1<<NEWSIGNFLAG;//新的积木图标产生标志置1

}

}

}

}

void Main()

{  

InitCpu();//初始化CPU

Lcd_Reset(); //初始化LCD屏

Lcd_Clear(0);//清屏  

Lcd_Reset(); //初始化LCD屏

Lcd_Clear(0);//清屏

DrawBoard();//画界面

GamePlay();//玩游戏

GameOver();//游戏结束

Lcd_Reset(); //初始化LCD屏

Lcd_Clear(0);//清屏

}

posted on 2011-12-27 12:46  风波邪人  阅读(1767)  评论(0编辑  收藏  举报