貪吃蛇的規則大家應該都知道,簡單來說就是吃到食物則蛇身增長,蛇可以在游戲區域內隨意移動,游戲結束條件就是蛇撞到邊界或者撞到自己色蛇身,

首先,實作一個函式,這個函式的作用是將游標移動到我們所期望的位置
/*
* 控制游標所在的位置
*/
void gotoxy(int x, int y)
{
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
構建結構體物件
設計這個游戲,最重要的兩個物件就是蛇和食物,因此用兩個結構體來代表這兩個物件,食物只關注其坐標位置,蛇的話,成員包括坐標陣列,長度和分數,
// 定義游戲區域的邊界寬度
#define WIDTH 100
#define HIGH 20
// 定義蛇的最大長度
#define MAX_LENGHT 100
// 定義游戲初始速度
#define SPEED 500
// 定義游戲中的兩個物件:食物和蛇
struct
{
int x;
int y;
}food;
struct
{
int len;
int x_buf[MAX_LENGHT];
int y_buf[MAX_LENGHT];
int score;
}snake;
// 要用到的全域變數
int food_flag = 0;
int key = 72;
初始化游戲邊界和小蛇
這個沒什么難度,就是回圈列印,直接放代碼,
/*
* 繪制游戲區域邊界
*/
void DrawMap(void)
{
int x, y;
for (x = 0; x < WIDTH + 4; x += 2)
{
y = 0;
gotoxy(x, y);
printf("■");
y = HIGH + 2;
gotoxy(x, y);
printf("■");
}
for (y = 1; y < HIGH + 2; y++)
{
x = 0;
gotoxy(x, y);
printf("■");
x = WIDTH + 2;
gotoxy(x, y);
printf("■");
}
// 將游標移出游戲區域
gotoxy(0, HIGH + 5);
}
注意最后一行使用gotoxy函式移動函式很重要,不然游標會在游戲區域內持續閃爍,在退出游戲時,甚至會出現顯示問題,(為了避免遺漏,我基本在每個涉及到游標移動的函式最后都加了這句話)
/*
* 初始化小蛇
*/
void CreateSnake(void)
{
int orgin_x, orgin_y;
orgin_x = WIDTH / 2 + 2;
orgin_y = HIGH / 2 + 1;
snake.len = 3;
snake.x_buf[0] = orgin_x;
snake.y_buf[0] = orgin_y;
snake.x_buf[1] = orgin_x;
snake.y_buf[1] = ++orgin_y;
snake.x_buf[2] = orgin_x;
snake.y_buf[2] = ++orgin_y;
snake.score = -1;
int i;
for (i = 0; i < snake.len; i++)
{
gotoxy(snake.x_buf[i], snake.y_buf[i]);
printf("■");
}
gotoxy(0, HIGH + 5);
}
生成食物
我使用一個標志位food_flag來代表區域內是否存在食物(初始時刻,以及蛇吃到食物時,food_flag為0),當food_flag為0時就執行生成食物的操作,由于要保證游戲的隨機性,用亂數來生成食物坐標,
/*
* 當游戲區域內不存在食物時,隨機創造一個食物
*/
void CreateFood(void)
{
if (food_flag == 0)
{
int flag = 0,i;
do
{
srand((unsigned int)time(NULL));
food.x = (rand() % (WIDTH/2))*2 + 2;
food.y = rand() % HIGH + 1;
// 判斷生成的食物是否和蛇身重合
for (i = 0; i < snake.len; i++)
{
if (snake.x_buf[i] == food.x && snake.y_buf[i] == food.y)
{
flag = 1;
break;
}
}
} while (flag);
gotoxy(food.x, food.y);
printf("★");
// 吃到食物,則分數加1
snake.score++;
food_flag = 1;
}
gotoxy(0, HIGH + 5);
}
實作的方法都大同小異,但是我強調的點是隨機生成坐標的實作,由于字符"■"是占兩位,所以橫坐標必須為2的倍數,其他的帖子里一般是用以下方法
food.x = rand() % WIDTH + 2;
food.y = rand() % HIGH + 1;
然后通過while回圈來判斷x是否適合要求,不符合就重新生成,但這種做法會出現一種問題,游戲進行程序中會出現卡頓的效果,主要原因就是奇偶數出現概率各占50%,因此有大概率出現多次的回圈操作,
我的方法如下,這樣的好處是可以保證生成的橫坐標一定是偶數,避免了大量的回圈操作,
food.x = (rand() % (WIDTH/2))*2 + 2;
food.y = rand() % HIGH + 1;
移動小蛇
首先要對snake物件中坐標快取區內的坐標進行后移,以便裝入新的坐標,在此要分兩種情況,一是小蛇沒吃到食物,則抹去最后一節,在頭部加入新坐標;二是小蛇吃到食物,則不刪去最后一節,
void SnakeMove(int x, int y)
{
// 判斷是否吃到食物,吃到長度加1
if (!food_flag)
snake.len++;
// 沒吃到則抹去最后一節
else
{
gotoxy(snake.x_buf[snake.len - 1], snake.y_buf[snake.len - 1]);
printf(" ");
}
int i;
for (i = snake.len - 1; i > 0; i--)
{
snake.x_buf[i] = snake.x_buf[i - 1];
snake.y_buf[i] = snake.y_buf[i - 1];
}
snake.x_buf[0] = x;
snake.y_buf[0] = y;
gotoxy(snake.x_buf[0], snake.y_buf[0]);
printf("■");
gotoxy(0, HIGH + 5);
}
隨后根據用戶按鍵,改變小蛇前進方向,這塊部分代碼也是我移植過來的,有詳細的注釋,就不在這贅述了,
void move()
{
int pre_key = key, x, y;
if (_kbhit())//如果用戶按下了鍵盤中的某個鍵
{
fflush(stdin);//清慷訓沖區的字符
//getch()讀取方向鍵的時候,會回傳兩次,第一次呼叫回傳0或者224,第二次呼叫回傳的才是實際值
key = _getch();//第一次呼叫回傳的不是實際值
key = _getch();//第二次呼叫回傳實際值
}
// 小蛇移動方向不能和上一次的方向相反
if (pre_key == 72 && key == 80)
key = 72;
if (pre_key == 80 && key == 72)
key = 80;
if (pre_key == 75 && key == 77)
key = 75;
if (pre_key == 77 && key == 75)
key = 77;
switch (key)
{
case 75:
x = snake.x_buf[0] - 2;//往左
y = snake.y_buf[0];
break;
case 77:
x = snake.x_buf[0] + 2;//往右
y = snake.y_buf[0];
break;
case 72:
x = snake.x_buf[0];
y = snake.y_buf[0] - 1;//往上
break;
case 80:
x = snake.x_buf[0];
y = snake.y_buf[0] + 1;//往下
break;
}
if (x == food.x&&y == food.y)
food_flag = 0;
SnakeMove(x, y);
}
檢查游戲行程
主要是包括兩個方面,(1)失敗:小蛇撞墻或者撞到自己的身體;(2)成功:小蛇長度達到最大長度,
void check(void)
{
int i;
// 失敗條件
if (snake.x_buf[0] == 0 | snake.x_buf[0] == WIDTH + 4 | snake.y_buf[0] == 0 | snake.y_buf[0] == HIGH + 2)
{
printf("Game Over!\n");
exit(0);
}
for (i = 1; i < snake.len; i++)
{
if (snake.x_buf[0] == snake.x_buf[i] && snake.y_buf[0] == snake.y_buf[i])
{
printf("Game Over!\n");
exit(0);
}
}
// 勝利條件
if (snake.len == MAX_LENGHT)
{
printf("Your are win!\n");
exit(0);
}
// 列印得分
gotoxy(0, HIGH + 6);
printf("Your score: %d", snake.score);
}
主函式
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <time.h>
#include <conio.h>
int main(void)
{
DrawMap();
CreateSnake();
while (1)
{
CreateFood();
move();
// 用于控制游戲的速度
Sleep(SPEED - 2 * snake.len);
check();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/258096.html
標籤:其他
