我试了说一下这个代码 核心的三个函数
menu()
setup()
draw()
menu用来设置菜单,也就是我们一运行看到的那个。setup用来设置参数,我们需要设置高度和宽度,还有分数,食物的位置。draw也就是画,也就是画整个画面。
还有一个枚举类型 这个结构体用来设置蛇的几个状态,我觉得这个也是面向对象编程的一个思想,把蛇的状态都封装成一个枚举类型。
typedef enum
{
STOP = 0,
LEFT,
RIGHT,
UP,
DOWN
}Direction
还有
/*判断贪吃蛇的长度*/
void logic()
这个函数,这个函数应该是整个贪吃蛇的精髓了,要理解代码怎么把蛇给连接起来。用了点巧妙的东西。
来看这里面的关键代码
/*把上一个位置记下*/
int lastX = tailX[0]
int lastY = tailY[0]
int last2X, last2Y
/*重新获取当前的位置*/
tailX[0]=x
tailY[0]=y
int i=0
/*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/
for(i=1i ntaili++)
{
last2X = tailX[i]
last2Y = tailY[i]
tailX[i]=lastX
tailY[i]=lastY
lastX = last2X
lastY = last2Y
}
lastX lastY 用来存上一次的蛇头的位置。后面的 for 循环,通过tail 蛇的长度,把蛇上个状态给保存到数组tailX tailY里面。
完整代码
#include stdio.h
#include stdlib.h
#include stdbool.h
#include Windows.h
#include time.h
#include conio.h /*键盘输入获取*/
bool gameOver
bool stop = false
bool hit = false
/*游戏的边框大小*/
const int width = 50
const int height = 20
/*蛇的坐标,食物的坐标还有分数*/
int x,y,fruitX,fruitY,score
/*蛇每个点的坐标*/
int tailX[200],tailY[200]
/*蛇的默认长度*/
int ntail=3
typedef enum
{
STOP = 0,
LEFT,
RIGHT,
UP,
DOWN
}Direction
Direction Dir
/*开始菜单*/
void menu()
{
int a
printf( ------------------------------------------------------------------\n
printf( | 贪吃蛇游戏|\n
printf( | 1) 新游戏 |\n
printf( | 2) 开始边界 |\n
printf( | 3) 退出游戏 |\n
printf( ------------------------------------------------------------------\n
printf( ---- 请输入你的选择:
scanf( %d ,
}
/*初始化状态*/
void setup()
{
gameOver = false
/*根据当前时间设置“随机数种子”*/
srand(time(NULL))
Dir = STOP
/*贪吃蛇的位置,固定在中间*/
x= width/2
y= height/2
/*食物的位置,位置是随机的*/
fruitX = rand()%width
fruitY = rand()%height
score = 0
}
/*绘制界面*/
void draw()
{
if(stop == true)
{
return
}
system( cls /*清除屏幕*/
printf( 分数:%d ,score)
printf( \n
/*第一行*/
int i
for(i= 0 i width+1i++)
{
printf( -
}
printf( \n
/*画中间的画面*/
int p
for(p= 0 p heightp++)/*高度*/
{
int q
for(q= 0 q widthq++)/*宽度*/
{
/*第一行最后已给字符*/
if(q==0 || q==width-1)
{
printf( |
}
if(p == fruitY q == fruitX)/*食物的随机坐标*/
{
printf( O
}
else
{
int k=0
bool print = false
/*贪吃蛇的长度 默认长度是 3*/
for(k=0k ntailk++)
{
if(tailX[k]==q tailY[k]==p)
{
printf( *
print = true
}
}
/*如果这个位置打印了 * 就不要打印空格了*/
if(!print)
{
printf(
}
}
}
printf( \n
}
/*最后一行*/
int j
for(j= 0 j width+1j++)
{
printf( -
}
}
/*按键输入控制*/
void input()
{
if(_kbhit())
{
/*获取键盘的输入字符*/
switch(_getch())
{
case 4 :
case 75:/*左键*/
Dir = LEFT
hit= true
break
case 8 :
case 72:/*上键*/
Dir = UP
hit= true
break
case 6 :
case 77:/*右键*/
Dir = RIGHT
hit= true
break
case 2 :
case 80:/*向下键盘键 */
Dir = DOWN
hit= true
break
case x :
case 27:/*ESE*/
gameOver = true
break
case 32:/*空格 暂停键*/
stop = !stop
break
}
}
else if(!hit stop == false)/*如果没有改变方向*/
{
x++
}
}
/*判断贪吃蛇的长度*/
void logic()
{
if(stop == true)
{
return
}
/*把上一个位置记下*/
int lastX = tailX[0]
int lastY = tailY[0]
int last2X, last2Y
/*重新获取当前的位置*/
tailX[0]=x
tailY[0]=y
int i=0
/*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/
for(i=1i ntaili++)
{
last2X = tailX[i]
last2Y = tailY[i]
tailX[i]=lastX
tailY[i]=lastY
lastX = last2X
lastY = last2Y
}
/*根据方向来改变x y 的值*/
switch(Dir)
{
case UP:
y--
break
case DOWN:
y++
break
case LEFT:
x--
break
case RIGHT:
x++
break
}
if(x 0 || width x || y 0 || height y)
{
gameOver = true
/*清除屏幕*/
system( cls
printf( ------------------------------------------------------------------\n
printf( ||\n
printf( ||\n
printf( | 游戏结束 |\n
printf( ||\n
printf( ||\n
printf( ------------------------------------------------------------------\n
}
if(x==fruitX y==fruitY)
{
/*吃了一个食物,蛇的长度增加1*/
ntail++
score+=10
/*更新下一个食物的位置*/
fruitX = rand()%width
fruitY = rand()%height
}
}
int main()
{
#if 0
while(1)
{
printf( %d\n ,_getch())
}
#endif
menu()
setup()
draw()
/*循环画贪吃蛇的界面*/
while(!gameOver)
{
draw()
input()
logic()
Sleep(70)
}
return 0
}
上面这段代码直接在Dev C++上面应该是可以运行的,很多人在知乎上私信问我,为什么我的贪吃蛇执行不了呢,可能就是平台不同,少了这个头文件,少了那个头文件,但是你为什么不能跟我一样,用Dev C++呢,轻量级,简单。代码的精髓是什么?我认为精髓一定是思想,不是你写了多少行代码,用了什么高端的IDE。
我自认为我的注释已经写得不错了,所以就没有什么好说明的了吧,有不明白的把代码过一下,至于屏幕刷新这个东西,如果只是用时间刷新就会闪屏,所以出现了一个双缓存,把要显示的东西送到一个buff里面去,另一个buff用来显示,这样就可以保证不会出现闪屏。除了写贪吃蛇,可以用这个方法写其他小程序,挺有意思的。
在知乎上,发起了一个C语言 100 行代码之内实现贪吃蛇的问题。我觉得很不错,里面很多同学的回复都非常赞,特别是叶大神的回复。
0142235ea7197f4e1d7ClTovj.png
学习C/C++编程知识,想要成为一个更加优秀的程序员,或者你学习C/C++的时候有难度,可以来UP主页的C++编程学习圈,里面不仅有学习视频和文件资料,还有更多志同道合的朋友,欢迎初学者和想转行的朋友,和大家一起交流成长会比自己琢磨更快哦! UP也上传了一些C/C++学习的视频教程和C语言基础教程,有兴趣的小伙伴可以看看~ 谢谢阅读!
文章知识点与官方知识档案匹配
C技能树首页概览
115488 人正在系统学习中
点击阅读全文
打开CSDN APP,看更多技术内容
C语言之出圈游戏(详解)
PTA7-5 出圈游戏 用指针实现以下功能:有n个人围成一个圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号。 (1)编程提示 每三个人离开,置为0;当数到最后一个人时,将指针重新指向第一个人;m表示离开的人数,当m=n-1时,说明只剩下一个人,循环结束。 输入样例: 10 输出样例: 4 上面是题目的要求。 本小白的思路是让n个人形成一个一维数组,每次判断该人是不是要离开, 如果离开,这就不添加到这个一维数组里,并记录下来离开的人数,否则,就在数组里加上这
继续访问
9718 整数因子分解(优先做)
9718 整数因子分解(优先做)Description输入格式输出格式输入样例输出样例 时间限制:1000MS 代码长度限制:10KB 提交次数:0 通过次数:0 题型: 编程题 语言: G++GCCVC Description 大于1的正整数 n 都可以分解为 n = x1 * x2 * … * xm, 每个xi为大于1的因子,即1<xi<=n 。 例如:当n=12时,共有8种不同的分解式: 12 = 12 12 = 62 12 = 43 12 = 34 12 = 322 12 =
继续访问
【C语言】链表——圈中游戏问题(数到3退出)
问题描述: 有n个人围成一圈,从第1个人开始报数1、2、3,每报到3的人退出圈子。使用链表找出最后留下的人。
继续访问
套圈游戏c语言程序设计教程课后答案,概率统计习题带答案
概率论与数理统计习题及题解沈志军 盛子宁第一章 概率论的基本概念1.设事件B A ,及B A 的概率分别为q p ,及r ,试求)(),(),(B A P B A P AB P 及)(AB P2.若C B A ,,相互独立,试证明:C B A ,,亦必相互独立。3.试验E 为掷2颗骰子观察出现的点数。每种结果以),(21x x 记之,其中21,x x 分别表示第一颗、第二颗骰子的点数。设事件}10...
继续访问
c语言贪吃蛇设计意义,C语言贪吃蛇设计理念.pdf
基于C语言的 “贪吃蛇”游戏的设计与实现摘3.功能描述 本游戏主要实现以下几种功能:“贪吃蛇”游戏贪 游 游吃 戏 戏蛇 显 分的 ...
继续访问
热门推荐 一个好玩的小游戏(纯C语言编写)
最近在看知乎是发现了一个这一个专栏 https://zhuanlan.zhihu.com/c2game 从中获取的许多知识,本文中的游戏也是从里面学到的,不过本人又自己加了一些功能。 这是一个类似于飞机大战的游戏,不过目前代码量比较小,所以看起来非常简陋游戏界面如下 更新日志,本人将原来的原来的代码有进一步的优化了一下,之前是只有一个非常小的战机现在更新后可以产生一个非常大的战机(看起来也更
继续访问
如何用C语言实现圈叉游戏(-)
今天情人节,还是在学习C语言 自己写了一遍发现自己写的没有书上的代码更简练 就把书上的代码稍微修改了一下 下面看游戏界面 和昨天的米字棋差不多,有时间会结合米字旗的代码做些修改
继续访问
C语言:围圈报数游戏
游戏规则:有N个人围成一圈,顺序排号,从第一个人开始1到D报数,,凡报到D的人退出圈子(下场),问最后留下来的是原来的第几号? 逻辑思想:用布尔数组记下每个人的上场状态,1为上场,0为下场,开始游戏后每D个状态为1的人将状态改为0(即下场),重复下场动作N-1次后可知剩下一人,遍历数组找出剩下的状态为1的人即可。 代码如下: #include<stdio.h>#define N 1000 //参与的总人数 #define D 3 //每D个人报数下场 int main() { /
继续访问
数圈圈
26个大写字母里面,有一部分字母是带有圈的,比如A有1个圈,B有2个圈,C没有圈, 给你一个带有n个大写字母组成的字符串,请问一共有多少个圈圈。 你可以将字母中完全封闭的一个区域当作一个圈 输入描述: 第一行输入一个整数t,代表有t组测试数据, 对于每组测试数据, 第一行输入一个整数n代表字符串的长度, 第二行输入一个长度为n的字符串S,保证只由大写字母组成。 1<=t<=10 1<=n<=1*10^5 输出描述: 对于每组测试数据,输出一个整数代表这个字符串共有多少个圈圈。 并且对
继续访问
C语言围圈游戏
玩游戏,一共 N( 1≤N≤1000 )个人围成一圈,从某个人起顺时针顺序编号为 1 ~ N 号。 游戏只能有一个人赢,船长让大家数数,从编号为 1 的人开始顺时针报数,每轮从 1 报到 M 号( 1≤ M ),凡报到 M 的人视为出局,接着又从紧邻的下一个人开始同样的报数(紧邻的下一个人又报 1 )。 依次输入人数 N ,和报数规则的末数 M ,中间隔一个空格。输出能赢的相应编号R。 #include<stdio.h>int main() {...
继续访问
圈中游戏
有n个人围成一圈,从第1个人开始报数1、2、3,每报到3的人退出圈子。编程使用链表找出最后留下的人。 bug版本 #include <stdio.h>#include <stdlib.h>struct player { long numstruct player *next}typedef struct player NODENODE *create(int n) { NODE *head, *tail, *pint i =
继续访问
c语言圈中的游戏,C语言实现扫雷游戏
本文将介绍如何用C语言多文件编程实现扫雷该示例扫雷程序可实现以下几个功能:自定义雷数踩雷后会将所有雷显示出来地图大小易修改Mine_clearance.h#pragma once#define _CRT_SECURE_NO_WARNINGS#include#include#include#define ROW 11#define COL 11#define 踩雷 0#define 玩家胜利 1in...
继续访问
c语言程序设计求各位数之和,C语言for回圈设计输入一个正整数,求它的各位数字之和及位数 例如234的各位数之和为9 位数是3...
C语言for回圈设计输入一个正整数,求它的各位数字之和及位数 例如234的各位数之和为9 位数是3以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!C语言for回圈设计输入一个正整数,求它的各位数字之和及位数 例如234的各位数之和为9 位数是3同意二楼,但得改一下#includeint main(int argc, ch...
继续访问
c语言draw函数使用实例,使用函数实现两个数的交换(C语言)
<>题目:使用函数实现两个数的代码<>常规思路:定义函数,调用函数,完成交换。你的代码是否和下面一样呢?#include #include void Swap(int a,int b) { int tmp = aa =bb = tmp} int main() { int x = 10int y = 20Swap(x,y)printf("%d %d\n...
继续访问
圈中的游戏 c语言,圈叉棋小游戏的简单实现代码
该楼层疑似违规已被系统折叠隐藏此楼查看此楼#include int game[3][3]={0}void Show(int turn,int x,int y){int i=0,j=0if(x>0 &&y>0){if(turn%2){game[x-1][y-1]=1}else{game[x-1][y-1]=-1}}for(i=0i<3++i){for...
继续访问
c语言圈中的游戏,圈叉棋小游戏的简单实现代码
该楼层疑似违规已被系统折叠隐藏此楼查看此楼#include int game[3][3]={0}void Show(int turn,int x,int y){int i=0,j=0if(x>0 &&y>0){if(turn%2){game[x-1][y-1]=1}else{game[x-1][y-1]=-1}}for(i=0i<3++i){for...
我这边有代码是JSP的
你试验一下
需要有JSP环境,我试验了下,可以玩!
<HTML>
<head>
<meta http-equiv="Content-Type" content="text/htmlcharset=gb2312">
<title>贪吃蛇</title>
</head>
<STYLE>
.Food { background-color: green}
.Snake {background-color: red}
.grid {border:1px solid #000}
</STYLE>
<SCRIPT langyage="javascript">
var Rows=10
var Cells=15
var Num=20 //正方形格子的边长
var BorderWidth=5
var SpeedUp=5000
//创建地图
function CreateMap()
{
BW = eval(Cells*Num + 2*BorderWidth) //宽度
BH = eval(Rows*Num + 2*BorderWidth) //高度
document.body.innerHTML+='<div id=MainMap style=position:absoluteleft:'+(document.body.clientWidth-BW)/2+'top:'+(document.body.clientHeight-BH)/2+'width:'+BW+'height:'+BH+'border-width:'+BorderWidth+'border-style:outsetborder-color:#0000ff></div>'
Map = new Array() //创建全局数组Map[]
for(y=0y<Rowsy++)
{
Map[y]=new Array() //创建全局二维数组Map[][],初始值为'0'
for(x=0x<Cellsx++)
Map[y][x] = '0' //'0'值表示“空地”
}
//ShowGrid() //显示地图内格子
Sx = parseInt(Math.random()*Cells) //创建全局变量Sx,赋予随机数
Sy = parseInt(Math.random()*Rows) //创建全局变量Sy,赋予随机数
CreateSnake() //生成蛇 - div
CreatFood()//生成食物 - span
AllDiv = MainMap.all.tags('DIV') //创建全局数组AllDiv,只有一个元素AllDiv[0]。MainMap是div的ID
AllSpan = MainMap.all.tags('SPAN') //创建全局数组AllSpan,只有一个元素AllSpan[0]
}
//显示地图内格子
function ShowGrid()
{
for(r=0r<Rowsr++) //行
{
t = r*Num
for(c=0c<Cellsc++) //列
{
l = c*Num
MainMap.innerHTML += '<table style="position:absoluteleft:'+ l +'top:'+ t +'width:'+Num+'height:'+Num+'" cellpadding=0 cellspacing=0><tr><td align=center valign=middle class=grid>O</td></tr><table>'
}
}
}
//创建蛇的初始位置,赋予初始值'S'
function CreateSnake()
{
//<div>表示蛇身,通过调用本函数,可以累加到若干个,蛇身变长
//注意 y 和 x 是“蛇”<div>的自定义属性。一直保存着蛇尾(!)的当前位置
//初始时,蛇头、蛇尾是同一个位置
MainMap.innerHTML += '<div x='+Sx+' y='+Sy+' style=position:absoluteleft:'+Sx*Num+'top:'+Sy*Num+'width:'+Num+'height:'+Num+'overflow:hidden class=Snake></div>'
Map[Sy][Sx]='S' //Snake首字母
}
//创建食物的位置,赋予初始值'F'
//食物的初始位置不能与蛇的初始位置相同,只能在空地放置食物。
//若随机产生的2位置相同,则递归执行,直到不相同为止
function CreatFood()
{
Fx = parseInt(Math.random()*Cells)
Fy = parseInt(Math.random()*Rows)
if(Map[Fy][Fx]=='0') //如果是空地
{
MainMap.innerHTML += '<span style=position:absoluteleft:'+Fx*Num+'top:'+Fy*Num+'width:'+Num+'height:'+Num+'overflow:hidden class=Food></span>'
Map[Fy][Fx]='F' //Food首字母
}
else
CreatFood() //递归
}
//主移动--判断蛇头前面的是什么
function Move()
{
Sx += GoX //自动行走,Map[Sy][Sx]为当前位置
Sy += GoY
if(Sy<0||Sy>=Rows) //碰墙,重新开始
Move1()
else
{
SnakeFront = Map[Sy][Sx]
if(SnakeFront=='0') //蛇前是空地
Move2()
else
{
if(SnakeFront=='F') //蛇前面是食物
Move3()
else
Move1()
}
}
}
//重新开始
function Move1()
{
if(confirm("Game Over,重新开始?"))
window.location.reload()
}
var Times=200
//蛇行走到的当前位置是空地时
function Move2()
{
Map[AllDiv[0].y][AllDiv[0].x]='0' //蛇走开后,把原位置设置为'0',表示是空地
AllDiv[0].removeNode(true) //把蛇数组当前元素删除,在下面的 CreateSnake()语句重新生成
CreateSnake() //在新的位置生成蛇的<div>
setTimeout('Move()',Times) //再次移动
}
//蛇行走到的当前位置是食物时
function Move3()
{
CreateSnake() //蛇数组当前元素不删除,<div>累加一次,蛇长长一节
AllSpan[0].removeNode(true) //把食物数组当前元素删除,在下面的 CreatFood()语句重新生成
CreatFood() //再次随机生成食物
setTimeout('Move()',Times) //再次移动
}
//蛇越行越快
function oTimes()
{
Times -= 5
if(Times>5)
setTimeout('oTimes()', SpeedUp)
}
document.onkeydown=KeyDown
//方向
function KeyDown()
{
Key=event.keyCode
switch(Key){
case 37:
Dir(-1,0)break //左方向键
case 39:
Dir(1,0)break //右方向键
case 38:
Dir(0,-1)break //上方向键
case 40:
Dir(0,1)break} //下方向键
return false
}
var Star=0
function Dir(x,y)
{
GoX=x
GoY=y
if(Star==0)
{
oTimes()
Star=1
Move()
}
}
//页面打开时运行
onload = CreateMap //注意无"()",不是 CreateMap()
//在<body>中调用的语法是:<BODY onload="CreateMap()">,必须加"()"
</SCRIPT>
<BODY>
<div id="help">
红色方块表示蛇,绿色方块表示食物。按方向键开始。<br>
</div>
</BODY>
</HTML>