C语言实现的贪吃蛇小游戏
学习完C语言基础后,当然要做点小东西来巩固一下知识啦~~,之前做的学生信息管理系统是比较小的,搞定之后决定还是做个贪吃蛇的小游戏,这是学习C语言的经典入门小程序,下面简单地说下用C语言开发这个需要用到什么库吧。
贪吃蛇
我刚刚做的时候也是一头雾水,不知道为什么别人能够在控制台应用程序中能够画出这么复杂的界面,经过网上的一番查找,终于知道,C语言是有方法定位光标的位置的。
// 移动光标到指定位置
void Gotoxy(int x, int y)
{
COORD position = { y, x };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), position);
}
相信认真去学过C语言的人对这个方法不陌生,没错,我曾经在网上找过实现贪吃蛇的很多资料,但是很多人的代码都只是把gotoxy这个方法的代码打出来,无头无脑,我根本不知道是自定义的代码还是库里自带的方法。
经过多番查找,发现这个方法其实是自己写的,里面的COORD则是库中自带的类型,属于<Windows.h>库,如果要写这个方法,直接饮用这个库就可以了。
整个游戏除了以上的方法是需要摸索来源,其余的代码基本用C语言的基础:数组、结构体和指针。就足以完成。下面是主要的代码:
头文件:SnakeInit.h
#define ROW 23 // 行
#define LINE 50 // 列
#define LENGTH 4; // 蛇的初始长度
#define WAIT_TIME 500; // 蛇的运行速度
int score; // 当局分数
int maxScore; // 最高分数
int length; // 蛇的长度
int xincrement; // x轴增量
int yincrement; // y轴增量
int isDigestion; // 是否已消化食物
int border[ROW][LINE]; // 边界数组
// 蛇结构体
typedef struct Snake {
int x;
int y;
int seq;
char text[1];
struct Snake *preNode;
struct Snake *nextNode;
}snake_t;
// 食物结构体
typedef struct Food {
int x;
int y;
char text[1];
}food_t;
snake_t *snake; // 蛇
snake_t *lastNode; // 蛇的最后一个节点
food_t food; // 食物
void InitMainView(); // 初始化界面
int IsDied(); //判断蛇是否已死(撞到边界或吃到自己)
void Gotoxy(int x, int y); // 将光标跳到指定的坐标
void InitFood(); // 初始化食物
void InitSnake(); // 初始化蛇
void ClearSnake(); // 清除蛇的轨迹
void MoveSnake(); // 移动蛇的位置
void ShowSnake(); // 显示蛇的所有节点
void OperateSnake(); //操作蛇的移动方向
int CheckCoord(int x, int y); //检查能投放食物的位置
void FoodSnake(); //投喂蛇
void AddNode(); // 蛇身添加节点
void RefreshScore(); // 刷新界面分数
void ShowDeadMessage(); //显示蛇死亡信息
void ShowMessage(); //提示信息
源文件:SnakeInit.c
#include <stdio.h>
#include <conio.h>
#include <Windows.h>
#include <conio.h>
#include "SnakeInit.h"
#pragma region 界面方法
// 初始化数组
void InitArray() {
int i, j;
for (i = 0;i < ROW;i++) {
border[i][0] = 1;
border[i][LINE - 1] = 1;
}
for (j = 0;j < LINE;j++) {
border[0][j] = 1;
border[ROW - 1][j] = 1;
}
}
// 初始化界面
void InitMainView() {
InitArray();
int i, j;
for (i = 0;i < ROW;i++) {
for (j = 0;j < LINE;j++) {
if (border[i][j] == 0) {
printf(" ");
}
else {
printf("#");
}
}
printf("\n");
}
}
// 移动光标到指定位置
void Gotoxy(int x, int y)
{
COORD position = { y, x };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), position);
}
#pragma endregion
#pragma region 蛇方法
void InitFood() {
strcpy(food.text, "*");
}
// 初始化蛇
void InitSnake() {
length = LENGTH;
snake = (snake_t *)malloc(sizeof(snake_t));
snake->preNode = NULL;
snake->nextNode = NULL;
snake->x = ROW / 2;
snake->y = LINE / 2;
snake->seq = 1;
strcpy(snake->text, "@");
int i;
snake_t *pre = snake;
for (i = 1;i < length;i++) {
snake_t *next = (snake_t *)malloc(sizeof(snake_t));
next->preNode = pre;
next->nextNode = NULL;
next->x = pre->x + 1;
next->y = pre->y;
next->seq = pre->seq + 1;
pre->nextNode = next;
strcpy(next->text, "@");
pre = next;
}
lastNode = pre;
}
// 清楚蛇的移动轨迹
void ClearSnake() {
Gotoxy(lastNode->x, lastNode->y);
printf(" ");
}
// 界面显示蛇
void ShowSnake() {
snake_t *snakeNode = snake;
while (snakeNode->nextNode != NULL) {
Gotoxy(snakeNode->x, snakeNode->y);
printf("%s", snakeNode->text);
snakeNode = snakeNode->nextNode;
}
Gotoxy(snakeNode->x, snakeNode->y);
printf("%s", snakeNode->text);
}
// 界面移动蛇
void MoveSnake() {
if (lastNode->x == food.x && lastNode->y == food.y) {
isDigestion = 1;
}
snake_t *node = lastNode;
while (node->preNode != NULL)
{
node->x = node->preNode->x;
node->y = node->preNode->y;
node = node->preNode;
}
node->x += xincrement;
node->y += yincrement;
}
// 操作蛇的运行方向
void OperateSnake() {
if (kbhit() == 0) {
// 没有按下按键
return;
}
char oper = getch();
switch (oper)
{
case 'w': // 上
case 'W':
xincrement = -1;
yincrement = 0;
break;
case 's': // 下
case 'S':
xincrement = 1;
yincrement = 0;
break;
case 'a': // 左
case 'A':
xincrement = 0;
yincrement = -1;
break;
case 'd': // 右
case 'D':
xincrement = 0;
yincrement = 1;
break;
default:
Gotoxy(ROW, 0);
printf("请输入正确的方向(上[w/W]、下[s/S]、左[a/A]、右[d/D]");
break;
}
}
// 蛇是否运行到边界或吃到自己
int IsDied() {
int result = 0;
if (snake->x == 0 || snake->x == ROW - 1 || snake->y == 0 || snake->y == LINE - 1) {
// 走到边界则死亡
result = 1;
}
int x = snake->x + xincrement;
int y = snake->y + yincrement;
snake_t *nextNode = snake->nextNode;
while (nextNode != NULL) {
if (x == nextNode->x && y == nextNode->y) {
result = 1;
break;
}
nextNode = nextNode->nextNode;
}
return result;
}
// 检查随机投放点是否在蛇的节点上
int CheckCoord(int x, int y) {
int result = 0;
snake_t *nextNode = snake;
while (nextNode != NULL) {
if (x == nextNode->x && y == nextNode->y) {
result = 1;
break;
}
nextNode = nextNode->nextNode;
}
return result;
}
// 投放食物
void FoodSnake() {
int x, y;
do {
x = rand() % (ROW - 1);
y = rand() % (LINE - 1);
} while (CheckCoord(x, y));
food.x = x;
food.y = y;
Gotoxy(food.x, food.y);
printf("%s", food.text);
}
// 吃掉食物后长度加一
void AddNode() {
snake_t *newNode = (snake_t *)malloc(sizeof(snake_t));
newNode->x = food.x;
newNode->y = food.y;
strcpy(newNode->text, "@");
newNode->preNode = lastNode;
newNode->nextNode = NULL;
lastNode = newNode;
}
#pragma endregion
#pragma region Message
void RefreshScore() {
int x = ROW / 2, y = LINE + 2;
Gotoxy(x, y);
printf("目前得分:%d", score);
Gotoxy(x + 2, y);
printf("最高得分:%d", maxScore);
}
void ShowDeadMessage() {
Gotoxy(ROW / 2, LINE / 2 - 10);
printf("蛇已死亡!请按任意键返回。");
getchar();
getchar();
}
void ShowMessage() {
Gotoxy(ROW + 2, 0);
printf("是否重新开局?(y/n):");
}
#pragma endregion
主函数:main.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include "SnakeInit.h"
int main(int argc, char *argv[]) {
while (1) {
int len = LENGTH; // 初始化蛇的初始长度
int waittime = WAIT_TIME;
CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); //隐藏光标
// 初始化界面
system("CLS");
InitMainView();
RefreshScore();
InitFood();
InitSnake();
ShowSnake();
FoodSnake();
xincrement = -1;
yincrement = 0;
// 初始化显示蛇
while (1) {
OperateSnake();
if (IsDied()) {
// 提示蛇已死亡
ShowDeadMessage();
break;
}
ClearSnake();
MoveSnake();
if (isDigestion) {
AddNode();
FoodSnake();
isDigestion = 0;
score += 10;
RefreshScore();
}
ShowSnake();
Sleep(waittime);
}
// 询问是否继续玩
char con[1];
ShowMessage();
scanf("%c", &con[0]);
if (con[0] == 'n') {
break;
}
if (score > maxScore) {
maxScore = score;
score = 0;
}
}
return 0;
}
本文到这里已经基本结束了,看代码,是不是很简单?除了头文件,两个类就能够把方法写完。本文主要是记录和分享一下代码,代码细节就不一一阐述了。