C語言實現推箱子游戲的代碼示例

這篇文章主要介紹了C語言實現推箱子游戲的代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨着小編來一起學習學習吧

很早就想過做點小遊戲了,但是一直沒有機會動手。今天閒來無事,動起手來。過程還是蠻順利的,代碼也不是非常難。今天給大家分享一下~

一、介紹

開發語言:C語言
開發工具:Dev-C++ 5.11
日期:2019年9月28日
作者:ZackSock

也不說太多多餘的話了,先看一下效果圖:

遊戲中的人物、箱子、牆壁、球都是字符構成的。通過wasd鍵移動,規則的話就是推箱子的規則,也就不多說了。

二、代碼實現

關於代碼方面,我儘可能講的細緻。希望大家可以理解~

(1)方法列表

//主函數
void main();

//初始化一些數據
initData();

//在控制檯上打印地圖
drawMap();

//向上移動
moveUp();

//向左移動
moveLeft()

//向下移動
moveDown()

//向右移動
moveRight();

這幾個方法都顧名思義,而且用意也非常明確,就initData可能不知道具體用處,但是沒有什麼大問題。唯一的問題就是,上左下右的順序可能會逼死幾個強迫症患者,哈哈。

(2)參數列表

爲了方便,我把include和宏定義也放到參數列表當中

//導入函數庫
#include <stdio.h>
#include <stdlib.h>

//宏定義
#define WIDTH 8
#define HEIGHT 8

//定義地圖數組,二維數組有兩個維度,而地圖也是二維的矩形
int map[HEIGHT][WIDTH] = {
 {0, 0, 1, 1, 1, 0, 0, 0},
 {0, 0, 1, 4, 1, 0, 0, 0},
 {0, 0, 1, 0, 1, 1, 1, 1},
 {1, 1, 1, 3, 0, 3, 4, 1},
 {1, 4, 0, 3, 2, 1, 1, 1},
 {1, 1, 1, 1, 3, 1, 0, 0},
 {0, 0, 0, 1, 4, 1, 0, 0},
 {0, 0, 0, 1, 1, 1, 0, 0} 
};

//人的位置,在二維地圖中,我們可以用座標表示一個人的位置,就好比經緯度
int x, y;

//箱子的個數,推箱子肯定要有箱子嘛。
int boxs;

這裏參數不多,其中橫爲x,縱爲y,另外這裏再規定一下map的一些東西:

/**
* 0 表示空
* 1 表示牆
* 2 表示人
* 3 表示箱子
* 4 表示目的地(球)
* 5 表示已完成的箱子
*/

(3)函數具體分析

接下來我們一個一個函數來分析。

1、main函數

int main(int argc, char *argv[]) {
 char direction; //存儲鍵盤按的方向 
 initData();  //初始化一些數據
 
 //開始遊戲的循環,這裏是個死循環,每按一次按鈕循環一次
 while(1){
 //每次循環的開始清除屏幕
 system("cls");
 //繪畫地圖
 drawMap();

 //判斷,當boxs的數量0時,!0爲真,然後走break跳出循環(結束遊戲) 
 if(!boxs){
  break;
 }
 
 //鍵盤輸入方向,這裏使用getch,因爲getch讀取字符不會顯示在屏幕上
 direction = getch();
 
 //用switch判斷用戶輸入的方向
 switch(direction){
  case 'w':
  //按w時,調用向上移動函數
  moveUp();
  break;
  case 'a':
  //按a時,調用向左移動函數
  moveLeft(); 
  break;
  case 's':
  moveDown();
  break;
  case 'd':
  moveRight();
  break; 
 }
 } 
 //當跳出循環時,運行該語句,遊戲結束
 printf("恭喜你完成遊戲!※");
 return 0;
}

我大概說一下流程,循環外面沒有什麼特別的。initData()只是一些簡單數據的初始化,不需要太在意。循環中大致流程如下:

  • 清除屏幕
  • 繪製地圖
  • 判斷遊戲是否結束
  • 對用戶按下的按鈕進行反饋

進入循環體,先清除屏幕,再繪製地圖,然後再判斷遊戲是否結束。可能大家對這個順序不是很理解,這裏我們先不考慮判斷遊戲結束的問題。我們把清屏和繪製地圖合在一起,簡稱“重繪地圖”,而遊戲結束的判斷先不考慮,那麼流程就簡化爲“重繪地圖 + 響應用戶的操作”。簡單來說就是,用戶按一下按鈕,我改變一下地圖。

2、initData()

void initData(){
 int i, j;
 
 //加載數據時讓用戶等待,一般情況加載數據比較快
 printf("遊戲加載中,請稍後........."); 
 
 //遍歷地圖中的數據
 for(i = 0; i < HEIGHT; i++){
 for(j = 0; j < WIDTH; j++){
  //遍歷到2(人)時,記錄人的座標。x, y是前面定義的全局變量
  if(map[i][j] == 2){
  x = j;
  y = i;
  } 
  //遍歷到3時,箱子的數目增加。boxs是前面定義的全局變量 
  if(map[i][j] == 3){
  boxs++;
  }
 }
 } 
}

這個方法很簡單,就是遍歷地圖,然後初始化人的位置和箱子的個數。這裏有一點要注意一下,就是到底內層循環是WIDTH還是外層循環是WIDTH。

如圖,在遍歷過程中。外層循環控制行數,即HEIGHT。那麼內層循環應該是WIDTH。

3、drawMap()

void drawMap(){
 int i, j;
 for(i = 0; i < WIDTH; i++){
 for(j = 0; j < HEIGHT; j++){
  switch(map[i][j]){
  case 0:
   printf(" ");
   break;
  case 1:
   printf("■");
   break;
  case 2:
   printf("♀");
   break;
  case 3:
   printf("◆");
   break;
  case 4:
   printf("●");
   break;
  case 5:
   printf("★");
   break; 
  }
 }
 printf("\n");
 }
}

這裏也非常簡單,變量map中的元素,然後通過switch判斷應該輸出的內容。然後內層循環每走完一次就換行。

4、moveUp()

這個函數內容有點多,想講一下大概思路:

向上移有兩種情況

1、前面爲空白
 這種情況有兩個步驟
 (1)將人當前的位置設置爲空白(0),
 (2)再講人前面的位置設置爲人(2)
2、前面爲箱子
 當前面爲箱子時有三種情況
 1、箱子前面爲空白
  移動人和箱子,這個操作有三個步驟
  (1)將人當前位置設置爲空(0)
  (2)將箱子位置設置爲人(2)
  (3)將箱子前面設置爲箱子(3)
 2、箱子前面爲牆
  這種情況不需要做任何操作
 3、箱子前面爲終點
  這種情況有四個個步驟
  (1)將人的位置設置爲空(0)
  (2)將箱子的位置設置爲人(2)
  (3)將終點位置設置爲★(5)
  (4)箱子boxs的數量減一
3、前面爲牆
 這種情況最簡單,不需要做任何操作
4、前面爲終點
 我這裏沒有考慮太多,這種情況不做操作。(如果更換地圖的話可能需要修改代碼)

具體代碼如下,解析我全寫在註釋裏面:

void moveUp(){
 //定義變量存放人物上方的座標
 int ux, uy; 
 
 //當上方沒有元素時,直接return (其實人不可能在邊緣)
 if(y == 0){
 return;
 }
 
 //記錄上方座標,x爲橫,y爲縱,所有ux = x, uy = y - 1;
 ux = x;
 uy = y - 1; 
 
 //上方爲已完成的箱子
 if(map[uy][ux] == 5){
 return;
 } 
 //假設上方爲牆,直接return,這個和上面的判斷可以合在一起,這裏爲了看清楚分開寫 
 if(map[uy][ux] == 1){
 return;
 }
 
 //假設上方爲箱子
 if(map[uy][ux] == 3){
 //判斷箱子上方是否爲牆 
 if(map[uy - 1][ux] == 1){
  return;
 }
 
 //判斷箱子上方是否爲終點
 if(map[uy - 1][ux] == 4){
  //將箱子上面內容賦值爲5★ 
  map[uy - 1][ux] = 5;
  map[uy][ux] = 0;
   
  //箱子的數目減1 
  boxs--; 
 }else{
  //移動箱子
  map[uy - 1][ux] = 3;
 }
 }
 //當上面幾種return的情況都沒遇到,人肯定會移動,移動操作如下
 map[y][x] = 0;
 map[uy][ux] = 2;
 //更新人的座標
 y = uy; 
} 

這是一個方向的,其它方向要考慮的問題也和前面一樣,我也就不贅述了。

6、moveLeft()

這裏大致都和上面一樣,就是在記錄左邊座標時,應該應該是lx = x - 1。

void moveLeft(){
 //定義變量存放人物左邊的座標
 int lx, ly; 
 
 //當左邊沒有元素時,直接return 
 if(x == 0){
 return;
 }
 
 //記錄左邊座標
 lx = x - 1;
 ly = y; 
 
 //左邊爲已完成方塊
 if(map[ly][lx] == 5){
 return;
 } 
 
 //假設左邊爲牆,直接return 
 if(map[ly][lx] == 1){
 return;
 }
 
 //假設左邊爲箱子
 if(map[ly][lx] == 3){
 //判斷箱子左邊是否爲牆 
 if(map[ly][lx - 1] == 1){
  return;
 }
 
 //判斷箱子左邊是否爲球
 if(map[ly][lx - 1] == 4){
  //將箱子左邊內容賦值爲5★ 
  map[ly][lx - 1] = 5;
  map[ly][lx] = 0;
 
  //箱子的數目減1 
  boxs--; 
 }else{
  //移動箱子 
  map[ly][lx - 1] = 3; 
 }
 }
 map[y][x] = 0;
 map[ly][lx] = 2;
 x = lx; 
}

7、moveDown()

這裏在判斷邊界時,判斷的是 y == HEIGHT - 1。

void moveDown(){
 //定義變量存放人物下方的座標
 int dx, dy; 
 
 //當下方沒有元素時,直接return 
 if(y == HEIGHT - 1){
 return;
 }
 
 //記錄下方座標
 dx = x;
 dy = y + 1; 
 
 //下方爲已完成方塊
 if(map[dy][dx] == 5){
 return;
 } 
 
 //假設下方爲牆,直接return 
 if(map[dy][dx] == 1){
 return;
 }
 
 //假設下方爲箱子
 if(map[dy][dx] == 3){
 //判斷箱子下方是否爲牆 
 if(map[dy + 1][dx] == 1){
  return;
 }
 
 //判斷箱子下方是否爲球
 if(map[dy + 1][dx] == 4){
  //將箱子下面內容賦值爲5★ 
  map[dy + 1][dx] = 5;
  map[dy][dx] = 0;
  
  //箱子的數目減1 
  boxs--; 
 }else{
  //移動箱子
  map[dy + 1][dx] = 3; 
 }
 }
 map[y][x] = 0;
 map[dy][dx] = 2;
 y = dy; 
}

8、moveRight()

這裏也沒什麼特別說的:

void moveRight(){
 //定義變量存放人物右邊的座標
 int rx, ry; 
 
 //當右邊沒有元素時,直接return 
 if(x == WIDTH - 1){
 return;
 }
 
 //記錄右邊座標
 rx = x + 1;
 ry = y; 
 
 //右邊爲已完成方塊
 if(map[ry][rx] == 5){
 return;
 } 
 
 //假設右邊爲牆,直接return 
 if(map[ry][rx] == 1){
 return;
 }
 
 //假設右邊爲箱子
 if(map[ry][rx] == 3){
 //判斷箱子右邊是否爲牆 
 if(map[ry][rx + 1] == 1){
  return;
 }
 
 //判斷箱子左邊是否爲球
 if(map[ry][rx + 1] == 4){
  //將箱子右邊內容賦值爲5★ 
  map[ry][rx + 1] = 5;
  map[ry][rx] = 0;
  
  //箱子的數目減1 
  boxs--; 
 }else{
  //移動箱子 
  map[ry][rx + 1] = 3; 
 }
 }
 map[y][x] = 0;
 map[ry][rx] = 2;
 x = rx; 
}

三、總結

現在再回顧開始的運行步驟

  • 清除屏幕
  • 繪製地圖
  • 判斷遊戲是否結束
  • 對用戶按下的按鈕進行反饋

這裏把判斷遊戲是否結束放到了重繪圖像後面,因爲在對用戶進行反饋的時候只是改變了map中的數據,實際上最後一個箱子推到終點的圖像還沒有顯示出來,所以要在重繪之後再判斷是否結束遊戲。

代碼有很多冗餘的地方,一方面是想大家更好的理解,還有一方面出於懶。哈哈,代碼運行起來沒有問題,源碼和源程序我會上傳,有興趣的可以下下來,或者直接複製代碼運行也是沒問題的。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持神馬文庫。

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