
基本思路:
蛇每吃一个食物蛇身子就增加一格,用UP, DOWN, LEFT, RIGHT控制蛇头的运动,而蛇身子跟着蛇头走,每后一格蛇身子下一步走到上一格蛇身子的位置,以此类推。
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#define BEG_X 2
#define BEG_Y 1
#define WID 20
#define HEI 20
HANDLE hout
typedef enum {UP, DOWN, LEFT, RIGHT} DIR
typedef struct Snake_body
{
COORD pos//蛇身的位置
struct Snake_body *next//下一个蛇身
struct Snake_body *prev//前一个蛇身
}SNAKE, *PSNAKE
PSNAKE head = NULL//蛇头
PSNAKE tail = NULL//蛇尾
//画游戏边框的函数
void DrawBorder()
{
int i, j
COORD pos = {BEG_X, BEG_Y}
for(i = 0i <HEI++i)
{
SetConsoleCursorPosition(hout, pos)
for(j = 0j <WID++j)
{
if(i == 0)//第一行
{
if(j == 0)
printf("┏")
else if(j == WID - 1)
printf("┓")
else
printf("━")
}
else if(i == HEI - 1)//最后一行
{
if(j == 0)
printf("┗")
else if(j == WID - 1)
printf("┛")
else
printf("━")
}
else if(j == 0 || j == WID - 1)//第一列或最后一列
printf("┃")
else
printf(" ")
}
++pos.Y
}
}
//添加蛇身的函数
void AddBody(COORD pos)
{
PSNAKE pnew = (PSNAKE)calloc(1, sizeof(SNAKE))
pnew->pos = pos
if(!head)
{
head = tail = pnew
}
else
{
pnew->next = head//新创建蛇身的next指向原先的蛇头
head->prev = pnew//原先的蛇头的prev指向新创建的蛇身
head = pnew//把新创建的蛇身作为新的蛇头
}
SetConsoleCursorPosition(hout, head->pos)
printf("◎")
}
//蛇身移动的函数
void MoveBody(DIR dir)
{
PSNAKE ptmp
COORD pos = head->pos
switch(dir)
{
case UP:
if(head->pos.Y >BEG_Y + 1)
--pos.Y
else
return
break
case DOWN:
if(head->pos.Y <BEG_Y + HEI - 2)
++pos.Y
else
return
break
case LEFT:
if(head->pos.X >BEG_X + 2)
pos.X -= 2
else
return
break
case RIGHT:
if(head->pos.X <BEG_X + (WID - 2) * 2)
pos.X += 2
else
return
break
}
AddBody(pos)//添加了一个新的蛇头
ptmp = tail//保存当前的蛇尾
tail = tail->prev
if(tail)
tail->next = NULL
SetConsoleCursorPosition(hout, ptmp->pos)
printf(" ")
free(ptmp)
}
int main()
{
int ctrl
DIR dir = RIGHT//初始蛇的方向是向右的
COORD pos = {BEG_X + 2, BEG_Y + HEI / 2}
system("color 0E")
system("mode con cols=90 lines=30")
hout = GetStdHandle(STD_OUTPUT_HANDLE)
printf(" ------------贪吃蛇的移动------------")
DrawBorder()
//自定义几个蛇的身体
AddBody(pos)
pos.X += 2
AddBody(pos)
pos.X += 2
AddBody(pos)
pos.X += 2
AddBody(pos)
pos.X += 2
AddBody(pos)
pos.X += 2
AddBody(pos)
pos.X += 2
AddBody(pos)
//控制蛇的移动
while(ctrl = getch())
{
switch(ctrl)
{
case 'w':
if(dir == DOWN)
continue
dir = UP
break
case 's':
if(dir == UP)
continue
dir = DOWN
break
case 'a':
if(dir == RIGHT)
continue
dir = LEFT
break
case 'd':
if(dir == LEFT)
continue
dir = RIGHT
break
case 'q':
return 0
}
MoveBody(dir)
}
return 0
}
扩展资料:
实现逻辑
1,可以设置光标,就能实现制定位置打印制定符号。
2,涉及一个结构体,包含两个元素坐标元素和一个结构体指针。
3,结构体串联形成链表,遍历获取成员坐标,打印符号得到蛇身。
4,不断的加头,去尾,重新遍历坐标,再打印形成蛇的移动。
5,食物产生的位置判定,不能越界,也不能与蛇身体重合。
6,蛇的转向判定,一条规则,不允许倒退。
7,转向的实现,跟行进方向决定新的关节坐标(当前头的上下左右)
8,死亡检测,是否头节点坐标是否与墙壁重合,是否与身体其他关节重合。
9,加速减速,设置刷新休眠时间实现。
参考资料来源:百度百科-C语言
这个我写过,代码已经丢了,我当时是创建一个(u16)数组,每个数组里面2个字节代表都是横竖2个地址,显示特定数量是数组的点(蛇长度)。每一次前进,就需要对数组进行自我覆盖,然后显示这个新数组的点。如果要变长,那就多显示一个数组,往后的不显示。如果现在写,我倾向于使用
链表
,这样就不需要反复复制整个数组,而是只改动头尾变化的点。
//总感觉这段代码应该编译不过去,有些地方写的好像也不是很合逻辑//这段代码可以用吗?
//注释的不是很完全,不过希望对你有帮助
/////////////////////////////////
// 这个是C51单片机的程序 //
/////////////////////////////////
#include <reg51.h>//包含进51的头文件
#define uchar unsigned char
#define SNAKE 20
#define TIME 50
#define SPEED 71
//#define keyenable 1
//sbit up=P0^0
//----------定义引角地址 Start-----------------
sbit keyenable=P3^6
sbit keyy=P0^2
sbit up=P3^3
sbit down=P3^1
sbit right=P3^2
sbit left=P3^4
//----------定义引角地址 End-----------------
uchar x[SNAKE+1]
uchar y[SNAKE+1]
uchar time,n,i,e
//这是个延时子函数,单位为 毫秒,是通过单片机的指定执行时间实现的
void delay(char MS)
{
char us,usn
while(MS!=0)
{
usn = 0
while(usn!=0)
{
us=0xff
while (us!=0){us-}
usn-
}
MS-
}
}
//此按数用来判断,是否有按键被按下,如果没有按键按下返回0 ,否而返回1
bit knock()
{
bit k
k=0
if(x[1]>7||y[1]>7) k=0
return k
}
void turnkey()
{//up=1
if(keyenable)
{
if(left)
{
addy=0
if(addx!=1)
addx=1
else
addx=1
}
if(right)
{
addy=0
if(addx!=1)
addx=1
else
addx=1
}
if(up)
{
addx=0
if(addy!=1)
addy=1
else addy=1
}
if(down)
{
addx=0
if(addy!=1)
addy=1
else
addy=1
}
{
addy=0
if(keyx)
if(addx==1)
addx=1
else
addx=1
else
if(addx==1)
addx=1
else
addx=1
}
else
{
addx=1
if(keyx)
if(addy==1)
addy=1
else
addy=1
else
if(addy==1)
addy=1
else
addy=1
}
}
}
uchar mux(uchar temp)
{
if(temp==7)return 128
if(temp==6)return 64
if(temp==5)return 32
if(temp==4)return 16
if(temp==3)return 8
if(temp==2)return 4
if(temp==1)return 2
if(temp==0)return 1
return 0
}
void timer0(uchar k)
{
while(k--)
{
for(i=0i<SNAKE+1i++)
{
P2=mux(x[i])
P1=255-mux(y[i])
turnkey()
delay(TIME)//延时50ms
P2=0x00
P1=0xff
}
}
}
void main(void)
{
e=SPEED
P0=0x00
P1=0xff
P2=0x00
P3=0x00
while(1)
{
//初始化变量
//if(keyenable==1){P1=0x00P2=0xff}else{P1=0xffP2=0x00}
for(i=3i<SNAKE+1i++) x[i]=100
for(i=3i<SNAKE+1i++) y[i]=10
x[0]=4y[0]=4 x[1]=1y[1]=0
x[2]=0y[2]=0
addx=0addy=0
//k=1
//等待连接P3^6的按钮按下,如果按下跳出循环进行下一步 *** 作,这个应该是个"开始按钮"
while(1)
{
if(keyenable)break
timer0(1)
}
while(1)
{
timer0(e)
if(knock()){e=SPEEDbreak}
{
n++
if(n==SNAKE+1)
{
n=3e=e-10
for(i=3i<SNAKE+1i++)x[i]=10
for(i=3i<SNAKE+1i++)y[i]=100
}
x[0]=x[n-2]
y[0]=y[n-2]
}
for(i=n-1i>1i--){x[i]=x[i-1]y[i]=y[i-1]}
//x[n-1]=x[2]y[n-1]=y[2]
x[1]=x[2]+addxy[1]=y[2]+addy
}
}
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)