貪喫蛇遊戲製作過程 源碼https://github.com/Rodma1/test.git
一.製作開始界面
void one_interface() {
printf("\n\n\n");
printf("\t\t\t\t\t\t--------------------\n");
printf("\n");
printf("\t\t\t\t\t\t歡迎來到貪喫蛇遊戲\n");
printf("\n");
printf("\t\t\t\t\t\t請按下空格進入遊戲\n");
printf("\n");
printf(" \t\t\t\t\t 根據 w a s d方向鍵控制\n");
printf("--------------------------------------------------------------------------------------------------------------\n");
}
二.製作音樂播放器
注:音頻必須時wav,且要和可執行程序放在一起
#include<mmsystem.h>//音頻頭文件
#pragma comment(lib, "WINMM.LIB")//音頻必加
void myPlaySound()
{
PlaySound("1.wav", NULL, SND_FILENAME | SND_ASYNC);
}
三.製作空格進入遊戲界面
#include<conio.h>//_getch頭文件
void _space()
{
while (1)
{
char charSpace;
charSpace = _getch();//輸入自動讀進charSpace
if (' ' == charSpace)
{
break;
}
}
}
四.製作關閉音樂
void stop_MyPlaySound()
{
PlaySound( NULL,0,0);
}
五.製作遊戲界面
(1)另取一個頭文件head.h
:將數組myArray[20][42]
放進去,然後在源文件裏獲取頭文件#include"head.h"
char myArray[20][42] = { "■■■■■■■■■■■■■■■■■■■■\n",//一個■佔用兩字節
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■ ■\n",
"■■■■■■■■■■■■■■■■■■■■\n" };
(2)在源文件輸出
void two_interface()
{
int i = 0;
for (i = 0;i < 20; i++)
{
printf(myArray[i]);
}
}
六.製作蛇身位置
(1)定義座標(2)定義方向 enum { East = 2, South = 1, West = -2, North =- 1 };//枚舉方向
疑惑點:爲什麼y是行,是列。
答:將myArray
數組用座標表示,y的數就相當於行數,由於方塊佔兩字節,所以x的數等於
ArraySnake[20][3]
的數組
y | x*2 | enum | 蛇頭 |
---|---|---|---|
y | x*2+2 | enum | 蛇身 |
y | x*2+4 | enum | 蛇尾 |
在head.h
中定義int arraySnake[x_pos][3] = { 0 };
//蛇的座標
void set_snakePos()
{
int x=-1,y=-1;//設置座標
srand((unsigned int)time (NULL));//獲得隨機數
x = rand() % 14+3;
y = rand() % 14+3;
//設置🐍的數組
arraySnake[0][0] = y;//行
arraySnake[0][1] = x*2;//列
arraySnake[0][2] = West;
//蛇頭
arraySnake[1][0] = y;
arraySnake[1][1] = x*2+2;
arraySnake[1][2] = West;
//蛇身
arraySnake[2][0] = y;
arraySnake[2][1] = x*2+4;
arraySnake[2][2] = West;
//蛇尾
set_snake();
}
七.製作蛇身
myArray[20][42]
數組
myArray[y][x*2] | myArray[y][x*2+4] | myArray[y][x*2+6] |
---|---|---|
y行x*2列 | y行x*2+4列 | y行x*2+6列 |
通過數組形成一條這樣子的蛇:◆◆◆
#pragma warning (disable : 4996)//strncpy不安全,得加上
//蛇身
void set_snake()
{
for (int i = 0; arraySnake[i][0] != 0; i++)
{
strncpy(&myArray[arraySnake[i][0]][arraySnake[i][1]], "◆",2 );//拷貝
}
}
八.製作蛇跑
解釋:因爲x_pos
值二十,所以只能取0~19
的下標,然後從第19個數開始遍歷,等到獲取有效數字就向前移動,否則過濾掉。
y | 方向 | |
---|---|---|
… | ||
19 |
在head.h
中定義int snakeDir = West;
void set_snakeRun()
{
int i = x_pos - 1;
set_direction();
delete_ophiurid();//刪除原來的蛇
for (i;i>=1;i--)
{
//過濾掉非法🐍
if (0 == arraySnake[i][1])
{
continue;
}
//把前一個結點的值,賦值給當前結點
arraySnake[i][0] = arraySnake[i-1][0];//行
arraySnake[i][1] = arraySnake[i-1][1];//列
arraySnake[i][2] = arraySnake[i-1][2];//方向
}
//初始向西移動
arraySnake[0][2] = snakeDir;
if (West== arraySnake[0][2]||East== arraySnake[0][2])
{
arraySnake[0][1] += arraySnake[0][2];//列加二或減二
}
else
{
arraySnake[0][0] += arraySnake[0][2];//行加二或減二
}
set_snake();
}
解析:
原本蛇是◆◆◆這樣子的,然後蛇頭向前移兩字節,原來蛇頭不變,蛇身變成蛇頭,蛇尾不變(如果設置拷貝的蛇頭是‘’█‘’,那麼蛇出來是█ █ █ ◆)
剛開始
蛇頭 |
---|
蛇身 |
蛇尾 |
arraySnake數組移動下標後:
解析:就相當域蛇身獲取了蛇頭元素,蛇尾獲取了蛇身的元素
蛇頭 |
---|
蛇頭 |
蛇身 |
蛇尾 |
座標加2,myArray
數組移動後
然後放到main
函數裏面while(1)
循環,座標x一直加2,蛇頭一直向前
蛇頭 |
---|
蛇頭 |
蛇頭 |
蛇身 |
九.製作消去蛇尾
注意:先消去蛇尾在跑set_snakeRun()
原因:把舊蛇換成空格,那麼畫新蛇的時候就剛好吧原來蛇頭蛇身的位置覆蓋掉,消去蛇尾
//消除尾節點
void delete_ophiurid()
{
for (int i = 0; arraySnake[i][0] != 0; i++)
{
strncpy(&myArray[arraySnake[i][0]][arraySnake[i][1]], " ", 2);//空兩格,因爲正方體是佔兩個節點
}
}
十.製作按鍵移動方向
知識點:short 兩字節,高字節0000 0010(可以一直按返回!0),低字節 0000 0001(只要按一下就一直返回1)
先在head.h
裏設置一個全局變量snakeDir=East;
然後在第八步驟設置方向那裏設置snakeDir=arraySnake[0][2].
void set_direction()
{
//_getch同步檢測:必須得輸入才能運行,每次循環都得輸入
if (GetAsyncKeyState('W'))//異步檢測:如果輸入字母就改變阿,不輸入就跳過這個函數🐍繼續動
{
if (South != arraySnake[0][2])//如果蛇頭不向南移動,纔可以點擊s鍵向北,否則無效
{
snakeDir = North;
}
}
else if (GetAsyncKeyState('A'))
{
if (East != arraySnake[0][2])
{
snakeDir = West;
}
}
else if (GetAsyncKeyState('S'))
{
if (North != arraySnake[0][2])
{
snakeDir = South;
}
}
else if (GetAsyncKeyState('D'))
{
if (West != arraySnake[0][2])
{
snakeDir = East;
}
}
}
十一.蛇死亡
在head.h
中定義#define true 1
#define false 0
bool set_snakeDead()
{
if (East == arraySnake[0][2] || West == arraySnake[0][2])
{
if ( 0 == strncmp(&myArray[arraySnake[0][0]][arraySnake[0][1] + arraySnake[0][2]], "■", 2))
{
return false;
}
else if(0 == strncmp(&myArray[arraySnake[0][0] + arraySnake[0][2]][arraySnake[0][1]], "◆", 2))
{
return false;
}
}
else
{
if ( 0 == strncmp(&myArray[arraySnake[0][0] + arraySnake[0][2]][arraySnake[0][1]], "■", 2))
{
return false;
}
else if (0 == strncmp(&myArray[arraySnake[0][0] + arraySnake[0][2]][arraySnake[0][1]], "◆", 2) )
{
return false;
}
}
return true;
}
十二.食物生成
在head.h
中定義#define x_pos 20
int g_Nx ,g_Ny ;
typedef int bool;//定義bool類型的變量
bool g_proFood = true;
void set_snakeFood()
{
//如果有食物就返回,沒有點添加食物
if (false == g_proFood)
{
return ;
}
//設置座標
srand((unsigned int)time(NULL));//獲得隨機數
g_Nx = rand() % 16 +2;
g_Ny = rand() % 16 + 2;
bool a_pos = true;
while (1)
{
for (int i = 0; arraySnake[i][0] != 0; i++)
{
if (g_Nx * 2 == arraySnake[i][1] &&g_Ny == arraySnake[i][0])
{
a_pos = false;
}
}
if (true == a_pos)
{
break;
}
}
strncpy(&myArray[g_Ny][g_Nx*2], "●", 2);//不要忘記乘二,卡在這裏好久了
//添加食物後變成false
g_proFood = false;
}
十三.蛇長大
在head.h
中定義蛇長大的成員變量int g_x = 2;
void set_snakeUp()
{
//如果蛇頭和食物座標相同1。蛇增長
if (g_Nx*2 == arraySnake[0][1] && g_Ny == arraySnake[0][0])
{
//蛇長大
/*不明白的地方:爲什麼arraySnake[g_x][0];
arraySnake[g_x][0]-2;
arraySnake[g_x][0];這也能編譯出來*/
if (East==arraySnake[g_x][2])
{
arraySnake[g_x+1][0] = arraySnake[g_x][0];//行
arraySnake[g_x+1][1] = arraySnake[g_x][1]-2;//列
arraySnake[g_x+1][2] = arraySnake[g_x][2];//方向
}
else if (West == arraySnake[g_x][2])
{
arraySnake[g_x + 1][0] = arraySnake[g_x][0];//行
arraySnake[g_x + 1][1] = arraySnake[g_x][1] + 2;//列
arraySnake[g_x + 1][2] = arraySnake[g_x][2];//方向
}
else if (South == arraySnake[g_x][2])
{
arraySnake[g_x + 1][0] = arraySnake[g_x][0]+1;//行
arraySnake[g_x + 1][1] = arraySnake[g_x][1];//列
arraySnake[g_x + 1][2] = arraySnake[g_x][2];//方向
}
else if (North == arraySnake[g_x][2])
{
arraySnake[g_x + 1][0] = arraySnake[g_x][0]-1;//行
arraySnake[g_x + 1][1] = arraySnake[g_x][1] ;//列
arraySnake[g_x + 1][2] = arraySnake[g_x][2];//方向
}
g_x++;
//如果蛇吃了食物就沒有食物了,返回true給set_snakeFood()添加食物
g_proFood = true;
g_score++;
}
}
十四.設置分數
在head.h
中定義分數變量int g_score = 0;
void set_score()
{
COORD rd;
rd.X = 45;
rd.Y = 2;
//設置位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),rd);
//打印
printf("score\n");
rd.X = 47;
rd.Y = 4;
//設置位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), rd);
//打印
printf("%d\n",g_score);
}
十五.main函數運行
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>//_getch頭文件
#include <time.h>//獲取時間數函數
#include"head.h"
#include<windows.h>//定義局部變量
#include<mmsystem.h>//音頻頭文件
#pragma comment(lib, "WINMM.LIB")//音頻必加
#pragma warning (disable : 4996)//strncpy不安全,得加上
int main(void)
{
one_interface();//初始界面
myPlaySound();//音頻
_space();//點擊空格鍵進入遊戲界面
system("cls");//清屏
printf("\t\t\t\t\t\t歡迎進入遊戲\n");
Sleep(2000);
stop_MyPlaySound();// 先消去再跑,順序不能亂
set_snakePos();//這個函數必須放在界面上面才能顯示
while (1)
{
system("cls");
set_snakeFood();//產生食物
set_snakeUp();//蛇變長
if (false == set_snakeDead())//蛇死亡
{
printf("snake dead");
break;
}
set_snakeRun();//蛇跑
two_interface();//遊戲界面
set_score();//得分
Sleep(500);
}
system("pause");
return 0;
}