使用c語言實作字符界面貪吃蛇,
親測可以在Windows Terminal下運行,
直接上原始碼,
歡迎交流,
效果圖



#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//每個位置的狀態是什么
#define Nothing 0 //空
#define Wall 1 //墻
#define Food 2 //食物
#define Head 3 //蛇頭
#define Body 4 //蛇身
//方向
#define Left 5 //左移
#define Right 6 //右移
#define Up 7 //上移
#define Down 8 //下移
HANDLE consoleHandle; // 操作控制臺需要的一個變數
int w, h; // 高度,寬度,對應 y 和 x
int score = 0;//記錄得分
int status[3000][120] = {{0}};//記錄每個位置的狀態是什么
int flag_death = 0;//判斷是否死亡
int flag_q = 0;//判斷是否退出游戲
//結構體:蛇頭
struct snack_head
{
int len;
int x;
int y;
int dir;
//分別為蛇長(不包括蛇頭),蛇頭橫坐標,縱坐標,方向
}snack;
//結構體,蛇身
struct snack_body
{
int x;
int y;
//蛇身中一節的橫坐標
}body[10086];//用二維陣列是一樣的
//結構體,食物
struct FOOD
{
int x;
int y;
}food;
// 列印輸入的一個字符
void mvaddch(int y, int x, char ch) { //y表示高度,x表示寬度
COORD co = (COORD) { .X = x, .Y = y };
SetConsoleCursorPosition(consoleHandle, co);
putchar(ch);
}
//列印一個字串
void mvaddstr(int y, int x, char *s) {
int len = strlen(s);
for (int i = 0; i < len; ++i)
mvaddch(y, x + i, *(s + i));//y表示高度,x表示寬
}
// 清屏(全屏空格)
void ClearScr() {
for (int i = 1; i <= h; ++i)
for (int j = 1; j <= w; ++j)
mvaddch(i, j, ' ');
}
//開始游戲的面板
void EnterGame() {
mvaddstr(12, 50, " Welcome ! ");
mvaddstr(16, 50, "Press any key to start !");
}
//初始化面板
void PrintBoard() {//寬為30~90 高為1~28
for (int i = 1; i <= 28; ++i)
for (int j = 30; j <= 90; j++)
status[i][j] = Nothing;
for (int i = 30; i <= 90; ++i){
mvaddch(1, i, '-');
status[0][i] = Wall;
}
for (int i = 30; i <= 90; ++i) {
mvaddch(28, i, '-');
status[29][i] = Wall;
}
for (int i = 1; i <= 28; ++i) {
mvaddch(i, 29, '|');
status[i][28] = Wall;
}
for (int i = 1; i <= 28; ++i) {
mvaddch(i, 91, '|');
status[i][92] = Wall;
}
mvaddstr(12,94,"press 'p' to pause");
mvaddstr(13,94, "press 'space' to continue");
}
//列印得分
void PrintScore(int y,int x, int score_) {
COORD co = (COORD) {.X = x, .Y = y};
SetConsoleCursorPosition(consoleHandle, co);
printf("score:%d", score_);
}
//游戲失敗時候的界面
void Game_Defeat() {
flag_death = 1;
PrintScore(h / 2 - 2, w / 2 - 3, score);
mvaddstr(h / 2 - 1, w / 2 - 3, "Good game!");
mvaddstr(h / 2, w / 2 - 10, "Press any key to restart.");
score = 0;
}
void InitSnack() {//初始化蛇
snack.len = 1;//蛇身初始長度為一節
snack.x = 60;
snack.y = 16;//y指的蛇頭高度
snack.dir = Right;//蛇頭的初始橫縱坐標及方向
body[0].x = 59;
body[0].y = 16;//第一節蛇身的橫縱坐標
}
void GenerateFood() {//隨機產生一個食物,注意食物的那個位置在這之前必須是空的
srand((unsigned ) time(NULL));
do {
food.x = rand() % 59 + 31;
food.y = rand() % 26 + 2;
} while (status[food.y][food.x] != Nothing);
status[food.y][food.x] = Food;
mvaddch(food.y, food.x, '*');
}
//判斷得分和是否結束,x,y分別指左移或右移的距離,如果吃到食物根據方向做相應的處理
void judge() {
if (snack.dir == Up) {
if (snack.x == food.x && snack.y - 1 == food.y) {
status[snack.y][snack.x] = Body;
status[food.y][food.x] = Head;
mvaddch(snack.y, snack.x, '#');
mvaddch(food.y, food.x, '@');
for (int i = snack.len; i >= 1; i--)
body[i] = body[i - 1];
body[0].x = snack.x;
body[0].y = snack.y;
snack.len++;
snack.y--;
score++;
GenerateFood();
} else if (status[snack.y - 1][snack.x] == Wall || status[snack.y - 1][snack.x] == Body || status[snack.y][snack.x - 1] == Wall || status[snack.y][snack.x+1] == Wall) {
Game_Defeat();
}
} else if (snack.dir == Down) {
if (snack.x == food.x && snack.y + 1 == food.y) {
status[snack.y][snack.x] = Body;
status[food.y][food.x] = Head;
mvaddch(snack.y, snack.x, '#');
mvaddch(food.y, food.x, '@');
for (int i = snack.len; i >= 1; i--)
body[i] = body[i - 1];
body[0].x = snack.x;
body[0].y = snack.y;
snack.len++;
snack.y--;
score++;
GenerateFood();
} else if (status[snack.y + 1][snack.x] == Wall || status[snack.y + 1][snack.x] == Body||status[snack.y][snack.x - 1] == Wall || status[snack.y][snack.x+1] == Wall) {
Game_Defeat();
}
} else if (snack.dir == Left) {
if (snack.x - 1 == food.x && snack.y == food.y) {
status[snack.y][snack.x] = Body;
status[food.y][food.x] = Head;
mvaddch(snack.y, snack.x, '#');
mvaddch(food.y, food.x, '@');
for (int i = snack.len; i >= 1; i--)
body[i] = body[i - 1];
body[0].x = snack.x;
body[0].y = snack.y;
snack.len++;
snack.x = snack.x - 1;
score++;
GenerateFood();
} else if (status[snack.y][snack.x - 1] == Wall||status[snack.y][snack.x - 1] == Body||status[snack.y+1][snack.x+1] == Wall||status[snack.y -1][snack.x]==Wall) {
Game_Defeat();
}
} else if (snack.dir == Right) {
if (snack.x + 1 == food.x && snack.y == food.y) {
status[snack.y][snack.x] = Body;
status[food.y][food.x] = Head;
mvaddch(snack.y, snack.x, '#');
mvaddch(food.y, food.x, '@');
for (int i = snack.len; i >= 1; i--)
body[i] = body[i - 1];
body[0].x = snack.x;
body[0].y = snack.y;
snack.len++;
snack.x = snack.x + 1;
score++;
GenerateFood();
} else if (status[snack.y][snack.x + 1] == Wall||status[snack.y][snack.x + 1] == Body||status[snack.y+1][snack.x+1] == Wall||status[snack.y -1][snack.x]==Wall) {
Game_Defeat();
}
}
}
void Clear_Snack() {//更新蛇之前先擦掉蛇
mvaddch(snack.y, snack.x,' ');
status[snack.y][snack.x] = Nothing;
for (int i = 0 ;i < snack.len; i++) {
mvaddch(body[i].y, body[i].x, ' ');
status[body[i].y][body[i].x] = Nothing;
}
}
void Draw_Snack() {//畫蛇
status[snack.y][snack.x] = Head;
mvaddch(snack.y, snack.x, '@');
for (int i = 0; i < snack.len; i++) {
status[body[i].y][body[i].x] = Body;
mvaddch(body[i].y, body[i].x, '#');
}
}
void Dir_Change() {//根據輸入調整方向
if (_kbhit()) {
switch (_getch()) {
case 'q':
case 'Q':
flag_q = 1;
break;
case 'W':
case 'w':
if (snack.dir != Down) {
snack.dir = Up;
break;
} else {
Game_Defeat();
break;
}
case 'S':
case 's':
if (snack.dir != Up) {
snack.dir = Down;
break;
} else {
Game_Defeat();
break;
}
case 'A':
case 'a':
if (snack.dir != Right) {
snack.dir = Left;
break;
} else {
Game_Defeat();
break;
}
case 'D':
case 'd':
if (snack.dir != Left) {
snack.dir = Right;
break;
} else {
Game_Defeat();
break;
}
case 'p':
case 'P':
while (1){
if (_getch() == ' ') {
break;
}
}
}
}
}
void MoveSnack() {//改變坐標
for (int i = snack.len - 1; i >= 0; i--) {
if ( i != 0) {
body[i] = body[i - 1];
} else {
body[i].x = snack.x;
body[i].y = snack.y;
}
}
switch (snack.dir) {
case Up:
snack.y--;
break;
case Down:
snack.y++;
break;
case Left:
snack.x = snack.x - 1;
break;
case Right:
snack.x = snack.x + 1;
break;
}
}
int main(){
consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); // 初始化這個操作器
CONSOLE_SCREEN_BUFFER_INFO csbi; // 螢屏的資訊
GetConsoleScreenBufferInfo(consoleHandle, &csbi); // 獲取螢屏資訊
w = csbi.dwSize.X;
h = csbi.dwSize.Y; // 得到寬度高度
// 游戲里面,如果一直有輸入的游標,就有點不好看,我們可以讓它不顯示
CONSOLE_CURSOR_INFO cci; // 游標資訊
cci.dwSize = 100;
cci.bVisible = FALSE; // 不可見
SetConsoleCursorInfo(consoleHandle, &cci); // 將游標特性應用到控制臺
// 到這里,閃爍的游標就消失了,
ClearScr();
EnterGame();//調出開始界面
getch();
ClearScr();
PrintBoard();
InitSnack();
GenerateFood();
while (1){
if (flag_q == 1) {
goto end;
}
MoveSnack();
Draw_Snack();
if (score <= 3){
Sleep(160);
} else if (score <= 7) {
Sleep(190);
} else if (score <= 12) {
Sleep(210);
} else {
Sleep(250);
}
PrintScore(10, 94, score);
Dir_Change();
if (flag_death == 1) {
flag_death = 0;
getch();
main();
}
judge();
if (flag_death == 1) {
flag_death = 0;
getch();
main();
}
Clear_Snack();
}
end :cci.bVisible = TRUE; // 可見
SetConsoleCursorInfo(consoleHandle, &cci); // 重新設定
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/398515.html
標籤:其他
