百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

C语言零基础项目:贪吃蛇!详细思路+源码分享

ztj100 2024-10-29 18:21 11 浏览 0 评论

每天一个C语言小项目,提升你的编程能力!

贪吃蛇游戏大家应该都不陌生了,要说没玩过的话,可能你是15后吧?

贪吃蛇游戏最初为单机模式,后续又陆续推出团战模式、赏金模式、挑战模式等多种玩法。

用游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。

贪吃蛇的唯一的目标就是长成最长的一条蛇!滑动摇杆控制小蛇走位,吃掉地图上彩色的小圆点,就会变长。

效果展示:

改变此款游戏的特别多。比如在蛋的方面,可能放上带道具的蛋,使蛇吃完后具有保护,穿墙等特种功能,而且难度逐渐变难。如果有编程技术比较强大的伙伴也可以去尝试一下哦!做出一个趋近完美的贪吃蛇那可就是能力的展现啦~

本项目编译环境:Visual Studio 2019/2022,EasyX插件

代码展示:

#include <graphics.h> 
#include <stdio.h>
#include <conio.h>
#include <time.h>
#define UP    1
#define DOWN  2
#define LEFT  3
#define RIGHT  4
////////////////////////////////////////////
//格子类,定义一个格子的属性及行为
////////////////////////////////////////////
class Cell
{
public:

  friend class GameArea;  //设置友元函数
?
  void setxy(short x, short y)   //设置格子左上角坐标
{
    m_x = x, m_y = y;
  }
  void setfull(short full)  //设置格子属性,0为空,1为障碍,2为食物
{
    m_full = full;
  }
  void display(COLORREF color)  //设置格子颜色并显示
{
    m_color = color;
    setfillstyle(m_color);
    bar(m_x, m_y, m_x+7, m_y+7);
  }
  void LaserDisplay()  //显示镭射状态的格子
{
    IMAGE image(10,10);
    SetWorkingImage(&image);
    DWORD* pMem = GetImageBuffer(&image);
    for(int i = 0; i < 10 * 10; i++)
    pMem[i] = BGR(RGB(0, 0, i * 256 / (10*10) ));
    SetWorkingImage(NULL);
    putimage(m_x,m_y,&image);
  }
  short ReturnFull()  //返回格子状态
{
    return m_full;
  }
  Cell()  //构造函数
  {
    m_x = 0,m_y = 0,m_full = 0;
    m_color = BLACK;
  }
?
private:
?
  short m_x;      //格子的左上角X坐标
  short m_y;      //格子的左上角Y坐标
  short m_full;    //0为空,1为阻挡,2为食物
  COLORREF m_color;  //格子颜色
};
////////////////////////////////////////////
//游戏区类,编写有关游戏区的一些操作
////////////////////////////////////////////
class GameArea  //游戏区域
{
public:
?
  Cell m_game[60][60];      //定义游戏区域(由360个格子组成)
?
  friend void MessageDispose();  //设置友元函数
?
  bool CreatFood()        //产生随机食物
{
    srand(time(NULL));      //初始化随机数种子
    m_random1 = rand()%58+1;    //随机生成一个0 - 58的整数
    m_random2 = rand()%58+1;    //随机一个0 - 58的整数
    if(m_game[m_random2][m_random2].m_full == 0)  //检查生成的食物坐标是否在障碍上
    {
      m_game[m_random1][m_random2].display(GREEN);
      m_game[m_random1][m_random2].m_full = 2;
      return true;
    }
    //如果随机的食物正好出现在蛇身上,则进入下面的循环寻找可以生成食物的地方
    for(m_random1 = 1;m_random1 < 59;m_random1++)
    {
      for(m_random2 = 1;m_random2 < 59;m_random2++)
      {
        if(m_game[m_random2][m_random2].m_full == 0)
        {
          m_game[m_random1][m_random2].display(GREEN);
          m_game[m_random1][m_random2].m_full = 2;
          return true;
        }
      }
    }
    //如果没有找到可以生成食物的地方,则通关
    return false;  //返回false即表示通关
  }
  void DelFood()  //删除食物
{
    m_game[m_random1][m_random2].m_full = 0;  //设置为0即代表格子属性为空
  }
    void ChangeColor(int flag1,int flag2,COLORREF color)  //设置指定格子的颜色
{
    m_game[flag1][flag2].display(color);
  }
  void Init()          //初始化GAME区域
{
    int flag1,flag2;    //标识变量
    BeginBatchDraw();    //开始批量绘图
    setfillstyle(BLACK);  //设置当前颜色
    bar(0,0,600,600);    //画无边框填充矩形(在这里的用途是用黑色清空游戏区域)
    for(flag1 = 0;flag1 < 60;flag1++)
    {
      for(flag2 = 0;flag2 < 60;flag2++)
      {
        if(flag1 == 0 || flag1 == 59 || flag2 == 0 || flag2 == 59)  //创建边界
        {                       
          m_game[flag1][flag2].setfull(1);
          m_game[flag1][flag2].setxy(flag1*10,flag2*10);
          m_game[flag1][flag2].display(RGB(237,28,36));
        }
        else                            //创建游戏区域
        {
          m_game[flag1][flag2].setfull(0);
          m_game[flag1][flag2].setxy(flag1*10,flag2*10);
          m_game[flag1][flag2].display(BLACK);
        }
      }
    }
    CreatFood();
    EndBatchDraw();
  }
?
private:
?
  int m_random1, m_random2;
};
////////////////////////////////////////////
//蛇类,定义蛇的数据结构以及蛇的行为
////////////////////////////////////////////
class Snake
{
public:
?
  int toward;    //蛇头朝向  
  friend void MessageDispose();
  friend int HitDetect();
  friend void ReInit(); 
  Snake()
  {
    head = NULL;
    last = NULL;
    now  = NULL;
  }
  void Init()      //初始化蛇的结构
{
    if(head!=NULL)  //重玩游戏时,释放原先的链表所有结点
    {
      for(now = head->next;now->next != NULL;now = now->next)
      {
        free(now->prior);
      }
    }
    head = (struct node*)malloc(sizeof(struct node));  //为蛇头分配内存
    head->prior = NULL;
    head->m_x = 300;
    head->m_y = 300;
    now = (struct node*)malloc(sizeof(struct node));
    head->next = now;
    now->prior = head;
    now->next = NULL;
    now->m_x = 300;
    now->m_y = 290;
    last = now;
    toward = DOWN;
  }
  void SnakeAdd()
{
    now = head;      //当前指向蛇头
    now->prior = (struct node*)malloc(sizeof(struct node));  //为新增的结点分配内存
    now = now->prior;  //让当前指向新分配的结点
    now->prior = NULL;  //置空当前结点的前趋
    now->next = head;  //让当前结点的后继指向蛇头
  
    switch(toward)    //根据当前蛇头方向确定新增部分的坐标
    {
    case UP:
      now->m_x = head->m_x;
      now->m_y = head->m_y -10;
      break;
      case DOWN:
      now->m_x = head->m_x;
      now->m_y = head->m_y + 10;
      break;
    case LEFT:
      now->m_x = head->m_x - 10;
      now->m_y = head->m_y;
      break;
    case RIGHT:
      now->m_x = head->m_x + 10;
      now->m_y = head->m_y;
      break;
    }
    head = now; //设置当前结点为蛇头
?
  }
  void SnakeDel()    //释放蛇尾结点(删除蛇尾)
{
    last = last->prior;
    free(last->next);
    last->next = NULL;
  }
  void SnakeMove()  //蛇身移动一格
{
    SnakeAdd();    //增加蛇头
    SnakeDel();    //删除蛇尾
  }
?
private:
?
  struct node         //蛇身链表
  {
    int m_x;
    int m_y;
    struct node *next;  //下个结点
    struct node *prior; //上个结点
  };
  struct node *head;
  struct node *last;
  struct node *now;
};
////////////////////////////////////////////
//游戏类,用来初始化游戏的参数,及实现其他游戏操作
////////////////////////////////////////////
class Game
{
public:
?
  void Init()
{
    closegraph();
    initgraph(800,600);
    setbkmode(TRANSPARENT);          //设置输出文字背景为透明
    LOGFONT f;
    getfont(&f);              // 获取当前字体设置
    f.lfHeight = 50;            // 设置字体高度为 48(包含行距)
    _tcscpy(f.lfFaceName, _T("黑体"));    // 设置字体为“黑体”
    f.lfQuality = ANTIALIASED_QUALITY;    // 设置输出效果为抗锯齿  
    setfont(&f);              // 设置字体样式
  }
  void FailGame()  //游戏失败显示的画面
{
    setcolor(RED);
    setfont(70, 0, _T("微软雅黑"));
    outtextxy(150, 265, _T("YOU LOSE!"));
  }
  void WinGame() //游戏胜利时显示的画面
{
    setcolor(RED);
    setfont(70, 0, _T("微软雅黑"));
    outtextxy(150, 265, _T("YOU WIN!"));
    FlushBatchDraw();
    Sleep(10000);
    exit(0);
  }
};
////////////////////////////////////////////
//管理区类,定义管理区域的相关操作
////////////////////////////////////////////
class ManageArea  
{
public:
?
  friend void MessageDispose();
?
  void TimeAdd(double add)  //增加时间(可在类外直接调用实现动态刷新时间)
{
    m_time += add;
    DisplayTime();
  }
  void ScoreAdd(short add)  //增加分数(可在类外直接调用实现动态刷新分数)
{
    m_score += add;
    DisplayScore();
  }
  void DisplayPause()      //显示暂停或者开始
{
    BeginBatchDraw();
    _stprintf(m_str_score, _T("%d"), m_score);
    setfont(25, 0, _T("微软雅黑"));
    setfillstyle(m_bgcolor);
    bar(625,490,800,515);
    setcolor(BLUE);
    if(m_pause)
    outtextxy(625, 490, _T("开始(P键)"));
    else
    outtextxy(625, 490, _T("暂停(P键)"));
    EndBatchDraw();
  }
  void Init()  //初始化管理界面
{
    m_time = 0.0;
    m_score = 0;
    m_leave = 1;
    m_pause = false;
    _stprintf(m_str_score, _T("%d"), m_score);  //格式化转换类型
    _stprintf(m_str_time, _T("%.1lf"), m_time);
    m_bgcolor = BLACK;
    BeginBatchDraw();
    setfillstyle(BLACK);
    bar(601,0,800,600);
    setfont(60, 0, _T("微软雅黑"));
    setcolor(GREEN);
    outtextxy(625, 30, _T("贪吃蛇"));
    setfont(30, 0, _T("微软雅黑"));
    setcolor(RGB(128,0,255));
    outtextxy(625, 140, _T("制作:轻雨漫步"));
    setfont(25, 0, _T("微软雅黑"));
    setcolor(BLUE);
    outtextxy(625, 430, _T("时间:"));
    outtextxy(625, 460, _T("分数:"));
    outtextxy(625, 490, _T("暂停(P键)"));
    outtextxy(625, 520, _T("重新游戏(R键)"));
    setcolor(RED);
    outtextxy(720, 400, m_str_leave);
    outtextxy(680, 460, m_str_score);
    outtextxy(680, 430, m_str_time);
    EndBatchDraw();
  } 
?
private:
?
  double  m_time;
  short  m_score;
  short  m_leave;
  bool  m_pause;
  TCHAR  m_str_leave[2], m_str_time[33], m_str_score[5];  
  COLORREF m_bgcolor;
?
  void DisplayTime()  //显示当前耗时
{
    BeginBatchDraw();
    _stprintf(m_str_time, _T("%.1lf"), m_time);
    setfont(25, 0, _T("微软雅黑"));
    setfillstyle(m_bgcolor);
    bar(680,430,800,455);
    setcolor(RED);
    outtextxy(680,430,m_str_time);
    EndBatchDraw();
  }
  void DisplayScore()  //显示当前分数
{
    BeginBatchDraw();
    _stprintf(m_str_score, _T("%d"), m_score);
    setfont(25, 0, _T("微软雅黑"));
    setfillstyle(m_bgcolor);
    bar(680,460,800,485);
    setcolor(RED);
    outtextxy(680,460,m_str_score);
    EndBatchDraw();
  }
};
?
?
////////////////////////////////////////////
//声明游戏需要的类
////////////////////////////////////////////
?
Game    game;    //用于初始化游戏、设置游戏相关参数
GameArea  a;      //用于初始化游戏区域,设置,改变游戏区域相关参数
ManageArea  manager;  //用于初始化管理区域,设置管理区相关参数
Snake    s;      //用于初始化蛇,数据化蛇,操作蛇
?
////////////////////////////////////////////
//游戏的消息控制,流程控制函数
////////////////////////////////////////////
void MessageDispose()  //消息处理函数
{
  char c;
  s.now = NULL;
  bool Keepdown = false;
?
  while(true)
  {
    Keepdown = false;  //是否持续按W A S D 中的一个按键
    if(kbhit())
    {
      switch(c = getch())  //处理按键消息(W A S D)
      {
      case 'w':
      case 'W':      
        if(s.toward == UP)Keepdown = true;
        else if(s.toward != DOWN&&s.toward != UP)s.toward = UP;
        break;
      case 's':
      case 'S':
        if(s.toward == DOWN)Keepdown = true;
        else if(s.toward != UP&&s.toward != DOWN)s.toward = DOWN;
        break;
      case 'a':
      case 'A':
        if(s.toward == LEFT)Keepdown = true;
        else if(s.toward != RIGHT&&s.toward != LEFT)s.toward = LEFT;
        break;
      case 'd':
      case 'D':
        if(s.toward == RIGHT)Keepdown = true;
        else if(s.toward != LEFT&&s.toward != RIGHT)s.toward = RIGHT;
        break;
      case 'p':
      case 'P':
        manager.m_pause = !manager.m_pause;  //设置暂停或开始
        manager.DisplayPause();  //显示暂停或开始
        break;
      case 'r':
      case 'R':
        ReInit();
        break;
      }
    }
    if(true == manager.m_pause)  //如果暂停,直接进行下次循环
    {
      continue;
    }
    BeginBatchDraw();
    switch(a.m_game[s.head->m_x/10][s.head->m_y/10].ReturnFull())  //检测蛇头遇到的情况
    {
    case 2:        //遇到食物,蛇身加长
      a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE);
      s.SnakeAdd();  //蛇增长
      a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE);
      a.DelFood();  //删除食物
      if(a.CreatFood() == false)  //创建新食物,并检查是否通关
      {
        game.WinGame();      //游戏通关(当地图没地方创建食物时)
      }
      manager.ScoreAdd(1);    //加一分
      break;
    case 0:
      a.m_game[s.last->m_x/10][s.last->m_y/10].setfull(0);        //设置蛇尾经过处无障碍
      a.ChangeColor(s.last->m_x/10,s.last->m_y/10,BLACK);
      s.SnakeMove();  //蛇移动一次
      a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE);
      a.m_game[s.head->next->m_x/10][s.head->next->m_y/10].setfull(1);  //设置蛇头经过处有障碍
      break;
    case 1:        //遇到障碍物
      game.FailGame();
      a.ChangeColor(s.head->m_x/10,s.head->m_y/10,RGB(255,127,39));
      FlushBatchDraw();
      {
        char c = ' '; 
        while(c != 'r' && c != 'R')  //当游戏失败时,按R键可重新进行游戏
        {
          if(kbhit())
          {
            c = getch();
          }
          Sleep(10);
        }
      }
      ReInit(); //重新开始游戏
      break;
    }
    EndBatchDraw();
    if(Keepdown==false)
    {
      Sleep(100);
      manager.TimeAdd(0.1);  //增加时间
    }
    else            //当持续按下按方向键时
    {
      Sleep(40);        //适当休眠可以增加游戏流畅性
      manager.TimeAdd(0.04);  //增加时间
    }
  }
}
////////////////////////////////////////////
//游戏初始化函数
////////////////////////////////////////////
void ReInit()
{
  a.Init(); //初始化游戏区
  s.Init();  //初始化蛇
  manager.Init();  //初始化管理区
  //绘制蛇的开始状态
  s.now = s.head;
  a.ChangeColor(s.now->m_x/10,s.now->m_y/10,BLUE);
  s.now = s.last;
  a.ChangeColor(s.now->m_x/10,s.now->m_y/10,BLUE);
}
////////////////////////////////////////////
//main函数,程序入口
////////////////////////////////////////////
int main(void)
{
  game.Init();    //初始化游戏参数、设置
  ReInit();      //初始化其他
  MessageDispose();  //消息处理函数
?
  return 0;
}?

大家赶紧去动手试试吧!

此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到C语言C++项目案例,帮助大家在学习C语言的道路上披荆斩棘!

编程学习书籍分享:

编程学习视频分享:

整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)最重要的是你可以在里面交流提问编程问题哦!

对于C/C++感兴趣可以关注小编在后台私信我:【编程交流】一起来学习哦!可以领取一些C/C++的项目学习视频资料哦!已经设置好了关键词自动回复,自动领取就好了!

相关推荐

从IDEA开始,迈进GO语言之门(idea got)

前言笔者在学习GO语言编程的时候,GO语言在国内还没有像JAVA/Php/Python那样普及,绕了不少的弯路,要开始入门学习一门编程语言,最好就先从选择一个好的编程语言的开发环境开始,有了这个开发环...

基于SpringBoot+MyBatis的私人影院java网上购票jsp源代码Mysql

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目介绍基于SpringBoot...

基于springboot的个人服装管理系统java网上商城jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目介绍基于springboot...

基于springboot的美食网站Java食品销售jsp源代码Mysql

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目介绍基于springboot...

贸易管理进销存springboot云管货管账分析java jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目描述贸易管理进销存spring...

SpringBoot+VUE员工信息管理系统Java人员管理jsp源代码Mysql

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目介绍SpringBoot+V...

目前见过最牛的一个SpringBoot商城项目(附源码)还有人没用过吗

帮粉丝找了一个基于SpringBoot的天猫商城项目,快速部署运行,所用技术:MySQL,Druid,Log4j2,Maven,Echarts,Bootstrap...免费给大家分享出来前台演示...

SpringBoot+Mysql实现的手机商城附带源码演示导入视频

今天为大家带来的是基于SpringBoot+JPA+Thymeleaf框架的手机商城管理系统,商城系统分为前台和后台、前台用的是Bootstrap框架后台用的是SpringBoot+JPA都是现在主...

全网首发!马士兵内部共享—1658页《Java面试突击核心讲》

又是一年一度的“金九银十”秋招大热门,为助力广大程序员朋友“面试造火箭”,小编今天给大家分享的便是这份马士兵内部的面试神技——1658页《Java面试突击核心讲》!...

SpringBoot数据库操作的应用(springboot与数据库交互)

1.JDBC+HikariDataSource...

SpringBoot 整合 Flink 实时同步 MySQL

1、需求在Flink发布SpringBoot打包的jar包能够实时同步MySQL表,做到原表进行新增、修改、删除的时候目标表都能对应同步。...

SpringBoot + Mybatis + Shiro + mysql + redis智能平台源码分享

后端技术栈基于SpringBoot+Mybatis+Shiro+mysql+redis构建的智慧云智能教育平台基于数据驱动视图的理念封装element-ui,即使没有vue的使...

Springboot+Mysql舞蹈课程在线预约系统源码附带视频运行教程

今天发布的是由【猿来入此】的优秀学员独立做的一个基于springboot脚手架的Springboot+Mysql舞蹈课程在线预约系统,系统项目源代码在【猿来入此】获取!https://www.yuan...

SpringBoot+Mysql在线众筹系统源码+讲解视频+开发文档(参考论文

今天发布的是由【猿来入此】的优秀学员独立做的一个基于springboot脚手架的在线众筹管理系统,主要实现了普通用户在线参与众筹基本操作流程的全部功能,系统分普通用户、超级管理员等角色,除基础脚手架外...

Docker一键部署 SpringBoot 应用的方法,贼快贼好用

这两天发现个Gradle插件,支持一键打包、推送Docker镜像。今天我们来讲讲这个插件,希望对大家有所帮助!GradleDockerPlugin简介...

取消回复欢迎 发表评论: