贪吃蛇游戏c语言教程,C语言实现贪吃蛇游戏

这是一个使用C语言编写的贪吃蛇游戏。游戏中,玩家可以通过键盘控制蛇的移动,吃到食物后会升级并加快速度。游戏窗口分为游戏区和日志区,实时显示得分和状态。当蛇碰到边界或自己时,游戏结束。代码中定义了蛇的结构体,实现了蛇的移动、增长、食物生成和检测等功能。
摘要由CSDN通过智能技术生成

#include

#include

#include

#include

#include

#include

#include

#define TBool int

#define True 1

#define False 0

#define SHAPE_FOOD '@'

#define SHAPE_SNAKE '#'

#define GAMEWIN_YLEN 20

#define GAMEWIN_XLEN 60

#define LOGWIN_YLEN 7

#define LOGWIN_XLEN (GAMEWIN_XLEN)

#define LOGBUF_NUM (LOGWIN_YLEN - 2)

#define LOGBUF_LEN (GAMEWIN_XLEN - 2)

#define MAXLEVEL 12

#define GetSnakeTail(s) ((s)->head->front)

WINDOW *logwin; //declare a windows for displaying message

#define INITRUNLOG() logwin = newlogw()

#define RUNLOG(str) runlog(logwin, str)

#define DESTROYRUNLOG() delwin(logwin)

int g_level; //level of player

enum TDirection

{

DIR_UP,

DIR_DOWN,

DIR_LEFT,

DIR_RIGHT

};

struct TFood

{

int x;

int y;

};

struct TSnakeNode

{

int y;

int x;

struct TSnakeNode *front;

};

struct TSnake

{

int length;

struct TSnakeNode *head;

enum TDirection dir;

};

int refreshgamew(WINDOW *win, struct TSnake *psnake);

void movesnake(struct TSnake *psnake);

int checksnake(struct TFood *pfood, struct TSnake *psnake);

void snakegrowup(struct TFood *pfood, struct TSnake *psnake);

void gameover(WINDOW *win, char *str);

struct TSnakeNode *newsnakenode(struct TSnakeNode **ppsnode, int y, int x);

struct TSnake *initsnake();

void destroysnake(struct TSnake *psnake);

void drawsnakew(WINDOW *win, struct TSnake *psnake);

void drawfoodw(WINDOW *win, struct TFood *pfood, struct TSnake *psnake);

TBool checkfood(struct TFood *pfood, struct TSnake *psnake);

WINDOW* newgamew();

WINDOW* newlogw();

void runlog(WINDOW* win, char *str);

void cleanline(WINDOW *win, int y, int x);

int main()

{

initscr();

raw();

noecho();

keypad(stdscr, TRUE);

curs_set(0);

refresh();

g_level = 1;

INITRUNLOG();

RUNLOG(" press 'q' or 'Q' to quit.");

RUNLOG(" press 'w/s/a/d' or 'W/S/A/D' to move the snake.");

RUNLOG("info:");

WINDOW *gwin = newgamew();

struct TSnake *psnake = initsnake();

drawsnakew(gwin, psnake);

while(refreshgamew(gwin, psnake) >= 0)

;

getch();

destroysnake(psnake);

delwin(gwin);

DESTROYRUNLOG();

endwin();

return 0;

}

WINDOW* newlogw()

{

WINDOW *win = newwin(LOGWIN_YLEN, LOGWIN_XLEN, GAMEWIN_YLEN + 2, 3);

box(win, 0, 0);

mvwprintw(win, 0, 2, " LOG ");

wrefresh(win);

return win;

}

WINDOW *newgamew()

{

WINDOW *win = newwin(GAMEWIN_YLEN, GAMEWIN_XLEN, 1, 3);

box(win, 0, 0);

mvwprintw(win, 0, 2, " GAME ");

mvwprintw(win, GAMEWIN_YLEN - 1, 2, " Level: %d ", g_level);

mvwprintw(win, GAMEWIN_YLEN - 1, 30, " Speed: %d ", (int)(g_level/3));

wrefresh(win);

return win;

}

void runlog(WINDOW *win, char *str)

{

static char logbuf[LOGBUF_NUM][LOGBUF_LEN] = {0};

static int index = 0;

strcpy(logbuf[index], str);

int i = 0;

for (; i < LOGBUF_NUM; ++i)

{

cleanline(win, i+1, 1);

mvwprintw(win, i+1, 1, logbuf[(index + i) % LOGBUF_NUM]);

wrefresh(win);

}

index = (index + LOGBUF_NUM - 1) % LOGBUF_NUM;

}

//将窗口win的坐标(x,y)清空

void cleanline(WINDOW *win, int y, int x)

{

char EMPTYLINE[LOGBUF_LEN] = {0}; //LOGBUF_LEN = 57

//置空数组 0-56个位置

memset(EMPTYLINE, ' ', LOGBUF_LEN-1);

//将光标移动到窗口win(y,x)然后打印字符串EMPTYLINE

mvwprintw(win, y, x, EMPTYLINE);

//在指定窗口上显示内容

wrefresh(win);

}

int refreshgamew(WINDOW *win, struct TSnake *psnake)

{

static TBool ffood = False;

struct TFood pfood;

if (!ffood)

{

drawfoodw(win, &pfood, psnake);

ffood = True;

}

int key = -1;

fd_set set;

FD_ZERO(&set);

FD_SET(0, &set);

struct timeval timeout;

timeout.tv_sec = 0;

timeout.tv_usec = (6 - (int)(g_level/3)) * 100 * 1000;

if (select(1, &set, NULL, NULL, &timeout) < 0)

{

return -1;

}

if (FD_ISSET(0, &set))

{

while ((key = getch()) == -1);

switch(key)

{

case 'w':

case 'W':

(psnake->dir == DIR_DOWN) ? : (psnake->dir = DIR_UP);

break;

case 's':

case 'S':

(psnake->dir == DIR_UP) ? : (psnake->dir = DIR_DOWN);

break;

case 'a':

case 'A':

(psnake->dir == DIR_RIGHT) ? : (psnake->dir = DIR_LEFT);

break;

case 'd':

case 'D':

(psnake->dir == DIR_LEFT) ? : (psnake->dir = DIR_RIGHT);

break;

case 'q':

case 'Q':

RUNLOG("Quit Game!");

gameover(win, "Quit Game!");

return -1;

default:

break;

}

}

movesnake(psnake);

drawsnakew(win, psnake);

switch(checksnake(&pfood, psnake))

{

case 0:

break;

case 1:

ffood = False;

if (++g_level > MAXLEVEL)

{

RUNLOG("Win!!!");

gameover(win, "Win!!!");

return -1;

}

mvwprintw(win, GAMEWIN_YLEN-1, 2, " Level: %d ", g_level);

mvwprintw(win, GAMEWIN_YLEN-1, 30, " Speed: %d ", (int)(g_level/3));

wrefresh(win);

RUNLOG("Level UP!");

snakegrowup(&pfood, psnake);

break;

default:

RUNLOG("Game over!");

gameover(win, "Game over!");

return -1;

}

return 1;

}

/**

* stuct TSnake是一个倒置的首尾相连的链表,head->front指向snake的尾部

* 如: [a]

* | ^ snake移动的时候,只用head指向d,

* `--------------' 并且修改d的(y,x)为snake头移动到的位置.

*/

void movesnake(struct TSnake *psnake)

{

int hy = psnake->head->y;

int hx = psnake->head->x;

psnake->head = GetSnakeTail(psnake);

switch(psnake->dir)

{

case DIR_UP:

psnake->head->y = hy - 1;

psnake->head->x = hx;

break;

case DIR_DOWN:

psnake->head->y = hy + 1;

psnake->head->x = hx;

break;

case DIR_LEFT:

psnake->head->y = hy;

psnake->head->x = hx - 1;

break;

case DIR_RIGHT:

psnake->head->y = hy;

psnake->head->x = hx + 1;

break;

default:

break;

}

}

int checksnake(struct TFood *pfood, struct TSnake *psnake)

{

int hy = psnake->head->y;

int hx = psnake->head->x;

if (hy <= 0 || hy >= GAMEWIN_YLEN || hx <= 0 || hx >= GAMEWIN_XLEN)

{

return -1;

}

struct TSnakeNode *pnode = GetSnakeTail(psnake);

int i = 0;

for (; i < psnake->length - 1; ++i, pnode = pnode->front)

{

if (hy == pnode->y && hx == pnode->x)

{

return -1;

}

}

if (hy == pfood->y && hx == pfood->x)

{

return 1;

}

return 0;

}

void snakegrowup(struct TFood *pfood, struct TSnake *psnake)

{

struct TSnakeNode *pnode = (struct TSnakeNode *)malloc(sizeof(struct TSnakeNode));

switch(psnake->dir)

{

case DIR_UP:

pnode->y = psnake->head->y - 1;

pnode->x = psnake->head->x;

break;

case DIR_DOWN:

pnode->y = psnake->head->y + 1;

pnode->x = psnake->head->x;

break;

case DIR_LEFT:

pnode->y = psnake->head->y ;

pnode->x = psnake->head->x - 1;

break;

case DIR_RIGHT:

pnode->y = psnake->head->y;

pnode->x = psnake->head->x + 1;

break;

default:

break;

}

pnode->front = GetSnakeTail(psnake);

psnake->head->front = pnode;

psnake->head = pnode;

++psnake->length;

}

void gameover(WINDOW *win, char *str)

{

mvwprintw(win, (int)(GAMEWIN_YLEN/2), (GAMEWIN_XLEN/2 - strlen(str)/2), str);

mvwprintw(win, (int)(GAMEWIN_YLEN/2 + 1), 20, "Please any key to quit...");

wrefresh(win);

}

struct TSnakeNode *newsnakenode(struct TSnakeNode **ppsnode, int y, int x)

{

*ppsnode = (struct TSnakeNode *)malloc(sizeof(struct TSnakeNode));

(*ppsnode)->y = y;

(*ppsnode)->x = x;

(*ppsnode)->front = NULL;

return *ppsnode;

}

struct TSnake *initsnake()

{

struct TSnake *psnake = (struct TSnake *)malloc(sizeof(struct TSnake));

psnake->dir = DIR_LEFT;

psnake->length = 4;

newsnakenode(&newsnakenode(&newsnakenode(&newsnakenode(&psnake->head, 4, 50)->front,

4, 53)->front, 4, 52)->front,

4, 51)->front = psnake->head;

return psnake;

}

void destroysnake(struct TSnake *psnake)

{

struct TSnakeNode *psnode = GetSnakeTail(psnake);

struct TSnakeNode *ptmp = NULL;

int i = 0;

for (; i < psnake->length; ++i)

{

ptmp = psnode;

psnode = psnode->front;

free(ptmp);

}

free(psnake);

psnake = NULL;

}

void drawsnakew(WINDOW *win, struct TSnake *psnake)

{

static int taily = 0;

static int tailx = 0;

if (taily != 0 && tailx != 0)

{

//将光标移动到指定窗口的指定位置(taily, tailx)然后输出字符

mvwaddch(win, taily, tailx, ' ');

}

struct TSnakeNode *psnode = GetSnakeTail(psnake);

int i = 0;

for (; i < psnake->length; ++i)

{

mvwaddch(win, psnode->y, psnode->x, SHAPE_SNAKE);

psnode = psnode->front;

}

taily = GetSnakeTail(psnake)->y;

tailx = GetSnakeTail(psnake)->x;

wrefresh(win);

}

void drawfoodw(WINDOW *win, struct TFood *pfood, struct TSnake *psnake)

{

do

{

pfood->y = random() % (GAMEWIN_YLEN - 2) + 1;

pfood->x = random() % (GAMEWIN_XLEN - 2) + 1;

}while(False == checkfood(pfood, psnake));

checkfood(pfood, psnake);

mvwaddch(win, pfood->y, pfood->x, SHAPE_FOOD);

wrefresh(win);

}

//检查food出现的位置不能在snake上

TBool checkfood(struct TFood *pfood, struct TSnake *psnake)

{

struct TSnakeNode *pnode = GetSnakeTail(psnake);

int i = 0;

for (; i < psnake->length; ++i, pnode = pnode->front)

{

if (pfood->y == pnode->y && pfood->x == pnode->x)

{

return false;

}

}

return true;

}

两个重点:

1.整个窗口的坐标以(0,0)为原点,x轴,y轴建立坐标点,x轴正向和y轴负向作为数值增大的方向,所以坐标移动时向下y轴坐标+1,反之-1

2.蛇移动时,每次只移动一个单位距离,所以只需要将最后一个节点拿走,放到要移动的那个位置上就整体上有移动的感觉了,至于移动的位置会有函数检测是否合法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值