开篇先说一句废话····
本旺名字叫萨摩耶,,Please 叫我旺财,,,哈哈,招财进宝嘛!
今天整理电脑的时候,发现之前学习过程中写了一个小游戏—贪吃蛇,这个游戏是我学习C语言时写的第一个小项目吧,想着打开玩玩呢······
感觉很有文艺范嘛·····
先简单说一下,贪吃蛇游戏,,,,,,,,,,谁都玩过,有的人甚至大神,可是到了我们学习编程的孩纸来讲,我们的仔细的了解游戏才能写出来呢,,,
先得分析一下吧
贪吃蛇游戏里只有两种东西------蛇和食物。
而蛇有哪些属性呢?蛇的长度(节数) 方向 每节蛇的坐标 ;
//方向
enum CH {
up=87,
left=65,
down=83,
right=68
};
struct Coor{ //坐标
int x;
int y;
};
struct Snake{ //蛇
int num; //节数
struct Coor xy[MAX]; //每节蛇的坐标
char ch;
}snake;
食物呢? 坐标 标志(是否被吃)。
struct Food {
Coor ch; //坐标
int flag; //标志 是否被蛇吃掉
int grade; //成绩
}food;
接下来······· 既然定义了,,那就得先给蛇初始化一下嘛。。
初始化蛇
void InitGame() {
//初始化界面
initgraph(640,480);
//初始化蛇
snake.num = 3;
snake.xy[2].x = 10;
snake.xy[2].y = 10;
snake.xy[1].x = 20;
snake.xy[1].y = 10;
snake.xy[0].x = 30;
snake.xy[0].y = 10;
snake.ch = right;
//初始化食物
food.flag = 0;
food.grade = 0;
}
初始化之后呢,先得在初始化界面里能显示蛇,,所以就有了绘画蛇了···
绘画蛇
而蛇在移动时,为了区分蛇头和蛇身,所以用不同的颜色来表示,蛇头只有一个,直接画,蛇身有好几节,用for循环来遍历,遍历多少就要用蛇结构体里 num 成员了。。。代码如下:
//绘画蛇
void DrawSnake() {
for (int i = 0; i < snake.num; i++) {
if (i==0) { //蛇头为绿色
setlinecolor(GREEN);
setfillcolor(GREEN);
fillroundrect(snake.xy[i].x, snake.xy[i].y, snake.xy[i].x + 10, snake.xy[i].y + 10, 10, 10);
}
else { //蛇身为黄色
setlinecolor(GREEN);
setfillcolor(YELLOW);
fillroundrect(snake.xy[i].x, snake.xy[i].y, snake.xy[i].x + 10, snake.xy[i].y + 10, 10, 10);
}
}
}
绘画完,蛇在窗口显示了,接下来就是移动蛇了,,
移动蛇
在移动过程中呢,是先动蛇头还是先动蛇身呢?注意的是:编程里面,蛇的坐标是用数据储存的,而移动就是遍历这些数据,所以移动蛇就是先移动蛇身,在移动蛇头 ,
怎么移动蛇呢??如图
且看代码
//蛇的移动
void MoveSnake() {
//蛇身的移动
for (int i = snake.num-1; i >0;i--) {
snake.xy[i].x = snake.xy[i-1].x;
snake.xy[i].y = snake.xy[i-1].y;
}
//蛇头的移动
switch (snake.ch) {
case up:
snake.xy[0].y -= 10;
break;
case down:
snake.xy[0].y += 10;
break;
case left:
snake.xy[0].x -= 10;
break;
case right:
snake.xy[0].x += 10;
break;
};
}
在游戏中呢,蛇除了会移动,还要改变方向来找食物。。。
改变蛇的方向
其实就是改变蛇头的坐标嘛,然后让把坐标赋给蛇身,依次画出就改变方向了嘛,,
这会就要依靠输入来控制了,先定义一个move来储存键盘的输入,然后用多分支选择来改变蛇头的坐标就好了。。。。
代码如下:
//改变蛇的方向
void ChangeSnake() {
char move;
move = _getch();
switch (move) {
case 87:if (snake.ch != down)
snake.ch = up; break;
case 65:if (snake.ch != right)
snake.ch = left; break;
case 83:if (snake.ch != up)
snake.ch = down; break;
case 68:if (snake.ch != left)
snake.ch = right; break;
default: break;
};
}
到这会,蛇就OK了,接下来就到了食物了,,,因为食物是随机出现的,就要用到随机数的产生了。。。。rand()函数。。而因为蛇在绘画中用10来表示蛇的每节蛇的长度,在移动时坐标都是能被10给整除,若想在之后的蛇吃食物的时候能成功的吃到食物,食物的坐标也要能被10整除,,,
事物的坐标获取到了,就要把食物画到窗口里了,,(和绘画蛇是一样的)
代码:
//获取食物的坐标
void CoorFood() {
if (food.flag == 0) {
food.ch.x = rand() % 64 * 10;
food.ch.y = rand() % 48 * 10;
}
}
//绘画食物
void DrawFood() {
setlinecolor(RED);
setfillcolor(RED);
fillroundrect(food.ch.x, food.ch.y, food.ch.x + 10, food.ch.y + 10, 10, 10);
food.flag = 1; //表示食物没有被吃
}
蛇和食物都完成了,接下来就是判断蛇要吃没吃到食物了,,怎么算是迟到了呢,,
当蛇头的坐标和食物的坐标相等了,是不时食物就被吃了
//蛇吃掉食物
void EatFood() {
//当蛇头的坐标等于食物的坐标的时候,表示蛇吃掉食物
if (snake.xy[0].x==food.ch.x && snake.xy[0].y==food.ch.y) {
food.flag = 0; //食物被吃
snake.num++; //蛇的节数加1
food.grade += 10; //成绩加10
}
}
吃食物完成了,那么剩下最后一个条件了,就是蛇怎么就死了呢??
第一,蛇头碰到墙壁
第二,蛇头碰到自己,自己被吃了呢,,,
碰到墙壁: 只需要用if判断蛇头的坐标和墙壁的坐标的关系就可以了
碰到自己:就要使用for循环来遍历坐标,判断蛇头和蛇身的坐标是否相等
//游戏规则
void Rule() {
char grade[100];
sprintf_s(grade,"%d",food.grade);
//蛇头碰到墙壁时,蛇死亡 --- 蛇头坐标等于墙壁坐标时,蛇死亡!
if (snake.xy[0].x < 0 || snake.xy[0].x > 630 || snake.xy[0].y < 0 || snake.xy[0].y > 470) {
outtextxy(145, 200, "分数:");
outtextxy(250, 200, grade);
outtextxy(140, 340, "你碰到了墙壁,已经死亡,游戏结束!!!按回车继续···");
MessageBox(0, "贪食蛇,要命的就在一个“贪”字上。所以,有时候真的需要及时收手,不要逼人太甚。如果没有余地,就算你的手再快,面临的结局也是——崩盘。", "Warning", 0);
getchar();
main();
}
//蛇头碰到自己身体时,蛇死亡 --- 蛇头坐标等于蛇身坐标时,蛇死亡!
for (int i = 1; i < snake.num;i++) {
if (snake.xy[0].x == snake.xy[i].x && snake.xy[0].y == snake.xy[i].y) {
outtextxy(145, 200, "分数:");
outtextxy(250, 200, grade);
outtextxy(140, 340, "你咬死了自己,已经死亡,游戏结束!!!按回车继续···");
MessageBox(0, "人生如同贪食蛇,丝毫大意不得,除非你在风风雨雨中玩得累了,不想继续了,那好,干脆关机,洗洗睡吧。", "Warning", 0);
getchar();
main();
}
}
//没有以上情况游戏继续
}
这是基本功能,读者也可以自行添加其他的功能,比如:分数排行榜,或者一些游戏的说明等等·········
写代码时搜索到的东西
现实中,我们何尝不是这样呢,,,,还有很好的一句话就是(贪吃蛇里),当我们还小的时候敢加速横冲直撞,等我们成长到一定程度之后,我们不在加速,不在“赌博”,,我们从最初的游戏体验到后来的功利心,也许这就是成长吧。。
终结语
希望这些代码可以帮助到你,
希望我们不要忘记自己的那份初心