C语言实现贪吃蛇游戏
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/times.h>
#include<sys/types.h>
#include<unistd.h>
#include<ncurses.h> #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();
refresh(); g_level = ;
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) >= )
; getch();
destroysnake(psnake);
delwin(gwin);
DESTROYRUNLOG();
endwin(); return ;
} WINDOW* newlogw()
{
WINDOW *win = newwin(LOGWIN_YLEN, LOGWIN_XLEN, GAMEWIN_YLEN + , );
box(win, , );
mvwprintw(win, , , " LOG ");
wrefresh(win); return win;
} WINDOW *newgamew()
{
WINDOW *win = newwin(GAMEWIN_YLEN, GAMEWIN_XLEN, , );
box(win, , );
mvwprintw(win, , , " GAME ");
mvwprintw(win, GAMEWIN_YLEN - , , " Level: %d ", g_level);
mvwprintw(win, GAMEWIN_YLEN - , , " Speed: %d ", (int)(g_level/));
wrefresh(win);
return win;
} void runlog(WINDOW *win, char *str)
{
static char logbuf[LOGBUF_NUM][LOGBUF_LEN] = {};
static int index = ;
strcpy(logbuf[index], str); int i = ; for (; i < LOGBUF_NUM; ++i)
{
cleanline(win, i+, );
mvwprintw(win, i+, , logbuf[(index + i) % LOGBUF_NUM]);
wrefresh(win);
}
index = (index + LOGBUF_NUM - ) % LOGBUF_NUM;
} //将窗口win的坐标(x,y)清空
void cleanline(WINDOW *win, int y, int x)
{
char EMPTYLINE[LOGBUF_LEN] = {}; //LOGBUF_LEN = 57 //置空数组 0-56个位置
memset(EMPTYLINE, ' ', LOGBUF_LEN-); //将光标移动到窗口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 = -; fd_set set;
FD_ZERO(&set);
FD_SET(, &set); struct timeval timeout;
timeout.tv_sec = ;
timeout.tv_usec = ( - (int)(g_level/)) * * ; if (select(, &set, NULL, NULL, &timeout) < )
{
return -;
} if (FD_ISSET(, &set))
{
while ((key = getch()) == -);
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 -; default:
break;
}
} movesnake(psnake);
drawsnakew(win, psnake);
switch(checksnake(&pfood, psnake))
{
case :
break; case :
ffood = False;
if (++g_level > MAXLEVEL)
{
RUNLOG("Win!!!");
gameover(win, "Win!!!");
return -;
} mvwprintw(win, GAMEWIN_YLEN-, , " Level: %d ", g_level);
mvwprintw(win, GAMEWIN_YLEN-, , " Speed: %d ", (int)(g_level/));
wrefresh(win);
RUNLOG("Level UP!");
snakegrowup(&pfood, psnake);
break; default:
RUNLOG("Game over!");
gameover(win, "Game over!");
return -;
}
return ;
} /**
* stuct TSnake是一个倒置的首尾相连的链表,head->front指向snake的尾部
* 如: [a]<-[b]<-[c]<-[d] a为head
* | ^ 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 - ;
psnake->head->x = hx;
break; case DIR_DOWN:
psnake->head->y = hy + ;
psnake->head->x = hx;
break; case DIR_LEFT:
psnake->head->y = hy;
psnake->head->x = hx - ;
break; case DIR_RIGHT:
psnake->head->y = hy;
psnake->head->x = hx + ;
break; default:
break;
}
} int checksnake(struct TFood *pfood, struct TSnake *psnake)
{
int hy = psnake->head->y;
int hx = psnake->head->x;
if (hy <= || hy >= GAMEWIN_YLEN || hx <= || hx >= GAMEWIN_XLEN)
{
return -;
} struct TSnakeNode *pnode = GetSnakeTail(psnake);
int i = ;
for (; i < psnake->length - ; ++i, pnode = pnode->front)
{
if (hy == pnode->y && hx == pnode->x)
{
return -;
} }
if (hy == pfood->y && hx == pfood->x)
{
return ;
}
return ;
} 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 - ;
pnode->x = psnake->head->x;
break; case DIR_DOWN:
pnode->y = psnake->head->y + ;
pnode->x = psnake->head->x;
break; case DIR_LEFT:
pnode->y = psnake->head->y ;
pnode->x = psnake->head->x - ;
break; case DIR_RIGHT:
pnode->y = psnake->head->y;
pnode->x = psnake->head->x + ;
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/), (GAMEWIN_XLEN/ - strlen(str)/), str);
mvwprintw(win, (int)(GAMEWIN_YLEN/ + ), , "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 = ; newsnakenode(&newsnakenode(&newsnakenode(&newsnakenode(&psnake->head, , )->front,
, )->front, , )->front,
, )->front = psnake->head; return psnake;
} void destroysnake(struct TSnake *psnake)
{
struct TSnakeNode *psnode = GetSnakeTail(psnake);
struct TSnakeNode *ptmp = NULL; int i = ;
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 = ;
static int tailx = ;
if (taily != && tailx != )
{
//将光标移动到指定窗口的指定位置(taily, tailx)然后输出字符
mvwaddch(win, taily, tailx, ' ');
} struct TSnakeNode *psnode = GetSnakeTail(psnake); int i = ;
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 - ) + ;
pfood->x = random() % (GAMEWIN_XLEN - ) + ;
}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 = ;
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.蛇移动时,每次只移动一个单位距离,所以只需要将最后一个节点拿走,放到要移动的那个位置上就整体上有移动的感觉了,至于移动的位置会有函数检测是否合法。
注意:
程序用到了ncurses库,如果没有的话需要下载:
# 更新软件源中的所有软件列表
$ sudo apt-get update # 安装 `curses` 库
$ sudo apt-get install libncurses5-dev
编译时最后要加上-lncurses
C语言实现贪吃蛇游戏的更多相关文章
- 小项目特供 贪吃蛇游戏(基于C语言)
C语言写贪吃蛇本来是打算去年暑假写的,结果因为ACM集训给耽搁了,因此借寒假的两天功夫写了这个贪吃蛇小项目,顺带把C语言重温了一次. 是发表博客的前一天开始写的,一共写了三个版本,第一天写了第一版,第 ...
- 贪吃蛇游戏——C语言双向链表实现
采用了双向链表结点来模拟蛇身结点: 通过C语言光标控制函数来打印地图.蛇身和食物: /************************** *************************** 贪吃 ...
- 【C语言项目】贪吃蛇游戏(上)
目录 00. 目录 01. 开发背景 02. 功能介绍 03. 欢迎界面设计 3.1 常用终端控制函数 3.2 设置文本颜色函数 3.3 设置光标位置函数 3.4 绘制字符画(蛇) 3.5 欢迎界面函 ...
- 贪吃蛇游戏(printf输出C语言版本)
这一次我们应用printf输出实现一个经典的小游戏—贪吃蛇,主要难点是小蛇数据如何存储.如何实现转弯的效果.吃到食物后如何增加长度. 1 构造小蛇 首先,在画面中显示一条静止的小蛇.二维数组canva ...
- 使用Love2D引擎开发贪吃蛇游戏
今天来介绍博主近期捣腾的一个小游戏[贪吃蛇],贪吃蛇这个游戏相信大家都不会感到陌生吧.今天博主将通过Love2D这款游戏引擎来为大家实现一个简单的贪吃蛇游戏,在本篇文章其中我们将会涉及到贪吃蛇的基本算 ...
- Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录
一.项目简介 贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏. 我已经将做好的案例上传到了应用宝,无病毒.无广告,大家可以放心下载下来把玩一下.应用宝 ...
- 用C++实现的贪吃蛇游戏
我是一个C++初学者,控制台实现了一个贪吃蛇游戏. 代码如下: //"贪吃蛇游戏"V1.0 //李国良于2016年12月29日编写完成 #include <iostream& ...
- WebGL实现HTML5的3D贪吃蛇游戏
js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...
- 100行JS实现HTML5的3D贪吃蛇游戏
js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...
随机推荐
- jenkins环境自动部署
https://my.oschina.net/tonystark/blog/1920889 示例脚本: #!/bin/bash #export BUILD_ID=dontKillMe这一句很重要,这样 ...
- dbvisualizer客户端执行创建存储过程或自定义函数语句的方法
DBVisualizer这个数据库客户端工具,如果要执行存储过程或函数的话,需要在创建存储过程或函数的语句的最前面和末尾分别加上[--/]和[/]符号. --/ CREATE FUNCTION B22 ...
- Chrome教程之使用Chrome DevTools命令菜单运行命令
1.模拟移动设备 点击 Toggle Device Toolbar 2.限制网络流量和 CPU 占用率 要限制网络流量和 CPU 占用率,请从 Throttle 列表中选择 Mid-tier mobi ...
- 分布式应用的未来 — Distributionless
作者丨阿里云高级技术专家 至简(李云) 在技术变革推动社会发展这一时代背景下,大量支撑规模化分布式应用的技术创新.创造与创业应用而生,Could Native.Service Mesh.Serverl ...
- shell脚本中判断进程是否存在
#! /bin/bash PROC_NAME=docker ProcNumber=`ps -ef |grep -w $PROC_NAME|grep -v grep|wc -l` ];then echo ...
- RookeyFrame在线新增模块
今天给大家演示下在线新增模块的功能,在线新增模块跟在vs中写model实体类区别不大,线上新增少了手动初始化的过程,新增后模块同样具备新增.修改.删除.查看.导入.导出.复制.批量编辑.回收站.草稿箱 ...
- 替换 Docker 或 Laradock 中 Debian 系统镜像源解决软件安装问题
Docker Debian 镜像源替换 因多数默认的 Docker 镜像为国外的,而采用的镜像源也是国外的,故访问很慢,所以我们需要替换为国内的(比如阿里云或163等). 163 - Debian A ...
- 3.InfluxDB-InfluxQL基础语法教程--数据说明
下面是本次演示的示例数据 表名:h2o_feet 数据示例: 数据描述 : 表h2o_feet中所存储的是6分钟时间区间内的数据. 该表有一个tag,即location,该tag有两个值,分别为coy ...
- Linux-CentOS-Nginx安装
原文转自 jerryhe326:https://www.cnblogs.com/jerrypro/p/7062101.html 一.安装准备 首先由于nginx的一些模块依赖一些lib库,所以在安装n ...
- ajax的一些知识
一.关于XMLHttpRequest的实例的属性和方法 实例的属性: 1.xhr.response 响应主体内容 2.xhr.responseText 响应主体内容字符串(JSON或者XML格式字符串 ...