游戲功能介紹:
1、玩家上下左右移動的正確實作,
2、玩家推箱子,箱子位置的變化,以及玩家是否能夠推動的判斷,
3、勝利檢測,(判斷游戲是否勝利)
4、選關模塊,方便玩家選擇自己想要游玩的關卡進行游玩,
5、游戲介紹模塊,
6、游戲目錄模塊,
鄭重宣告:
1、該游戲代碼屬于原創,尤其是其中的檔案檢索功能,應該在目前網路上,還未出現過和我一樣的關卡檔案引數格式,
2、采用類和物件的方式來書寫,可以供學習面向物件的朋友,提高oo思想,
3、希望看見這篇博客的朋友能夠充分學習其中的知識點,提升自己,同時也歡迎各位朋友在下方評論區評論以及下來的討論,
4、代碼剛剛寫完,而且制作的第3關和第4關,是參考到網上的推箱子的地圖,作者因為實力有限而沒有在第3關和第4關獲勝,所以若有bug,請朋友們指正,
下載鏈接:
1、游戲下載鏈接:點擊藍色字前往下載
2、源代碼下載鏈接:點擊藍色字前往下載
注意:
1、游戲下載需要三個積分,
2、源代碼下載還是老規矩,(粉絲即可)
效果視頻展示:
展示
地圖制作方式 以及 地圖添加方式:
地圖制作方式:
地圖制作
地圖添加方式:
游戲組建添加方式(推箱子游戲)
代碼分析:
1、宏定義:
#define SIZE 10 //宏意義地圖大小,
#define NUMBER 10 //宏定義最大箱子數目,(可以根據玩家自己制作的地圖,而修改最大箱子數,)(個人認為10個箱子應該夠了,)
2、創建類和物件:
這里面創建了兩個內,一個是箱子的類,另一個是玩家的類,
這兩個類里面都會分別記錄物件的橫縱坐標,
玩家這個類里面有兩個行為,一個是移動,另一個是推箱子,
箱子這個類里面有一個行為,那就是移動,
特別宣告,箱子的類必須定義在玩家類的前面,因為在玩家推的行為里面會涉及到箱子的移動行為,
class Box
{
public:
int placeI; //記錄箱子的橫坐標,
int placeJ; //記錄箱子的縱坐標,
Box(); //該類的構造器,
int move( int command );//箱子的移動行為,
};
class Player
{
public:
int placeI; //記錄玩家橫坐標
int placeJ; //記錄玩家縱坐標
Player(); //該類的構造器,
int move( int command ); //玩家的移動行為,
int push( int command , Box box[] , int ); //玩家的推箱子行為,
};
//玩家類的構造器,
Player::Player()
{
//玩家的位置為(-1,-1),由于這個點在地圖上并不存在,所以在運行程序中,若玩家的位置依舊為(-1,-1),那么可以表示檔案讀取錯誤,
placeI = -1;
placeJ = -1;
}
//箱子類的構造器,
Box::Box()
{
//和玩家的構造器一樣,
placeI = -1;
placeJ = -1;
}
int Player::move( int command )
{
switch ( command )
{
//表示玩家位置向上移動一格,
case 1:
placeI -= 1;
break;
//表示玩家位置向左移動一格,
case 2:
placeJ -= 1;
break;
//表示玩家位置向下移動一格,
case 3:
placeI += 1;
break;
//表示玩家位置向右移動一格,
case 4:
placeJ += 1;
default:
break;
}
return 0;
}
int Player::push( int command , Box box[] , int I )
{
int tempI = placeI , tempJ = placeJ;//讓新產生的這兩個變數指向玩家所站的地方,(這兩個變數一起看的話是一個坐標,)
//將該坐標向玩家將要移動的方向移動一格,
switch ( command )
{
case 1:
tempI -= 1;
break;
case 2:
tempJ -= 1;
break;
case 3:
tempI += 1;
break;
case 4:
tempJ += 1;
break;
default:
break;
}
//檢測該坐標指向的方塊是哪一個箱子,
int temp = 0;//用于檢索box里面的每個元素,
while( temp < I )
{
if( box[temp].placeI == tempI && box[temp].placeJ == tempJ )//如果是該箱子,
{
box[temp].move( command );//呼叫箱子移動的行為,
break;
}
temp++;
}
move( command );//玩家移動,
return 0;
}
int Box::move( int command )
{
//和玩家到移動行為一樣,
switch ( command )
{
case 1:
placeI -= 1;
break;
case 2:
placeJ -= 1;
break;
case 3:
placeI += 1;
break;
case 4:
placeJ += 1;
break;
default:
break;
}
return 0;
}
宣告所需的子函式:
子函式有點多,希望朋友們不要畏懼困難,
相反,我們要迎難而上,
gettingData()子函式,是用于檢索地圖并且加載到記憶體中的一個函式,
在視頻中已經講到了,我們的程式是可以允許玩家自行創造地圖的,所以我們必須要從程式外部將地圖讀取進來,
printMap()是一個列印函式,這毋庸置疑,
getCommand()用于接收玩家在鍵盤中的輸入,
void detect()檢測玩家將要走向方向的前兩個方塊的內容,
int menu()主選單函式,
int levelChoose()選關函式,
voluationForStar()初始化中點坐標函式,
weatherPass()判斷是否勝利函式,
int gettingData( int smallSquare[SIZE][SIZE] , int number , Player *player , Box box[NUMBER] ,
int *I , int star[NUMBER][2] ); //用于檢索游戲資料
void printMap( int smallSquare[SIZE][SIZE] , Player player , Box box[NUMBER] , int I); //列印地圖
int getCommand();//接收用戶輸入,
void detect( Player *player , Box box[] , int smallSquare[SIZE][SIZE] ,int *pointerFirst , int *pointerSecond , int command , int I ); //用于探測玩家指向方向前兩塊區域的內容,
int menu( ); //創建選單函式
int levelChoose( );//關卡選擇
void introduce(); //游戲介紹
void voluationForStar( int star[NUMBER][2] );
int weatherPass( int star[NUMBER][2] , Box box[NUMBER] , int );
檢索游戲地圖函式:
這個涉及 C++的檔案操作,
該函式對于有興趣制作地圖的朋友來說,建議好好學習,
int gettingData( int smallSquare[SIZE][SIZE] ,int number , Player *player , Box box[NUMBER] , int *I , int star[NUMBER][2] )
{
char gameLevel[12] = { 'N' , 'u' , 'm' , 'b' , 'e' , 'r' ,0 , '.' , 't' , 'x' , 't' , 0 }; //用于檢索游戲資料,
gameLevel[6] = number + 48 ; //整型轉化為字符型,需要統一一下,
std::ifstream fileOfGettingGameData;
fileOfGettingGameData.open( gameLevel ); //打開游戲配置
if( !fileOfGettingGameData )
{
system("cls");
std::cout << "未檢測到關卡" << number << "的存在" << "\n請檢查您在選擇關卡時是否輸入正確," << std::endl;
system("pause");
return 0;
}
/*
else
{
std::cout << "關卡初始化成功" << std::endl;
Sleep( 500 );
}
*/
//初始化地圖,(檢索游戲檔案)
int tempI , tempJ , temp = 0 ;//temp用于終點的計數,
for( tempI = 0 ; tempI < SIZE ; tempI++ )
{
for( tempJ = 0 ; tempJ < SIZE ; tempJ++ )
{
fileOfGettingGameData >> smallSquare[tempI][tempJ];
//人物位置單獨計算
if( 3 == smallSquare[tempI][tempJ] )
{
player->placeI = tempI;
player->placeJ = tempJ;
smallSquare[tempI][tempJ] = 2 ;
}
//箱子位置單獨計算
if( 1 == smallSquare[tempI][tempJ] )
{
box[ (*I) ].placeI = tempI;
box[ (*I) ].placeJ = tempJ;
smallSquare[tempI][tempJ] = 2 ;
(*I)++;
}
//終點位置單獨計算
if( 4 == smallSquare[tempI][tempJ] )
{
star[temp][0] = tempI;
star[temp][1] = tempJ;
temp++;
}
}
}
return 1;
}
列印地圖函式:
system(“cls”);
該陳述句可以實作win32的清屏,
在函式定義在windows.h頭檔案中,
void printMap( int smallSquare[SIZE][SIZE] , Player player , Box box[NUMBER] , int I )
{
int tempI , tempJ , temp ;//temp用于檢索數列box
int weatherPrintBox = 0; //0表示沒有列印箱子,1表示列印了,
system("cls");
printf(" 0 1 2 3 4 5 6 7 8 9\n");
for( tempI = 0 ; tempI < SIZE ; tempI++ )
{
printf("%d" , tempI);
for( tempJ = 0 ; tempJ < SIZE ; tempJ++ )
{
weatherPrintBox = 0;
for( temp = 0 ; temp < I ; temp++ )
{
if( tempI == box[temp].placeI && tempJ == box[temp].placeJ )
{
printf("■"); //列印箱子,
weatherPrintBox = 1;
break;
}
}
if( tempI == player.placeI && tempJ == player.placeJ )
{
std::cout << "▼"; //列印人物,
}
else if( 2 == smallSquare[tempI][tempJ] && 0 == weatherPrintBox )//&&運算子后面的陳述句表示:如果列印了箱子就不必再列印箱子下面的道路,
{
std::cout << " "; //列印道路,
}
else if( 0 == smallSquare[tempI][tempJ] )
{
std::cout << "▓"; //列印墻壁,
}
else if( 4 == smallSquare[tempI][tempJ] && 0 == weatherPrintBox )//&&運算子后面的陳述句表示:如果列印了箱子就不必再列印箱子下面的終點,
{
std::cout << "☆"; //列印終點,
}
}
std::cout << "\n";
}
}
獲取玩家指令的函式:
_getch();
這個函式定義在conio.h
如果有朋友知道,其他的表示方式,比如說:cin.get();也是可以相互替換的,
int getCommand()
{
int commandReturn = -1; //表示沒有輸入
switch( _getch() )
{
case 'W':
case 'w':
commandReturn = 1; //表示向上
break;
case 'A':
case 'a':
commandReturn = 2; //表示向左
break;
case 'S':
case 's':
commandReturn = 3; //表示向下
break;
case 'D':
case 'd':
commandReturn = 4; //表示向右
break;
case 'B':
case 'b':
commandReturn = 5; //表示回傳選關界面
break;
case 10 :
case 13 :
commandReturn = 6; //表示回車
break;
default:
commandReturn = -2; //表示用戶錯誤輸入
break;
}
return ( commandReturn );
}
探測玩家指向方向前兩格方塊內容的函式:
這是代碼里面比較復雜的一塊,
不講了,
void detect( Player *player , Box box[] , int smallSquare[SIZE][SIZE] , int *pointerFirst , int *pointerSecond , int command , int I )
{
int tempFirstI , tempFirstJ , tempSecondI , tempSecondJ ; //用于記錄玩家位置的前兩個位置的坐標,
int temp; //用于檢索box里的每一個元素,
switch ( command )
{
case 1:
//計算玩家朝向的兩個方向的方塊的坐標,并且將其賦值,
tempFirstI = player->placeI - 1;
tempFirstJ = player->placeJ;
tempSecondI = player->placeI - 2;
tempSecondJ = player->placeJ;
if( tempFirstI >= 0 && tempFirstJ >= 0 ) //檢索范圍未超出地圖的情況,
{
*pointerFirst = smallSquare [tempFirstI][tempFirstJ];
}
//范圍超出地圖的區塊,將其按墻壁計算,
else
{
*pointerFirst = 0;
}
if( tempSecondI >= 0 && tempSecondJ >= 0 ) //檢索范圍未超出地圖的情況,
{
*pointerSecond = smallSquare[tempSecondI][tempSecondJ];
}
//范圍超出地圖的區塊,將其按墻壁計算,
else
{
*pointerSecond = 0;
}
//檢索玩家所指向方向的前兩個方塊是否為箱子
for( temp = 0 ; temp < I ; temp++ )
{
if( box[temp].placeI == tempFirstI && box[temp].placeJ == tempFirstJ )
{
*pointerFirst = 1;
}
else if( box[temp].placeI == tempSecondI && box[temp].placeJ == tempSecondJ )
{
*pointerSecond = 1;
}
}
break;
/************其后的注釋與上面保持一樣,請朋友們融會貫通,(寫長一點,給自己營造一種感覺,自己都寫了那么多行了,噓~~~~~~~~)*****************************/
case 2:
tempFirstI = player->placeI;
tempFirstJ = player->placeJ - 1;
tempSecondI = player->placeI;
tempSecondJ = player->placeJ - 2;
if( tempFirstI >= 0 && tempFirstJ >= 0 ) //檢索范圍未超出地圖的情況,
{
*pointerFirst = smallSquare [tempFirstI][tempFirstJ];
}
//范圍超出地圖的區塊,將其按墻壁計算,
else
{
*pointerFirst = 0;
}
if( tempSecondI >= 0 && tempSecondJ >= 0 )
{
*pointerSecond = smallSquare[tempSecondI][tempSecondJ];
}
else
{
*pointerSecond = 0;
}
for( temp = 0 ; temp < I ; temp++ )
{
if( box[temp].placeI == tempFirstI && box[temp].placeJ == tempFirstJ )
{
*pointerFirst = 1;
}
else if( box[temp].placeI == tempSecondI && box[temp].placeJ == tempSecondJ )
{
*pointerSecond = 1;
}
}
break;
case 3:
tempFirstI = player->placeI + 1;
tempFirstJ = player->placeJ;
tempSecondI = player->placeI + 2;
tempSecondJ = player->placeJ;
if( tempFirstI >= 0 && tempFirstJ >= 0 ) //檢索范圍未超出地圖的情況,
{
*pointerFirst = smallSquare [tempFirstI][tempFirstJ];
}
//范圍超出地圖的區塊,將其按墻壁計算,
else
{
*pointerFirst = 0;
}
if( tempSecondI >= 0 && tempSecondJ >= 0 )
{
*pointerSecond = smallSquare[tempSecondI][tempSecondJ];
}
else
{
*pointerSecond = 0;
}
for( temp = 0 ; temp < I ; temp++ )
{
if( box[temp].placeI == tempFirstI && box[temp].placeJ == tempFirstJ )
{
*pointerFirst = 1;
}
else if( box[temp].placeI == tempSecondI && box[temp].placeJ == tempSecondJ )
{
*pointerSecond = 1;
}
}
break;
case 4:
tempFirstI = player->placeI;
tempFirstJ = player->placeJ + 1;
tempSecondI = player->placeI;
tempSecondJ = player->placeJ + 2;
if( tempFirstI >= 0 && tempFirstJ >= 0 ) //檢索范圍未超出地圖的情況,
{
*pointerFirst = smallSquare [tempFirstI][tempFirstJ];
}
//范圍超出地圖的區塊,將其按墻壁計算,
else
{
*pointerFirst = 0;
}
if( tempSecondI >= 0 && tempSecondJ >= 0 )
{
*pointerSecond = smallSquare[tempSecondI][tempSecondJ];
}
else
{
*pointerSecond = 0;
}
for( temp = 0 ; temp < I ; temp++ )
{
if( box[temp].placeI == tempFirstI && box[temp].placeJ == tempFirstJ )
{
*pointerFirst = 1;
}
else if( box[temp].placeI == tempSecondI && box[temp].placeJ == tempSecondJ )
{
*pointerSecond = 1;
}
}
break;
default:
break;
}
}
還有幾個函式,我并沒有在這里展示,不過有興趣的朋友可以下載源代碼好好學習,
主要是博主實在寫不動了,
你呢,還希望大家能夠通過我的代碼,不斷提高自己的編程能力,不斷的提升,
游戲和原始碼的下載鏈接在上面,有大家可以下載下來反復學習喲,
其次看在小博主我寫了這么多的份上,你不點個贊再走嗎?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/255607.html
標籤:其他
下一篇:LintCode 介紹
