用C/C++實現較完整貪喫蛇遊戲

記得在大一時剛學習c/c++語言,學到一半突然想用這門語言做一些小遊戲出來,首先想到的便是貪喫蛇。於是本人利用空餘時間寫出了這麼一個簡單的小遊戲。

由於當時的我還沒有能力構造出用戶界面,故直接使用dos界面運行。那麼問題來了,如何讓一個字符在dos界面上自由移動???對於這個問題我採用的解決方案是實現gotoxy函數來控制指針位置從而實現字符的移動。那麼我們就先來實現這個函數。

gotoxy 函數並非系統函數,我將其儲存於 gotoxy.h 的頭文件中方便調用。

gotoxy.h

#include <windows.h>
void gotoxy(int x,int y) 
{
	COORD pos;
	pos.X = x - 1;
	pos.Y = y - 1;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}

現在我們已經能夠利用 gotoxy 函數對指針進行控制,那麼實現字符的移動則只需將原來位置的字符清除,然後利用此函數移動指針到想去的座標後打印字符即可

在對此函數進行測試的時候,我發現了一個重要的問題,因爲代碼是一行一行的運行,那麼在等待我輸入方向的時候,其他代碼是無法執行的,這意味這我的蛇只能是我給一下方向它移動一下,那麼該如何使得字符在等待我輸出方向的同時自行移動呢???對於這個問題有兩個解決方案:一、創建線程(對於當時的我來說線程還很陌生) 二、利用 kbhit() 非阻塞函數(百度一下,你就知道)。當然我選擇的是第二個方案,再配合使用 getch() 函數即可完美實現方向的輸入。

該遊戲的兩個難點都解決了,話不多說 ↓

(由於沒有涉及什麼算法,加之年少,代碼顯得過於冗長)

這裏主要運用到的知識有這些:結構體,srand(), rand(), kbhit(), getch(), Sleep().

/*******************http://blog.csdn.net/lcsy000**********************/

#include<iostream>
#include"gotoxy.h"
#include<windows.h>
#include<conio.h>
#include<time.h>
using namespace std;
char direction_a,direction_b;			//方向a、b,用於方向的限制 
int scores,num,fool_x,fool_y,speed=100;	//得分、num用於蛇身起步、食物x座標、食物y座標 
bool end;								//結束標記 
struct node 							//蛇身結點 
{
	int x,y;
	node *next;
}*head=NULL,*p,*tail;

void init();							//初始化開始界面 
void start();							//遊戲開始入場 
void init_snake();						//初始化蛇身 
void delete_snake();					//刪除蛇身 
void control();							//方向控制 
void move();							//蛇身移動 
void limit();							//方向限制
void panduan();							//配合limit限制方向 
void fool();							//食物的出現以及食物被吞
void isEnd();							//結束判斷 
void zhuangwei();						//撞尾判斷 
void zhuangqiang();						//撞牆判斷 

int main ()
{
	srand((unsigned)time(NULL));
	init();
	cin>>direction_a;
	if(direction_a!='y'&&direction_a!='Y')
		return 0;
	do
	{
		system("cls");					//清除屏幕 
		end=false;
		start();
		delete_snake();
		init_snake();
		scores=0;
		num=0;
		fool_x=(rand() % (79-2+1))+ 2;
		fool_y=(rand() % (22-2+1))+ 2;
		gotoxy(fool_x,fool_y); 
		cout<<"0";
		direction_a=getch();
		while(direction_a!='d'&&direction_a!='s'&&direction_a!='w') direction_a=getch();
		while(true)
		{
			if(num&&direction_a!='d'&&direction_a!='s'&&direction_a!='w'&&direction_a!='a')
			{
				direction_a=direction_b;
			}
			control();
			fool();
			Sleep(speed);
			if(kbhit())					//kbhit 非阻塞函數 
			{
				direction_a=getch();	//使用 getch 函數獲取鍵盤輸入 
				limit();
			}
			panduan();
			num=1;
			zhuangqiang();
			zhuangwei();
			if(end) break;
		}
	}while(direction_a=='y'||direction_a=='Y'); 
	return 0;
}
void init()							
{
	gotoxy(35,8);
	cout<<"★貪  喫  蛇★";
	gotoxy(36,10);
	cout<<"開始請輸入y:";
}
void start()						
{
	for(int i=0;i<=79;i++)
		{
			Sleep(10);
			cout<<"*";
			gotoxy(i+1,24);
			cout<<"*";
			gotoxy(i+2,1);
		}	
		gotoxy(1,2);
		for(int i=0;i<=21;i++)
		{
			Sleep(20);
			cout<<"*";
			for(int j=0;j<=77;j++)	cout<<" ";
			cout<<"*";
		}
}
void init_snake()								
{
	int n=3;
	head=new node;
	tail=head;
	head->x=40;
	head->y=12;
	while(n--)
	{
		p=new node;
		tail->next=p;
		p->x=tail->x-1;
		p->y=tail->y;
		tail=p;
	}
	tail->next=NULL;
	node *q=head->next;
	gotoxy(head->x,head->y);
	cout<<'#';
	while(q!=NULL)
	{
		gotoxy(q->x,q->y);
		cout<<'*';
		q=q->next;
	}
}
void delete_snake()								
{
	while(head!=NULL)
	{
		node *q=head;
		head=q->next;
		delete q;
	}
}
void move()							
{
	gotoxy(tail->x,tail->y);
	cout<<" ";
	gotoxy(head->next->x,head->next->y);
	cout<<'*';
	gotoxy(head->x,head->y);
	cout<<'#';
	node *q=tail;
	tail=head;
	while(tail->next!=q)
	{
		tail=tail->next;
	}
	tail->next=NULL;
	delete q;
}
void control()						
{
	node *q=new node;
	q->next=head;
	q->x=head->x;
	q->y=head->y;
	head=q;
	switch(direction_a)
	{
		case 'w':	head->y--;break;
		case 's':	head->y++;break;
		case 'a':	head->x--;break;
		case 'd':	head->x++;break;
		default :	break;
	}
	move();
}
void limit()							
{
	
	if(direction_b=='s'&&direction_a=='w') direction_a='s'; 
	if(direction_b=='w'&&direction_a=='s') direction_a='w'; 
	if(direction_b=='a'&&direction_a=='d') direction_a='a'; 
	if(direction_b=='d'&&direction_a=='a') direction_a='d'; 
}
void panduan()							
{
	if(direction_a=='s') direction_b='s';
	if(direction_a=='w') direction_b='w';
	if(direction_a=='d') direction_b='d';
	if(direction_a=='a') direction_b='a';
}
void fool()							
{
	node *q;
	if(head->x==fool_x&&head->y==fool_y)
	{
		fool_x=(rand() % (79-2+1))+ 2;
		fool_y=(rand() % (22-2+1))+ 2;
		gotoxy(fool_x,fool_y); 
		cout<<"0";
		num=0;
		scores++;
		node *q=new node;
		q->x=tail->x;
		q->y=tail->y;
		tail->next=q;
		tail=q;
		tail->next=NULL;
	}
	q=head;
	while(q!=NULL)
	{
		if(q->x==fool_x&q->y==fool_y)
		{
			fool_x=(rand() % (79-2+1))+ 2;
			fool_y=(rand() % (22-2+1))+ 2;
			gotoxy(fool_x,fool_y); 
			cout<<"*";
			q=head;
			continue;
		}
		q=q->next;
	}
}
void isEnd()						
{
	end=true;
	Sleep(600);
	system("cls");
	gotoxy(35,8);
	cout<<"您 輸 啦 ~";
	gotoxy(33,10);
	cout<<"您的分數爲: "<<scores;
	gotoxy(31,12);
	cout<<"重新開始請輸入y:";
	cin>>direction_a;
}
void zhuangwei()				
{
	node *q=head->next;
	while(q!=NULL)
	{
		if(head->x==q->x&&head->y==q->y)
		{
			isEnd();
			break;
		}
		q=q->next;
	}
}
void zhuangqiang()						
{
	if(head->x==80||head->x==1||head->y==24||head->y==1) 
	isEnd();
}

效果圖:


由於考慮到遊戲的各種 BUG 故自定義函數很多,有興趣的朋友可以自行改動一些函數對比效果。

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