超簡單的C語言貪喫蛇(附源碼)

所用知識:

  1. 一維數組的使用
  2. 結構體的使用
  3. 播放音樂函數的使用
  4. 電腦按鍵的檢測
  5. 窗口光標座標函數的使用

相關函數講解

1.光標移動到某一指定座標的函數

#include <windows.h>//座標的API
void gotoxy(int x, int y)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD coord; //定義結構體coord (座標系coord)
	coord.X = x; //橫座標x
	coord.Y = y; //縱座標y
	SetConsoleCursorPosition(handle, coord); //移動光標
}

2.kbhit按鍵檢測函數

#include <conio.h>//按鍵

引用一下其他網友的解答:

#include <conio.h>
#include
using namespace std;
int main()
{
while(!kbhit()) //當沒有鍵按下
{
cout<<“無鍵按下”<<endl;
}
cout<<“有鍵按下”<<endl; //有鍵按下時輸出這
system(“pause”);
}
kbhit() 在執行時,檢測是否有按鍵按下,有按下返回非0值,一般是1
沒有按下返回0;是非阻塞函數
getch() 在執行時,檢測按下什麼鍵,如果不按鍵該函數不返回;是阻塞函數
類似地
在Tc2.0中有一個處理鍵盤輸入的函數bioskey();
int bioskey(int cmd);
當cmd爲1時,bioskey()檢測是否有鍵按下。沒有鍵按下時返回0;有鍵按下時返回按鍵碼(
任何按鍵碼都不爲0),但此時並不將檢測到的按鍵碼從鍵盤緩衝隊列中清除。 是非阻塞參數。
當cmd爲0時,bioskey()返回鍵盤緩衝隊列中的按鍵碼,並將此按鍵碼從鍵盤緩衝隊列中清
除。如果鍵盤緩衝隊列爲空,則一直等到有鍵按下,纔將得到的按鍵碼返回。是阻塞調用。
//個人理解kbhit()有點像bioskey(1)
具體搜索bioskey詞條吧 :)

3.playsound函數
引用一下這個函數的詳細說明
所需頭文件,順序要這樣子

#include <windows.h>//座標的API
#include <MMSystem.h>
#pragma comment(lib,"winmm.lib")

在main函數裏面使用,m1.wav爲文件名,我放在跟cpp文件同目錄下來了

PlaySound(L"m1.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);//播放聲音

基本要素

  1. 畫地圖(包含剛開始的畫蛇和食物)
  2. 按鍵檢測
  3. 產生食物
  4. 判斷蛇的狀態

代碼

game.cpp

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>//座標的API
#include <conio.h>//按鍵
#include <time.h>//產生隨機數要用到
#include"game.h"

SNAKE snake;//定義SNAKE 類型的snake,不可在.h文件中定義
FOOD food;//同上
int score = 0;//得分
char key = 'W';//鍵盤獲得的方向
char tempkey = 'W';//當前蛇行進方向
bool changeflag = false;//用於有無喫到食物的標誌

//到某一指定座標的函數
void gotoxy(int x, int y)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD coord; //定義結構體coord (座標系coord)
	coord.X = x; //橫座標x
	coord.Y = y; //縱座標y
	SetConsoleCursorPosition(handle, coord); //移動光標
}
//畫地圖
void drawmap()
{
	
	gotoxy(50, 8);
	printf("——遊戲開始——");
	gotoxy(43, 10);
	printf("——切換鍵盤爲大寫字母模式——");
	gotoxy(51, 12);
	system("pause");

	system("CLS");
	for (int i = 0; i <= MAP_HIGHT; i++)
	{
		gotoxy(0, i);
		printf("■");
		gotoxy(MAP_WIDTH, MAP_HIGHT-i);//不同方向打印
		printf("■");
		Sleep(20);//有一個一個打印的延時效果
	}
	for (int i = 0; i < MAP_WIDTH; i += 2)
	{
		gotoxy(i, 0);
		printf("■");//佔兩個橫座標,一個縱座標
		gotoxy(MAP_WIDTH - i, MAP_HIGHT);
		printf("■");
		Sleep(20);
	}
	//打印說明
	gotoxy(100, 7);
	printf("按鍵說明:");
	gotoxy(100, 10);
	printf("W:向上");
	gotoxy(100, 13);
	printf("A:向左");
	gotoxy(100, 16);
	printf("S:向下");
	gotoxy(100, 19);
	printf("D:向右");
	gotoxy(100, 22);
	printf("當前分數:%d", score);

	//初始畫蛇頭
	snake.x[0] = MAP_WIDTH / 2 +1;//蛇頭的座標必須是偶數,因爲■橫座標是佔了兩節,不明白的話把1去掉試試效果
	snake.y[0] = MAP_HIGHT / 2;
	gotoxy(snake.x[0], snake.y[0]);
	printf("●");
	//打印蛇身,方向要與初始的方向一致
	for (int i = 1; i < snake.len; i++) {
		snake.x[i] = snake.x[0];
		snake.y[i] = snake.y[0] + i;
		gotoxy(snake.x[i], snake.y[i]);
		printf("●");
	}
	//初始畫食物
	food.x = MAP_WIDTH / 4;
	food.y = MAP_HIGHT / 2;
	gotoxy(food.x, food.y);
	printf("◆");
}
void KeyDown()
{	//無按鍵操作
	if (_kbhit())
	{
		fflush(stdin);
		key = _getch();
		//當行進方向與按鍵方向相反時防止自殺現象
		if (key != 'w' && key != 'W' && key != 's' && key != 'S' && key != 'A' && key != 'a' && key != 'd' && key != 'D')
			key = tempkey;
		else {
			if (tempkey == 'w' || tempkey == 'W')
				if (key == 's' || key == 'S')
					key = tempkey;
			if (tempkey == 's' || tempkey == 'S')
				if (key == 'w' || key == 'W')
					key = tempkey;
			if (tempkey == 'a' || tempkey == 'A')
				if (key == 'D' || key == 'd')
					key = tempkey;
			if (tempkey == 'D' || tempkey == 'd')
				if (key == 'a' || key == 'A')
					key = tempkey;
			tempkey = key;//非wasd鍵
		}
	}
	if (!changeflag)
	{
		gotoxy(snake.x[snake.len-1 ], snake.y[snake.len-1 ]);//總共有len個蛇的身體單元●,因爲數組,最後一個是len-1
		printf("  ");//沒有喫到食物的時候要去最後把蛇尾擦除
	}
	else
	{
		snake.x[snake.len] = snake.x[snake.len - 1];//喫到食物後len+1
		snake.y[snake.len] = snake.y[snake.len - 1];
		snake.len++;
	}
	for (int i = snake.len - 1; i > 0; i--)
	{
		snake.x[i] = snake.x[i - 1];
		snake.y[i] = snake.y[i - 1];
	}
	switch (key)
	{
	case 'W':
	case 'w': snake.y[0]--; break;//注意gotoxy的座標原點是左上角
	case 'S':
	case 's': snake.y[0]++; break;
	case 'A':
	case 'a': snake.x[0] -= 2; break;//佔兩個字符
	case 'D':
	case 'd': snake.x[0] += 2; break;
	default: break;
	}
	gotoxy(snake.x[0], snake.y[0]);
	printf("●");
	changeflag = false;
}
void CreatFood()
{
	//隨機種子,產生隨機數
	srand((unsigned)time(NULL));
	if (snake.x[0] == food.x&&snake.y[0] == food.y)//判斷喫到食物
	{
		score++;
		gotoxy(100, 22);
		printf("當前分數:%d", score);//打印分數
		if (score % 10 == 0)
		{
			snake.speed -= 10;
		}
		while (1)
		{
			bool flag = 1;
			food.x = rand() % (MAP_WIDTH - 4) + 2;//減掉左右兩列4個座標,然後加上最左一列2個座標就是寬了
			food.y = rand() % (MAP_HIGHT - 2) + 1;
			for (int i = 0; i < snake.len; i++)
			{
				if (food.x == snake.x[i] && food.y == snake.y[i])//食物不能出現在自己身上
				{
					flag = 0;
					break;
				}


			}
			if (flag&&food.x % 2 == 0)//食物x座標要爲偶數
			{
				break;
			}
		}

		gotoxy(food.x, food.y);
		printf("◆");
		changeflag = true;
	}

}
int SnakeState(void)
{
	//判斷是否撞牆
	if (snake.x[0] == 0 || snake.x[0] == MAP_WIDTH || snake.y[0] == 0 || snake.y[0] == MAP_HIGHT)
		return false;
	for (int i = 1; i < snake.len; i++)
	{
		if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i])
			return false;
	}
	return true;
}

game.h

#pragma once
#ifndef GAME_H
#define GAME_H

#define MAP_HIGHT 29
#define MAP_WIDTH 90
#define snake_max_len 200
#define snake_begin_len 3
#define snake_begin_speed 200

struct SNAKE
{
	int len = snake_begin_len;
	int x[snake_max_len];
	int y[snake_max_len];
	int speed = snake_begin_speed;
};
struct FOOD
{
	int x;
	int y;

};


extern SNAKE snake;
extern FOOD food;

extern int score;

void gotoxy(int x, int y);
void drawmap(void);
void KeyDown(void);
void CreatFood(void);
int SnakeState(void);
#endif // !GAME_H

main.cpp

#include <stdio.h>
#include <windows.h>//座標的API
#include <MMSystem.h>
#pragma comment(lib,"winmm.lib")
#include "game.h"

int main()
{
	PlaySound(L"m1.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);//播放聲音
	//隱藏光標
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO cci;
	GetConsoleCursorInfo(hOut, &cci);
	cci.bVisible = FALSE;
	SetConsoleCursorInfo(hOut, &cci);
	system("CLS");
	drawmap();
	while (1)
	{
		KeyDown();
		Sleep(snake.speed);
		CreatFood();
		if (SnakeState()==false)
		{
			break;
		}
	}
	
	system("CLS");
	gotoxy(50, 8);
	printf("——遊戲結束——");
	gotoxy(52, 10);
	printf("你的分數爲:%d\n", score);
	gotoxy(51, 12);

	
	
	
	system("pause");
	
	return 0;
}

效果圖

在這裏插入圖片描述

一個.cpp文件的版本(差別不大)

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>//座標的API
#include <MMSystem.h>
#pragma comment(lib,"winmm.lib")
#include <conio.h>//按鍵
#include <time.h>

#define MAP_HIGHT 29
#define MAP_WIDTH 90
#define snake_max_len 200
#define snake_begin_len 3
#define snake_begin_speed 200
int score=0;//得分
char key = 'W';
char tempkey = 'W';
bool changeflag = false;
struct SNAKE
{
	int len= snake_begin_len;
	int x[snake_max_len];
	int y[snake_max_len];
	int speed = snake_begin_speed;
}snake;
struct FOOD
{
	int x;
	int y;

}food;
void gotoxy(int x, int y)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD coord; //定義結構體coord (座標系coord)
	coord.X = x; //橫座標x
	coord.Y = y; //縱座標y
	SetConsoleCursorPosition(handle, coord); //移動光標
}
void drawmap()
{
	for (int i = 0; i <= MAP_HIGHT; i++)
	{
		gotoxy(0, i);
		printf("■");
		gotoxy(MAP_WIDTH, i);
		printf("■");
		Sleep(20);
	}
	for (int i = 0; i < MAP_WIDTH; i+=2)
	{
		gotoxy(i, 0);
		printf("■");
		gotoxy(MAP_WIDTH -i, MAP_HIGHT);
		printf("■");
		Sleep(20);
	}
		gotoxy(100, 7);
		printf("按鍵說明:");
		gotoxy(100, 10);
		printf("W:向上");
		gotoxy(100, 13);
		printf("A:向左");
		gotoxy(100, 16);
		printf("S:向下");
		gotoxy(100, 19);
		printf("D:向右");
		gotoxy(100, 22);
		printf("當前分數:%d", score);
	
		//畫蛇
		
		snake.x[0] = MAP_WIDTH/2+1;//偶數
		snake.y[0] = MAP_HIGHT/2;

		gotoxy(snake.x[0], snake.y[0]);
		printf("●");
		for (int i = 1; i < snake.len; i++) {
			snake.x[i] = snake.x[0];
			snake.y[i] = snake.y[0] + i;
			gotoxy(snake.x[i], snake.y[i]);
			printf("●");
		}
		//畫食物
		food.x = MAP_WIDTH / 4;
		food.y = MAP_HIGHT / 2;
		gotoxy(food.x, food.y);
		printf("◆");
}
void KeyDown()
{	//無按鍵操作
	if (_kbhit())
	{
		fflush(stdin);
		key = _getch();
		if (key != 'w' && key != 'W' && key != 's' && key != 'S' && key != 'A' && key != 'a' && key != 'd' && key != 'D') 	
				key = tempkey;
		else {
			if (tempkey == 'w' || tempkey == 'W')
				if (key == 's' || key == 'S')
					key = tempkey;
			if (tempkey == 's' || tempkey == 'S')
				if (key == 'w' || key == 'W')
					key = tempkey;
			if (tempkey == 'a' || tempkey == 'A')
				if (key == 'D' || key == 'd')
					key = tempkey;
			if (tempkey == 'D' || tempkey == 'd')
				if (key == 'a' || key == 'A')
					key = tempkey;
			tempkey = key;//非wasd鍵
		}
	}
	if (!changeflag)
	{
		gotoxy(snake.x[snake.len-1], snake.y[snake.len - 1]);
		printf("  ");
	}
	else
	{
		snake.x[snake.len] = snake.x[snake.len-1];
		snake.y[snake.len] = snake.y[snake.len-1];
		snake.len++;
	}
	for (int i = snake.len-1; i >0; i--)
	{
		snake.x[i] = snake.x[i - 1];
		snake.y[i] = snake.y[i - 1];
	}
	switch (key)
	{
	case 'W':
	case 'w': snake.y[0]--; break;
	case 'S':
	case 's': snake.y[0]++; break;
	case 'A':
	case 'a': snake.x[0]-=2; break;//佔兩個字符
	case 'D':
	case 'd': snake.x[0]+=2; break;
	default: break;
	}
	gotoxy(snake.x[0], snake.y[0]);
	printf("●");
	changeflag = false;
}
void CreatFood()
{
	srand((unsigned)time(NULL));
	if (snake.x[0]==food.x&&snake.y[0] == food.y)
	{
		//PlaySound(L"m2.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
		score++;
		gotoxy(100, 22);
		printf("當前分數:%d", score);//打印分數
		if (score%15==0)
		{
			snake.speed -= 20;
		}
		while (1)
		{
			bool flag = 1;
			food.x = rand() % (MAP_WIDTH - 4) + 2;
			food.y = rand() % (MAP_HIGHT - 2) + 1;
			for (int i = 0; i < snake.len; i++)
			{
				if (food.x ==snake.x[i] && food.y == snake.y[i])
				{
					flag = 0;
					break;
				}
				

			}
			if (flag&&food.x % 2 == 0)
			{
				break;
			}
		}

		gotoxy(food.x, food.y);
		printf("◆");
		changeflag = true;
	}
	
}
int SnakeState(void)
{
	if (snake.x[0] == 0 || snake.x[0] == MAP_WIDTH || snake.y[0] == 0 || snake.y[0] == MAP_HIGHT)
		return false;
	for (int  i = 1; i < snake.len; i++)
	{
		if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i])
			return false;
	}
	return true;
}
int main()
{
	PlaySound(L"m1.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
	//隱藏光標
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO cci;
	GetConsoleCursorInfo(hOut, &cci);
	cci.bVisible = FALSE;
	SetConsoleCursorInfo(hOut, &cci);
	system("CLS");
	drawmap();
	while (1)
	{
		KeyDown();
		Sleep(snake.speed);
		CreatFood();
		if (SnakeState()==false)
		{
			break;
		}
	}
	
	system("CLS");
	gotoxy(50, 8);
	printf("——遊戲結束——");
	gotoxy(52, 10);
	printf("你的分數爲%d\n", score);
	

	
	
	
	system("pause");
	
	return 0;
}

單文件沒有詳細的講解,講解看看多文件版本。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章