⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snake.c

📁 步进电机控制程序
💻 C
字号:
/**************************************************************/
/*                  贪食蛇游戏  V2.0                          */
/*          硬件m64 + 128*64图形液晶(ks0108)8M RC           */
/*  环境:AVRSstudio4.12 SP4 + WINAVR20060421 -00优化         */
/*  作者:Bozai(章其波)                                       */
/*  日期: 2006-12-31  3:30                                    */
/**************************************************************/
/*            SNAKE  GAME V2.0                                */
/*  Author: Zhang Qibo                                        */
/*  E-mail: sudazqb@163.com                                   */
/*  MSN   : zhangqibo_1985@hotmail.com                        */
/*  Date  : 2006-12-31                                        */
/**************************************************************/

#include<avr/io.h>
#include<avr/pgmspace.h>
#include"LCD/LCD.H"
#include<stdlib.h>
//按键   //key
#define KEY_RIGHT  PF1
#define KEY_LEFT   PF0
#define KEY_UP     PF2
#define KEY_DOWN   PF3

//全局速度   //defination of speed
#define SPEED 20000



//记录蛇转向的结构体,链表
//链表首代表尾部的方向,链表尾部代表当前蛇首的方向
//a list is used to record the every turns
struct NODE
{
	unsigned char direction;	//方向   //direction
	unsigned char cnt;			//在此方向上前进的点数  //the count of the dot in this section
	struct Node *next;			//指向下一个节点  //next node
};

//记录蛇状态的结构体
//record the state of the snake
struct SNAKE
{
	unsigned char Head_X;		//蛇头的坐标//coordinate of the head
	unsigned char Head_Y;
	unsigned char Tail_X;		//蛇尾的坐标//coordinate of the tail
	unsigned char Tail_Y;
	unsigned char Direction;	//移动方向//current dirction of the head
#define TO_RIGHT 0x01
#define TO_LEFT  0x02
#define TO_UP    0x03
#define TO_DOWN  0x04
	unsigned char Level;		//游戏级别// game level
#define L0 0x00
#define L1 0x01
#define L2 0x02
#define L3 0x03
#define L4 0x04
#define L5 0x05
#define L6 0x06
#define L7 0x07
	unsigned int  Dot_Cnt;	//蛇身长度//the length of body
	unsigned char Next_X;	//目标点//coordinate of the destination
	unsigned char Next_Y;
	struct NODE * p;		//表明尾部移动方向的链表首//the head of the list,the head is the earlist turn
} Snake_Data;//声明结构体变量//global struct variable

unsigned char Hit_Self(unsigned char x,unsigned char y);//原形//prototype

//定时器1初始化//timer 1 initialization , offer the seed of the random()
void Timer1_Initial()
{
 TCNT1H=0x00;
 TCNT1L=0x00;
 TCCR1A=0x03;//ctc mode  use icr1
 TCCR1B=0x01;//system clock;
 ICR1H=0xff;
 ICR1L=0xff;
}

/*********** 以四个像素作为一个点 *************/
//总共尺寸 为 64 * 32
// x范围0~63 y范围0~31 val为填充值 1或0

//use four pixel as a dot,that means 128*64pixels have 64*32 dots
void OneDot(unsigned char x,unsigned char y,unsigned char val)//fill the four pixels with 1 or 0
{
	OnePixel(x<<1,y<<1,val);
	OnePixel(x<<1,(y<<1)+1,val);
	OnePixel((x<<1)+1,y<<1,val);
	OnePixel((x<<1)+1,(y<<1)+1,val);
}

//蛇身初始化,x y 为起始坐标,length为长度,level为游戏级别
//Initialization of the snake, (x,y)means the start place
//length means the default length of the snake
//level is the speed of the game
void Snake_Ini(unsigned char x,unsigned char y,unsigned char length,unsigned char level)
{
	unsigned char i;
	unsigned int position;
	Snake_Data.Head_X = x + length - 1;	//蛇头  //head of the snake
	Snake_Data.Head_Y = y;
	Snake_Data.Tail_X = x;				//蛇尾  //tail of the snake
	Snake_Data.Tail_Y = y;
	Snake_Data.Direction = TO_RIGHT;	//默认方向  //directon
	Snake_Data.Level = level;			//游戏级别  //level
	Snake_Data.Dot_Cnt = length;		//蛇身长度  //length
	ClearDisBuf(0x00);					//清屏      //clear display buffer
	for(i = 0;i<length;i++)OneDot(x+i,y,1);//填充   //fill the snake
	while(1)						//确定目标点    //creat a destinate dot use function rand()
	{
		srand(TCNT1);
		position = rand()>>4;			//产生随机数  //creat dot
		if(Hit_Self(position%64,position/64))continue;//如果落在有点处则重新产生  //if the dot is not locate at blank spce
		OneDot(position%64,position/64,1);	//填充  //fill the new dot
		Snake_Data.Next_X = position%64;//设置目标点   //set the coordinate of the new dot
		Snake_Data.Next_Y = position/64;
		break;
	}
	Snake_Data.p = malloc(4); 			 	//动态申请内存  //malloc
	Snake_Data.p->direction = TO_RIGHT;		//方向   //direction
	Snake_Data.p->cnt = length;				//点数   //length
	Snake_Data.p->next = 0;					//无下一节点   //no next node
	UpdateDis();							//刷新   //refresh the screen
}

//检测是否碰到自己   //if the snake hit itself  1 hit 0 not hit
unsigned char Hit_Self(unsigned char x,unsigned char y)
{
	return ReadPixel(x<<1,y<<1);
}

//键盘初始化   //keys initialization
void Key_Ini()
{
	DDRF |= 0x00;
	PORTF |= 0xff;
}

//键盘扫描    //key scan  return the direction
unsigned char Key_Scan(unsigned int n)
{
	unsigned char i = 0;
	while(n--)
	{
		if((PINF & (1<<KEY_RIGHT))==0)i = TO_RIGHT;
		else if((PINF & (1<<KEY_LEFT))==0)i = TO_LEFT;
		else if((PINF & (1<<KEY_UP))==0)i = TO_UP;
		else if((PINF & (1<<KEY_DOWN))==0)i = TO_DOWN;
	}
	return i;
}

//移动蛇身    // move the snake
unsigned char Move()
{
	unsigned int position;
	unsigned char x,y;
	struct NODE * temp;//临时节点  //temporary node

	//判断是否撞到四周的墙 //gameover
	//judge if it hit the wall
	if(Snake_Data.Direction == TO_RIGHT && Snake_Data.Head_X == 63)return 1;
	else if(Snake_Data.Direction == TO_LEFT && Snake_Data.Head_X == 0)return 1;
	else if(Snake_Data.Direction == TO_UP && Snake_Data.Head_Y == 0)return 1;
	else if(Snake_Data.Direction == TO_DOWN && Snake_Data.Head_Y == 31)return 1;

	//根据方向置x y的值
	//set x,y according the direction
	x = Snake_Data.Head_X;
	y = Snake_Data.Head_Y;
	if(Snake_Data.Direction == TO_RIGHT)x++;
	else if(Snake_Data.Direction == TO_LEFT)x--;
	else if(Snake_Data.Direction == TO_UP)y--;
	else if(Snake_Data.Direction == TO_DOWN)y++;

	temp = Snake_Data.p;
	while(temp->next != 0)temp = temp->next;//找到链表尾  //find the last node (the last turn of the snake)
	temp->cnt += 1;							//把点值加1   //add the cnt  

	//如果碰到目标点,即吃子
	//if the snake hit the destination
	if(x == Snake_Data.Next_X && y == Snake_Data.Next_Y)
	{
		//OneDot(x,y,1);
		Snake_Data.Dot_Cnt += 1;	//点加1   //length += 1
		Snake_Data.Head_X = x;		//置新头  //set the new coordinate of the head
		Snake_Data.Head_Y = y;

		while(1)                   //重新计算新目标点   //reculculate the destinate dot
		{
			srand(TCNT1);         //use TCNT1 as the seed
			position = rand()>>4;
			if(Hit_Self(position%64,position/64))continue;
			OneDot(position%64,position/64,1);
			Snake_Data.Next_X = position%64;
			Snake_Data.Next_Y = position/64;
			break;
		}
		UpdateDis();			//刷新      //refresh
		return 0;				//正常返回0 //return 0 normal
	}
	//如果碰到自己
	//if hit itself
	else if(Hit_Self(x,y) && !(x == Snake_Data.Tail_X && y == Snake_Data.Tail_Y))return 1;//gameover
	//正常移动
	//normal movement
	else
	{
		OneDot(x,y,1);			//向前移动  //move ahead
		Snake_Data.Head_X = x;	//置新首    //set the new head coordinate
		Snake_Data.Head_Y = y;
		if(x == Snake_Data.Tail_X && y == Snake_Data.Tail_Y);//如果是头尾相接就不清除  //if the head meet the tail do not clear
		else OneDot(Snake_Data.Tail_X,Snake_Data.Tail_Y,0);//否则清最后一点  //ohterwise clear the tail
		UpdateDis();									//刷新  //refresh

		if(Snake_Data.p->cnt == 1)						//如果已是该段的最后一个子  //if the dot is the last of this turn
		{
			temp = Snake_Data.p->next;					//保存节点   //save node
			free(Snake_Data.p);							//删除       //delete the node
			Snake_Data.p = temp;						//重新赋值   //reset
		}
		else            //否则该段减1   //otherwise decrement the count of this turn
		{
			Snake_Data.p->cnt -= 1;
		}
		//set the new tail according the direction
		switch(Snake_Data.p->direction)//根据该段的方向确定尾部移向哪个个点
		{
			case TO_RIGHT:Snake_Data.Tail_X += 1;break;
			case TO_LEFT :Snake_Data.Tail_X -= 1;break;
			case TO_UP   :Snake_Data.Tail_Y -= 1;break;
			case TO_DOWN :Snake_Data.Tail_Y += 1;break;
			default:break;
		}
	}
	return 0;//正常返回0  //return 0 normally
}

//进行游戏   // Play game
void Play_Game()
{
	unsigned int cnt;										//用于游戏速度  	//speed
	unsigned char direction;								//方向          	//direction
	unsigned char current_direction = Snake_Data.Direction;//当前方向 			//current direction
	struct NODE * temp;										//零时节点 用于交换	//temporary node
	struct NODE * temp1;									//零时节点
	switch(Snake_Data.Level)								//根据游戏级别设置延时 //set the speed according the level
	{
		case L0: cnt = SPEED/(L0+1);break;
		case L1: cnt = SPEED/(L1+1);break;
		case L2: cnt = SPEED/(L2+1);break;
		case L3: cnt = SPEED/(L3+1);break;
		case L4: cnt = SPEED/(L4+1);break;
		case L5: cnt = SPEED/(L5+1);break;
		case L6: cnt = SPEED/(L6+1);break;
		case L7: cnt = SPEED/(L7+1);break;
		default: cnt = SPEED/(L0+1);break;
	}
	while(1)
	{	
		direction = Key_Scan(cnt);							//读键值		//read key
		if(direction!=0 && direction != current_direction)	//不同方向		//a new direction
		{
			//判断是否为有效方向,不允许直接掉头
			//judge if it is a valid turn, do not allowed turn back directly
			if((direction == TO_RIGHT && current_direction == TO_LEFT)||(direction == TO_LEFT && current_direction == TO_RIGHT)||(direction == TO_UP && current_direction == TO_DOWN)||(direction == TO_DOWN && current_direction == TO_UP));
			else
			{
				current_direction = direction;		//改变方向			//change direction
				struct NODE *p = malloc(4);			//申请一个新节点	//a new node
				p->direction = current_direction;	//置方向			//set direction
				p->cnt = 0;							//点数为0  在move函数中会置值  //cnt=1 it will be set 1 in function Move()
				p->next = 0;						//无后续节点		//no next node
				temp = Snake_Data.p;				//把链表首给零时值  //set the new list head
				while(temp->next != NULL)temp = temp->next;//找到链表尾 //find the last node
				temp->next = p;						//添加新节点        //add the new node
			}
		}
		switch(direction)//根据按键方向确定移动方向 不可向相反方向移动
		{				 //set the direction of the head
			case TO_RIGHT :if(Snake_Data.Direction != TO_LEFT)Snake_Data.Direction = TO_RIGHT;break;
			case TO_LEFT  :if(Snake_Data.Direction != TO_RIGHT)Snake_Data.Direction = TO_LEFT;break;
			case TO_UP    :if(Snake_Data.Direction != TO_DOWN)Snake_Data.Direction = TO_UP;break;
			case TO_DOWN  :if(Snake_Data.Direction != TO_UP)Snake_Data.Direction = TO_DOWN;break;
			default:break;
		}
		if(Move())
		{
			//游戏结束,释放内存,删除链表
			//game over release the memory
			temp = Snake_Data.p;
			while(temp->next != 0)
			{
				temp1 = temp->next;
				free(temp);
				temp = temp1;
			}
			free(temp);
			return;//如果撞倒四周和自己就gameover了  //game over
		}
	}	
}

int main()
{
	Timer1_Initial();	//定时器1初始化				//initialize timer1
	Key_Ini();			//初始化按键				//initialize key
	InitialLcd();		//液晶屏初始化				//initialize LCD
	while(1)
	{
		Snake_Ini(5,5,8,0);	//游戏初始化 尾在(5,5)处 长度8 级别0	//initialize game
		Play_Game();		//开始游戏								//play game
	}	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -