學習完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;
}
本文到這里已經基本結束了,看代碼,是不是很簡單?除了頭文件,兩個類就能夠把方法寫完。本文主要是記錄和分享一下代碼,代碼細節就不一一闡述了。