1. 程式人生 > >字元基礎——簡易版飛機大戰

字元基礎——簡易版飛機大戰

使用C/C++開發一個字元版的飛機大戰,玩家可以上下左右移動,空格鍵開火,子彈為鐳射,敵機可以自我移動,玩家發射的鐳射如果擊中敵機,繪畫簡易版爆炸效果。

開發環境:Dev-C++ 5

介紹:使用表示主角飛機,使用表示敵機,使用表示敵機被擊中的形態,使用表示正在開火的主角飛機,"|"表示鐳射。當敵機被擊中後,分數score++並且在一個隨機的位置生成新的敵機,這裡限制了敵機只能在第0行到第4行以及第0列到第width-3列交錯的區域內移動,通過多次迴圈移動一次敵機,確保了玩家飛機的機動性更強。

製作過程:

使用x、y變數記錄主角飛機的左上角頂點位於第x行第y列;

使用target_x、target_y變數記錄敵機的左上角頂點位於第target_x行第target_y列;

使用target_x_v、target_y_v變數記錄敵機垂直方向和水平方向的速度;

使用isFire記錄玩家是否按下了開火鍵,如果玩家按空格鍵開火,將1賦值給isFire變數,當發射完鐳射後,將0重新賦值回isFire;

使用score記錄分數,擊中敵機,分數+1;

使用input記錄玩家按下的按鍵,使用getch()可以不按下回車就觸發按鍵事件;

使用width和height記錄遊戲區域共有width列height行;

使用count記錄第幾次迴圈了,每到第五次迴圈,敵機進行一次移動。

	int i,j;
	int x = 15;
	int y = 10;
	int score = 0;
	int isFire = 0; 
	int target_x = 1;//敵機點座標 
	int target_y = 1;
	int target_x_v = 1;//敵機縱向速度,值為正數向下移動,值為負數向上移動 
	int target_y_v = 1;	//敵機橫向速度,值為正數向右移動,值為負數向左移動 
	int width = 40;
	int height = 22;
	int count = 0;//每迴圈五次,敵機移動一次 
	char input;

由於使用傳統的system("cls")清屏會有嚴重的閃爍效果,這裡使用windows.h下的SetConsoleCursorPosition(Handle handle,COORD pos)來將游標進行移動pos點處,每次迴圈前先執行下該方法,從而實現清屏效果。

//將游標移動到(x,y)處,實現清屏效果 
void goToXY(int x,int y){
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos;
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(handle,pos);
}

除此之外,游標的閃爍效果也是比較嚴重的,這裡可以使用HideCursor()函式對游標進行隱藏。

//隱藏游標 
void HideCursor(){
	CONSOLE_CURSOR_INFO cursor_info = {1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}

重點說下列印玩家飛機和敵機以及碰撞檢測:

先使用雙層for迴圈對遊戲區域的資訊進行列印,i表示遍歷到第幾行,j表示遍歷到第幾列;如果當前敵機剛好位於第j列,那麼根據當前列印的行數和敵機各部分所在的行數進行對比,假如當前行數是敵機第1行,就列印敵機第一行,注意使用空格對輸出的空白處進行填充,列印玩家飛機同理;

            for(int i=0;i<height;i++){
				for(int j=0;j<width;j++){
					if(i==target_x&&j==target_y){
				  	//繪畫敵機第一行 
					cout<<" @ ";
					j+=3;
				    }else if(i==target_x+1&&j==target_y){
				    //繪畫敵機第二行
					cout<<"@@@";
					j+=3;
					}else if(i==x&&j==y){
					//繪畫主角第一行
					 cout<<"  *  ";
					 j+=5; 
					}else if(i==x+1&&j==y){
					//繪畫主角第二行
					 cout<<"*****";
					 j+=5; 
					}else if(i==x+2&&j==y){
					//繪畫主角第三行
					 cout<<" * * ";
					 j+=5; 
					} 
				    	if(j<width)				   				    
						cout<<" ";					
				}
				cout<<endl;
			} 

在這裡為了簡便起見,玩家發射的是即時性的鐳射,根據前面的截圖可以看到玩家飛機有3行5列,敵機有2行3列,玩家按了空格之後,進入到開火事件中。玩家飛機發射的鐳射是在最中間一列發射出去的,即鐳射所在列數 = 玩家左上角列數y+2;如果

敵機左上角y列數<=鐳射所在列數<=敵機左上角y列數+2,說明鐳射打中了敵機;

碰撞檢測化簡得到:敵機左上角y列數-2<=主角左上角y列數<=敵機左上角y列數時,鐳射射中敵機;

如果鐳射射中敵機,需要修改敵機的顯示狀態為"-",並且隨機生成新的敵機位置和移動方向;

開火完畢後記得把isFire修改回未開火狀態。

	
		if(isFire){
					
			
			if(target_y-2<=y&&y<=target_y){//鐳射射中敵機 
				
				score++;
				
				for(int i=0;i<height;i++){
				for(int j=0;j<width;j++){
					if(i==target_x&&j==target_y){
				  	//繪畫敵機第一行 
					cout<<" - ";
					j+=3;
				    }else if(i==target_x+1&&j==target_y){
				    //繪畫敵機第二行
					cout<<"---";
					j+=3;
					}else if(i==x&&j==y){
					//繪畫主角第一行
					 cout<<"  *  ";
					 j+=5; 
					}else if(i==x+1&&j==y){
					//繪畫主角第二行
					 cout<<"*****";
					 j+=5; 
					}else if(i==x+2&&j==y){
					//繪畫主角第三行
					 cout<<" * * ";
					 j+=5; 
					} 
				    				    
				    if(j==y+2&&i<x){
				    	cout<<"|";
					}else{
						cout<<" ";
					}
				}
				cout<<endl;
			}
				//重置敵機座標,隨機移動方向 
				target_x = rand()%5;
				target_y = rand()%(width-2);
					int flag1 = rand()%2;
					int flag2 = rand()%2;
					if(flag1)
						target_x_v = - target_x_v;
					if(flag2)
						target_y_v = - target_y_v;
				
			}else{//鐳射未射中敵機 
				
				for(int i=0;i<height;i++){
				for(int j=0;j<width;j++){
					if(i==target_x&&j==target_y){
				  	//繪畫敵機第一行 
					cout<<" @ ";
					j+=3;
				    }else if(i==target_x+1&&j==target_y){
				    //繪畫敵機第二行
					cout<<"@@@";
					j+=3;
					}else if(i==x&&j==y){
					//繪畫主角第一行
					 cout<<"  *  ";
					 j+=5; 
					}else if(i==x+1&&j==y){
					//繪畫主角第二行
					 cout<<"*****";
					 j+=5; 
					}else if(i==x+2&&j==y){
					//繪畫主角第三行
					 cout<<" * * ";
					 j+=5; 
					} 
				    				    
				    if(j==y+2&&i<x){
				    	cout<<"|";
					}else{
						cout<<" ";
					}
				}
				cout<<endl;
			} 
				
			} 
			
			isFire = 0;

		}

列印分數,對敵機進行指定方向的移動,在碰到邊界時,調整速度方向:

		
		for(i=0;i<2;i++)
		cout<<endl;
		cout<<"score:"<<score<<endl; 
		if(count==5){//每迴圈五次移動一次敵機
			if(target_x==4&&target_x_v>0){//敵機到第4行時往回走
				target_x_v = -target_x_v;
			}
			if(target_x==0&&target_x_v<0){//敵機到第0行時往回走
				target_x_v = -target_x_v;
			}			
			if(target_y==width-3&&target_y_v>0){//敵機到第width-3列時往回走
				target_y_v = -target_y_v;
			}
			if(target_y==0&&target_y_v<0){//敵機到第0列時往回走
				target_y_v = -target_y_v;
			}
			
			target_x += target_x_v;//按照垂直速度和水平速度修改敵機座標
			target_y += target_y_v;

			count = 0;//重置迴圈次數
		}
		
		if(kbhit()){
			input = getch();
			if(input == 'a'&&y>0){
				y--;
			}
			if(input == 'd'&&y<width-5){
				y++;
			}
			if(input == 'w'&&x>0){
				x--;
			}
			if(input == 's'&&x<height-3){
				x++;
			}
			if(input == ' '){
				isFire = 1;
			}
		}
		Sleep(500); 
		count++;
	}

完整原始碼

#include<iostream>
#include<stdlib.h>
#include<conio.h>
#include<windows.h>

using namespace std;

//將游標移動到(x,y)處,實現清屏效果 
void goToXY(int x,int y){
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos;
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(handle,pos);
}

//隱藏游標 
void HideCursor(){
	CONSOLE_CURSOR_INFO cursor_info = {1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}

int main(){
	
	int i,j;
	int x = 15;
	int y = 10;
	int score = 0;
	int isFire = 0; 
	int target_x = 1;//敵機點座標 
	int target_y = 1;
	int target_x_v = 1;//敵機縱向速度,值為正數向下移動,值為負數向上移動 
	int target_y_v = 1;	//敵機橫向速度,值為正數向右移動,值為負數向左移動 
	int width = 40;
	int height = 22;
	int count = 0;//每迴圈五次,敵機移動一次 
	char input;
	
	HideCursor();
	
	//打中目標,碰撞檢測:敵機y<=主角y+2<=敵機y+2;化簡得:  敵機y-2<=主角y<=敵機y時,鐳射射中敵機
	
	while(1){
//		system("cls");
		goToXY(0,0);
		
		if(isFire){
					
			
			if(target_y-2<=y&&y<=target_y){//鐳射射中敵機 
				
				score++;
				
				for(int i=0;i<height;i++){
				for(int j=0;j<width;j++){
					if(i==target_x&&j==target_y){
				  	//繪畫敵機第一行 
					cout<<" - ";
					j+=3;
				    }else if(i==target_x+1&&j==target_y){
				    //繪畫敵機第二行
					cout<<"---";
					j+=3;
					}else if(i==x&&j==y){
					//繪畫主角第一行
					 cout<<"  *  ";
					 j+=5; 
					}else if(i==x+1&&j==y){
					//繪畫主角第二行
					 cout<<"*****";
					 j+=5; 
					}else if(i==x+2&&j==y){
					//繪畫主角第三行
					 cout<<" * * ";
					 j+=5; 
					} 
				    				    
				    if(j==y+2&&i<x){
				    	cout<<"|";
					}else{
						cout<<" ";
					}
				}
				cout<<endl;
			}
				//重置敵機座標,隨機移動方向 
				target_x = rand()%5;
				target_y = rand()%(width-2);
					int flag1 = rand()%2;
					int flag2 = rand()%2;
					if(flag1)
						target_x_v = - target_x_v;
					if(flag2)
						target_y_v = - target_y_v;
				
			}else{//鐳射未射中敵機 
				
				for(int i=0;i<height;i++){
				for(int j=0;j<width;j++){
					if(i==target_x&&j==target_y){
				  	//繪畫敵機第一行 
					cout<<" @ ";
					j+=3;
				    }else if(i==target_x+1&&j==target_y){
				    //繪畫敵機第二行
					cout<<"@@@";
					j+=3;
					}else if(i==x&&j==y){
					//繪畫主角第一行
					 cout<<"  *  ";
					 j+=5; 
					}else if(i==x+1&&j==y){
					//繪畫主角第二行
					 cout<<"*****";
					 j+=5; 
					}else if(i==x+2&&j==y){
					//繪畫主角第三行
					 cout<<" * * ";
					 j+=5; 
					} 
				    				    
				    if(j==y+2&&i<x){
				    	cout<<"|";
					}else{
						cout<<" ";
					}
				}
				cout<<endl;
			} 
				
			} 
			
			isFire = 0;

		}else{//未發射鐳射 
		
				for(int i=0;i<height;i++){
				for(int j=0;j<width;j++){
					if(i==target_x&&j==target_y){
				  	//繪畫敵機第一行 
					cout<<" @ ";
					j+=3;
				    }else if(i==target_x+1&&j==target_y){
				    //繪畫敵機第二行
					cout<<"@@@";
					j+=3;
					}else if(i==x&&j==y){
					//繪畫主角第一行
					 cout<<"  *  ";
					 j+=5; 
					}else if(i==x+1&&j==y){
					//繪畫主角第二行
					 cout<<"*****";
					 j+=5; 
					}else if(i==x+2&&j==y){
					//繪畫主角第三行
					 cout<<" * * ";
					 j+=5; 
					} 
				    	if(j<width)				   				    
						cout<<" ";					
				}
				cout<<endl;
			} 
		
		}
		
		for(i=0;i<2;i++)
		cout<<endl;
		cout<<"score:"<<score<<endl; 
		if(count==5){//每迴圈五次移動一次敵機
			if(target_x==4&&target_x_v>0){//敵機到第4行時往回走
				target_x_v = -target_x_v;
			}
			if(target_x==0&&target_x_v<0){//敵機到第0行時往回走
				target_x_v = -target_x_v;
			}			
			if(target_y==width-3&&target_y_v>0){//敵機到第width-3列時往回走
				target_y_v = -target_y_v;
			}
			if(target_y==0&&target_y_v<0){//敵機到第0列時往回走
				target_y_v = -target_y_v;
			}
			
			target_x += target_x_v;//按照垂直速度和水平速度修改敵機座標
			target_y += target_y_v;

			count = 0;
		}
		
		if(kbhit()){//如果玩家有按鍵輸入 
			input = getch();
			if(input == 'a'&&y>0){
				y--;
			}
			if(input == 'd'&&y<width-5){
				y++;
			}
			if(input == 'w'&&x>0){
				x--;
			}
			if(input == 's'&&x<height-3){
				x++;
			}
			if(input == ' '){
				isFire = 1;
			}
		}
		Sleep(20); 
		count++;
	}
	
	return 0;
} 

執行效果截圖: