贪吃蛇(简易版)

一、引言

为了提高自己的代码能力和复习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版本

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂java杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值