一、引言
为了提高自己的代码能力和复习C语言语法规则。学习和实现了贪吃蛇简易版,有一定的收获,记录一下学习过程和待改善点。非常适合c语言入门实践,建议收藏学习。
二、学习过程
首先思考几个问题
- 蛇身用什么数据结构存储?
- 这儿采用数组
- 大致的逻辑是怎么样的?
- (1) 初始化,界面,蛇,随机块
- (2) 判断蛇头是否与食物坐标重合,从而产生食物
- (3) 获取移动速度,同时调整
- (4) 改变蛇的方向
- (5) 蛇死亡的判断
- 蛇是如何实现移动的?
- 如何判断游戏结束?
- 如何判断自食?
1、基本原理
对于这样一个游戏,需要搞清楚蛇是如何实现移动的?如何打印?即使用gotoxy方法找到光标位置打印实现的。打印蛇头然后打印蛇身即可。
2、操作说明
使用wasd来操作上左下右
3、待改善点
(1)每次打开得按一下shift切换成英文才能玩
(2)可以改为使用方向键控制,需要读取两次才能读到方向键对应的ASCII码
(3)不能按回头键
4、可执行代码
/**************************************************************************************************************
**文件:snake.c
**编写者:咸鱼
**编写日期:2021年4月22号
**简要描述:贪吃蛇简易版。
**注:在VC6.0环境下能正常运行。
**控制台:Code::Blocks 17.12
**************************************************************************************************************/
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <conio.h>
#define ui_width 40
#define ui_height 20
#define UP 'w'
#define DOWN 's'
#define LEFT 'a'
#define RIGHT 'd'
//snake
struct Snake{
int x[50];
int y[50];
//长度
int len;
int speed;
}snake;//snake[0]即为蛇头
//food 设置食物的坐标
struct Food{
int x;
int y;
}food;
/*
所需函数声明
1、蛇头坐标与食物坐标重复与否,产生食物
2、获取移动速度
3、移动蛇
4、死亡判断
*/
//初始化
void init(void);
//蛇头坐标与食物坐标重复与否,产生食物
void generate_food(void);
//速度控制
void speed_control(void);
//移动蛇
void snake_moving(void);
//死亡判断,返回死亡与否的状态
int is_death(void);
void gotoxy(int x, int y);
//全局变量
int i,j,k;
char ch = UP;
int grow = 0;
//光标移动
void gotoxy(int x, int y)
{
HANDLE hout;//那么pos其实是一个结构体变量,其中X和Y是它的成员,
//通过修改pos.X和pos.Y的值就可以实现光标的位置控制。
COORD cor;//坐标
hout=GetStdHandle(STD_OUTPUT_HANDLE);//标准输出句柄,包含在windows.h中
cor.X=y;//调整坐标
cor.Y=x;
SetConsoleCursorPosition(hout,cor);
}
int main(){
//初始化
init();
while(1){
generate_food();
speed_control();
Sleep(snake.speed);//延迟出现蛇的每一部分,从而达到调整速度效果
snake_moving();
if(!(is_death())){
break;
}
}
printf("GAME OVER!");
getch();
return 0;
}
void init(){
//初始化随机发生器
srand(time(NULL));
//初始化食物位置,在游戏窗口内
food.x = rand()%(ui_height-2)+1;
food.y = rand()%(ui_width-2)+1;
gotoxy(food.x,food.y);
printf("!");
//蛇初始位置
snake.x[0]=ui_height/2;
snake.y[0]=ui_width/2;
gotoxy(snake.x[0],snake.y[0]);
printf("@");
snake.len = 3;
snake.speed = 200;
for(k=1;k<snake.len;k++){
snake.x[k] = snake.x[k-1]+1;
snake.y[k] = snake.y[k-1];
gotoxy(snake.x[k],snake.y[k]);
printf("@");
}
//初始化地图
for(i = 0;i<ui_width;i++){
gotoxy(0,i);
printf("#");
gotoxy(ui_height-1,i);
printf("#");
}
for(j = 0;j<ui_height;j++){
gotoxy(j,0);
printf("#");
gotoxy(j,ui_width-1);
printf("#");
}
}
void snake_moving(){
if(kbhit()){//接受键盘的输入,如果有输入则读到ch中
ch = getch();
}
if(!grow){
//如果没有变长,先清除尾巴,采用" "的方式
gotoxy(snake.x[snake.len-1],snake.y[snake.len-1]);
printf(" ");
}
//蛇身连接
for(k = snake.len-1;k>0;k--){
snake.x[k] = snake.x[k-1];
snake.y[k] = snake.y[k-1];
}
//判断蛇头位置是否发生变化
switch(ch){
case UP:
snake.x[0]--;break;
case DOWN:
snake.x[0]++;break;
case LEFT:
snake.y[0]--;break;
case RIGHT:
snake.y[0]++;break;
default: break;
}
//蛇头定位
gotoxy(snake.x[0],snake.y[0]);
printf("@");
//
grow = 0;
gotoxy(ui_height,0);//每次移动光标都在这个位置,防止影响游戏体验,如果去掉这句话会怎么样?
}
void generate_food(){
//将被吃掉的食物清空
if(snake.x[0]==food.x&&snake.y[0]==food.y){
snake.len++;
grow = 1;
gotoxy(food.x,food.y);
printf(" ");
//初始化随机发生器
srand(time(NULL));
//初始化食物位置,在游戏窗口内
food.x = rand()%(ui_height-2)+1;
food.y = rand()%(ui_width-2)+1;
gotoxy(food.x,food.y);
printf("!");
}
}
void speed_control(){
if(snake.len<6) snake.speed = 200;
else if(snake.len<12) snake.speed = 100;
else if(snake.len<24) snake.speed = 50;
else if(snake.len<33) snake.speed = 30;
else snake.speed = 20;
}
int is_death(){
if((snake.x[0] == 0)||(snake.x[0] == ui_height-1)||(snake.y[0] == 0)||(snake.y[0] == ui_width-1))
return 0;
for(int s=1;s<snake.len;s++){
if(snake.x[s] == snake.x[0] && snake.y[s] == snake.y[0])
return 0;
}
return 1;
}
5、参考
https://blog.csdn.net/liutong123987/article/details/79274274
6、学习计划
(1)改善点
(2)转战Java版本