设计贪吃蛇游戏的主要目的是
夯实自己的C语言基础,训练编程思维,培养解决问题,学习游戏开发基础的思路。
总之就是巩固基础😋
用一个二维数组存储地图,一个二维数组存储地图上的数字对应的值,方便用中文替换,或者以后用贴图或者加上颜色渲染
#define mapX 16
#define mapY 16
int map[mapX][mapY]{
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};
char CN[5][1024] = {
{" "},
{"墙"},
{"果"},
{"头"},
{"身"},
};
蛇的身子是一节一节的,此时最容易联想到的数据结构就是顺序表,链表,二维数组,因为我对于顺序表和链表的使用还很一般,这里就用一个二维数组来维护蛇的身体,随机生成蛇头的位置,并保证不会生成在食物的位置
int snake[mapX * mapY][2] = { {1,1} };
while (1) {
snake[0][0] = rand() % 14 + 1;
snake[0][1] = rand() % 14 + 1;
if (snake[0][0] != fruitPosX && snake[0][1] != fruitPosY) {
break;
}
}
食物的产生,随机的在地图中产生一个节点,在蛇的头坐标和食物的坐标重复的时候,食物消失,蛇的身子加长
//果子位置初始化
srand(time(NULL));
int fruitPosX = rand() % 14 + 1;
int fruitPosY = rand() % 14 + 1;
map[fruitPosX][fruitPosY] = 2;
//检测吃到果子
if (snake[0][0] == fruitPosX && snake[0][1] == fruitPosY) {
snakeLength++;
while (1) {
//果子位置初始化
//再次初始化随机值的话会固定fruitPosX和fruitPosY
srand(time(NULL));
fruitPosX = rand() % 14 + 1;
fruitPosY = rand() % 14 + 1;
int fruitFlag = 1;
for (int i = 0; i < snakeLength; i++) {
if (snake[i][0] == fruitPosX && snake[i][1] == fruitPosY) {
fruitFlag = 0;
break;
}
}
if (fruitFlag) {
map[fruitPosX][fruitPosY] = 2;
break;
}
}
}
蛇触碰到身子或者触碰到墙死亡
// 检测蛇头是否撞到自己的身体
for (int i = 1; i < snakeLength; i++) {
if (snake[0][0] == snake[i][0] && snake[0][1] == snake[i][1]) {
gameOver = 1;
}
}
// 检测蛇头是否撞墙
if (snake[0][0] <= 0 || snake[0][0] >= mapX-1 || snake[0][1] <= 0 || snake[0][1] >= mapY-1) {
gameOver = 1;
}
//gameOver
if (gameOver) {
map[fruitPosX][fruitPosY] = 0;
//清除屏幕
printf("\033[H\033[2J");
printf("\n 哇,你输掉了游戏ヾ( ̄ー ̄)X(^▽^)ゞ");
break;
}
void snakeGame_Init() {
//gameInit
//果子位置初始化
srand(time(NULL));
int fruitPosX = rand() % 14 + 1;
int fruitPosY = rand() % 14 + 1;
map[fruitPosX][fruitPosY] = 2;
//蛇头位置初始化
int snake[mapX * mapY][2] = { {1,1} };
while (1) {
snake[0][0] = rand() % 14 + 1;
snake[0][1] = rand() % 14 + 1;
if (snake[0][0] != fruitPosX && snake[0][1] != fruitPosY) {
break;
}
}
map[snake[0][0]][snake[0][1]] = 3;
int snakeLength = 3;
int gameOver = 0;
while (1)
{
//检测吃到果子
if (snake[0][0] == fruitPosX && snake[0][1] == fruitPosY) {
snakeLength++;
while (1) {
//果子位置初始化
//再次初始化随机值的话会固定fruitPosX和fruitPosY
srand(time(NULL));
fruitPosX = rand() % 14 + 1;
fruitPosY = rand() % 14 + 1;
int fruitFlag = 1;
for (int i = 0; i < snakeLength; i++) {
if (snake[i][0] == fruitPosX && snake[i][1] == fruitPosY) {
fruitFlag = 0;
break;
}
}
if (fruitFlag) {
map[fruitPosX][fruitPosY] = 2;
break;
}
}
}
//清除屏幕
printf("\033[H\033[2J");
//地图
for (int i = 0; i < mapX; i++) {
for (int j = 0; j < mapY; j++) {
printf("%s", CN[map[i][j]]);
}
printf("\n");
}
printf("\n");
//移动
moveS(snake, &snakeLength);
// 检测蛇头是否撞到自己的身体
for (int i = 1; i < snakeLength; i++) {
if (snake[0][0] == snake[i][0] && snake[0][1] == snake[i][1]) {
gameOver = 1;
}
}
// 检测蛇头是否撞墙
if (snake[0][0] <= 0 || snake[0][0] >= mapX-1 || snake[0][1] <= 0 || snake[0][1] >= mapY-1) {
gameOver = 1;
}
//gameOver
if (gameOver) {
map[fruitPosX][fruitPosY] = 0;
//清除屏幕
printf("\033[H\033[2J");
printf("\n 哇,你输掉了游戏ヾ( ̄ー ̄)X(^▽^)ゞ");
break;
}
}
}
首先定义一个全局变量direction用来判断每次自动移动时蛇头向那个方向移动
获取玩家输入:通过 _kbhit() 和 _getch() 函数检查是否有键盘输入。如果有,根据按下的键改变 direction 的值,从而决定蛇的移动方向。
处理自动移动:如果没有键盘输入,direction 的值保持不变,表示蛇将按照之前的方向自动移动。
计算新位置:根据当前的 direction 值,计算出蛇头的新位置。这里通过 dirX 和 dirY 来表示移动的方向。
更新蛇头位置:首先将蛇头当前位置的值设置为0(表示空白),然后更新蛇头的位置,最后将新位置设置为3(表示蛇头)。
更新蛇身位置:通过遍历蛇身的每个部分,将它们按照蛇头的新位置移动。每个部分的新位置也被设置为4(表示蛇身)。
更新地图:在移动蛇的过程中,需要更新地图上的相应位置,以反映蛇的移动情况。
_kbhit() 和 _getch() 是Windows特有的函数,用于检测键盘输入。
不加Sleep(会一直进入未检测到输入的状态)
所以需要Sleep(1000) 用于暂停一秒,检测按键输入,另外可以通过调整sleep数值来改变难度
//蛇头的移动方向
int direction = 1;
void moveS(int (*snake)[2],int* snakeLength) {
int dirX = 0;
int dirY = 0;
// 获取玩家输入
//char keydown = _getch();
//反应时间
Sleep(1000);
if (_kbhit() != 0)
{
switch (_getch())
{
case 'w':
direction = 1;
break;
case 's':
direction = 2;
break;
case 'a':
direction = 3;
break;
case 'd':
direction = 4;
break;
}
// 手动移动蛇的位置
switch (direction)
{
case 1: // 上
dirX = -1;
break;
case 2: // 下
dirX = 1;
break;
case 3: // 左
dirY = -1;
break;
case 4: // 右
dirY = 1;
break;
}
}
else {
// 自动移动蛇的位置
switch (direction)
{
case 1: // 上
dirX = -1;
break;
case 2: // 下
dirX = 1;
break;
case 3: // 左
dirY = -1;
break;
case 4: // 右
dirY = 1;
break;
}
}
// 头的移动
int posX = snake[0][0];
int posY = snake[0][1];
int nextX = posX + dirX;
int nextY = posY + dirY;
map[posX][posY] = 0;
snake[0][0] = nextX;
snake[0][1] = nextY;
map[nextX][nextY] = 3;
// 身子跟着头移动
for (int i = 1;i<*snakeLength; i++)
{
nextX = posX;
nextY = posY;
posX = snake[i][0];
posY = snake[i][1];
snake[i][0] = nextX;
snake[i][1] = nextY;
map[posX][posY] = 0;
map[nextX][nextY] = 4;
}
}
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
#include<conio.h>
#include<Windows.h>
#define mapX 16
#define mapY 16
int map[mapX][mapY]{
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};
char CN[5][1024] = {
{" "},
{"墙"},
{"果"},
{"头"},
{"身"},
};
//蛇头的移动方向
int direction = 1;
void moveS(int (*snake)[2],int* snakeLength) {
int dirX = 0;
int dirY = 0;
// 获取玩家输入
//char keydown = _getch();
//反应时间
Sleep(1000);
if (_kbhit() != 0)
{
switch (_getch())
{
case 'w':
direction = 1;
break;
case 's':
direction = 2;
break;
case 'a':
direction = 3;
break;
case 'd':
direction = 4;
break;
}
// 手动移动蛇的位置
switch (direction)
{
case 1: // 上
dirX = -1;
break;
case 2: // 下
dirX = 1;
break;
case 3: // 左
dirY = -1;
break;
case 4: // 右
dirY = 1;
break;
}
}
else {
// 自动移动蛇的位置
switch (direction)
{
case 1: // 上
dirX = -1;
break;
case 2: // 下
dirX = 1;
break;
case 3: // 左
dirY = -1;
break;
case 4: // 右
dirY = 1;
break;
}
}
// 头的移动
int posX = snake[0][0];
int posY = snake[0][1];
int nextX = posX + dirX;
int nextY = posY + dirY;
map[posX][posY] = 0;
snake[0][0] = nextX;
snake[0][1] = nextY;
map[nextX][nextY] = 3;
// 身子跟着头移动
for (int i = 1;i<*snakeLength; i++)
{
nextX = posX;
nextY = posY;
posX = snake[i][0];
posY = snake[i][1];
snake[i][0] = nextX;
snake[i][1] = nextY;
map[posX][posY] = 0;
map[nextX][nextY] = 4;
}
}
void snakeGame_Init() {
//gameInit
//果子位置初始化
srand(time(NULL));
int fruitPosX = rand() % 14 + 1;
int fruitPosY = rand() % 14 + 1;
map[fruitPosX][fruitPosY] = 2;
//蛇头位置初始化
int snake[mapX * mapY][2] = { {1,1} };
while (1) {
snake[0][0] = rand() % 14 + 1;
snake[0][1] = rand() % 14 + 1;
if (snake[0][0] != fruitPosX && snake[0][1] != fruitPosY) {
break;
}
}
map[snake[0][0]][snake[0][1]] = 3;
int snakeLength = 3;
int gameOver = 0;
while (1)
{
//检测吃到果子
if (snake[0][0] == fruitPosX && snake[0][1] == fruitPosY) {
snakeLength++;
while (1) {
//果子位置初始化
//再次初始化随机值的话会固定fruitPosX和fruitPosY
srand(time(NULL));
fruitPosX = rand() % 14 + 1;
fruitPosY = rand() % 14 + 1;
int fruitFlag = 1;
for (int i = 0; i < snakeLength; i++) {
if (snake[i][0] == fruitPosX && snake[i][1] == fruitPosY) {
fruitFlag = 0;
break;
}
}
if (fruitFlag) {
map[fruitPosX][fruitPosY] = 2;
break;
}
}
}
//清除屏幕
printf("\033[H\033[2J");
//地图
for (int i = 0; i < mapX; i++) {
for (int j = 0; j < mapY; j++) {
printf("%s", CN[map[i][j]]);
}
printf("\n");
}
printf("\n");
//移动
moveS(snake, &snakeLength);
// 检测蛇头是否撞到自己的身体
for (int i = 1; i < snakeLength; i++) {
if (snake[0][0] == snake[i][0] && snake[0][1] == snake[i][1]) {
gameOver = 1;
}
}
// 检测蛇头是否撞墙
if (snake[0][0] <= 0 || snake[0][0] >= mapX-1 || snake[0][1] <= 0 || snake[0][1] >= mapY-1) {
gameOver = 1;
}
//gameOver
if (gameOver) {
map[fruitPosX][fruitPosY] = 0;
//清除屏幕
printf("\033[H\033[2J");
printf("\n 哇,你输掉了游戏ヾ( ̄ー ̄)X(^▽^)ゞ");
break;
}
}
}
int main() {
snakeGame_Init();
}
实现贴图渲染/颜色渲染
做一个游戏开始界面,计算得分
打包成.exe文件
存储在数据库中,可以查看历史最高分
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。