亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C語(yǔ)言實(shí)現(xiàn)推箱子游戲的代碼示例

 更新時(shí)間:2019年09月30日 09:44:35   作者:ZackSock  
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)推箱子游戲的代碼示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

很早就想過(guò)做點(diǎn)小游戲了,但是一直沒(méi)有機(jī)會(huì)動(dòng)手。今天閑來(lái)無(wú)事,動(dòng)起手來(lái)。過(guò)程還是蠻順利的,代碼也不是非常難。今天給大家分享一下~

一、介紹

開(kāi)發(fā)語(yǔ)言:C語(yǔ)言
開(kāi)發(fā)工具:Dev-C++ 5.11
日期:2019年9月28日
作者:ZackSock

也不說(shuō)太多多余的話(huà)了,先看一下效果圖:

游戲中的人物、箱子、墻壁、球都是字符構(gòu)成的。通過(guò)wasd鍵移動(dòng),規(guī)則的話(huà)就是推箱子的規(guī)則,也就不多說(shuō)了。

二、代碼實(shí)現(xiàn)

關(guān)于代碼方面,我盡可能講的細(xì)致。希望大家可以理解~

(1)方法列表

//主函數(shù)
void main();

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

//在控制臺(tái)上打印地圖
drawMap();

//向上移動(dòng)
moveUp();

//向左移動(dòng)
moveLeft()

//向下移動(dòng)
moveDown()

//向右移動(dòng)
moveRight();

這幾個(gè)方法都顧名思義,而且用意也非常明確,就initData可能不知道具體用處,但是沒(méi)有什么大問(wèn)題。唯一的問(wèn)題就是,上左下右的順序可能會(huì)逼死幾個(gè)強(qiáng)迫癥患者,哈哈。

(2)參數(shù)列表

為了方便,我把include和宏定義也放到參數(shù)列表當(dāng)中

//導(dǎo)入函數(shù)庫(kù)
#include <stdio.h>
#include <stdlib.h>

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

//定義地圖數(shù)組,二維數(shù)組有兩個(gè)維度,而地圖也是二維的矩形
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} 
};

//人的位置,在二維地圖中,我們可以用坐標(biāo)表示一個(gè)人的位置,就好比經(jīng)緯度
int x, y;

//箱子的個(gè)數(shù),推箱子肯定要有箱子嘛。
int boxs;

這里參數(shù)不多,其中橫為x,縱為y,另外這里再規(guī)定一下map的一些東西:

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

(3)函數(shù)具體分析

接下來(lái)我們一個(gè)一個(gè)函數(shù)來(lái)分析。

1、main函數(shù)

int main(int argc, char *argv[]) {
 char direction; //存儲(chǔ)鍵盤(pán)按的方向 
 initData();  //初始化一些數(shù)據(jù)
 
 //開(kāi)始游戲的循環(huán),這里是個(gè)死循環(huán),每按一次按鈕循環(huán)一次
 while(1){
 //每次循環(huán)的開(kāi)始清除屏幕
 system("cls");
 //繪畫(huà)地圖
 drawMap();

 //判斷,當(dāng)boxs的數(shù)量0時(shí),!0為真,然后走break跳出循環(huán)(結(jié)束游戲) 
 if(!boxs){
  break;
 }
 
 //鍵盤(pán)輸入方向,這里使用getch,因?yàn)間etch讀取字符不會(huì)顯示在屏幕上
 direction = getch();
 
 //用switch判斷用戶(hù)輸入的方向
 switch(direction){
  case 'w':
  //按w時(shí),調(diào)用向上移動(dòng)函數(shù)
  moveUp();
  break;
  case 'a':
  //按a時(shí),調(diào)用向左移動(dòng)函數(shù)
  moveLeft(); 
  break;
  case 's':
  moveDown();
  break;
  case 'd':
  moveRight();
  break; 
 }
 } 
 //當(dāng)跳出循環(huán)時(shí),運(yùn)行該語(yǔ)句,游戲結(jié)束
 printf("恭喜你完成游戲!※");
 return 0;
}

我大概說(shuō)一下流程,循環(huán)外面沒(méi)有什么特別的。initData()只是一些簡(jiǎn)單數(shù)據(jù)的初始化,不需要太在意。循環(huán)中大致流程如下:

  • 清除屏幕
  • 繪制地圖
  • 判斷游戲是否結(jié)束
  • 對(duì)用戶(hù)按下的按鈕進(jìn)行反饋

進(jìn)入循環(huán)體,先清除屏幕,再繪制地圖,然后再判斷游戲是否結(jié)束。可能大家對(duì)這個(gè)順序不是很理解,這里我們先不考慮判斷游戲結(jié)束的問(wèn)題。我們把清屏和繪制地圖合在一起,簡(jiǎn)稱(chēng)“重繪地圖”,而游戲結(jié)束的判斷先不考慮,那么流程就簡(jiǎn)化為“重繪地圖 + 響應(yīng)用戶(hù)的操作”。簡(jiǎn)單來(lái)說(shuō)就是,用戶(hù)按一下按鈕,我改變一下地圖。

2、initData()

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

這個(gè)方法很簡(jiǎn)單,就是遍歷地圖,然后初始化人的位置和箱子的個(gè)數(shù)。這里有一點(diǎn)要注意一下,就是到底內(nèi)層循環(huán)是WIDTH還是外層循環(huán)是WIDTH。

如圖,在遍歷過(guò)程中。外層循環(huán)控制行數(shù),即HEIGHT。那么內(nèi)層循環(huán)應(yīng)該是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");
 }
}

這里也非常簡(jiǎn)單,變量map中的元素,然后通過(guò)switch判斷應(yīng)該輸出的內(nèi)容。然后內(nèi)層循環(huán)每走完一次就換行。

4、moveUp()

這個(gè)函數(shù)內(nèi)容有點(diǎn)多,想講一下大概思路:

向上移有兩種情況

1、前面為空白
 這種情況有兩個(gè)步驟
 (1)將人當(dāng)前的位置設(shè)置為空白(0),
 (2)再講人前面的位置設(shè)置為人(2)
2、前面為箱子
 當(dāng)前面為箱子時(shí)有三種情況
 1、箱子前面為空白
  移動(dòng)人和箱子,這個(gè)操作有三個(gè)步驟
  (1)將人當(dāng)前位置設(shè)置為空(0)
  (2)將箱子位置設(shè)置為人(2)
  (3)將箱子前面設(shè)置為箱子(3)
 2、箱子前面為墻
  這種情況不需要做任何操作
 3、箱子前面為終點(diǎn)
  這種情況有四個(gè)個(gè)步驟
  (1)將人的位置設(shè)置為空(0)
  (2)將箱子的位置設(shè)置為人(2)
  (3)將終點(diǎn)位置設(shè)置為★(5)
  (4)箱子boxs的數(shù)量減一
3、前面為墻
 這種情況最簡(jiǎn)單,不需要做任何操作
4、前面為終點(diǎn)
 我這里沒(méi)有考慮太多,這種情況不做操作。(如果更換地圖的話(huà)可能需要修改代碼)

具體代碼如下,解析我全寫(xiě)在注釋里面:

void moveUp(){
 //定義變量存放人物上方的坐標(biāo)
 int ux, uy; 
 
 //當(dāng)上方?jīng)]有元素時(shí),直接return (其實(shí)人不可能在邊緣)
 if(y == 0){
 return;
 }
 
 //記錄上方坐標(biāo),x為橫,y為縱,所有ux = x, uy = y - 1;
 ux = x;
 uy = y - 1; 
 
 //上方為已完成的箱子
 if(map[uy][ux] == 5){
 return;
 } 
 //假設(shè)上方為墻,直接return,這個(gè)和上面的判斷可以合在一起,這里為了看清楚分開(kāi)寫(xiě) 
 if(map[uy][ux] == 1){
 return;
 }
 
 //假設(shè)上方為箱子
 if(map[uy][ux] == 3){
 //判斷箱子上方是否為墻 
 if(map[uy - 1][ux] == 1){
  return;
 }
 
 //判斷箱子上方是否為終點(diǎn)
 if(map[uy - 1][ux] == 4){
  //將箱子上面內(nèi)容賦值為5★ 
  map[uy - 1][ux] = 5;
  map[uy][ux] = 0;
   
  //箱子的數(shù)目減1 
  boxs--; 
 }else{
  //移動(dòng)箱子
  map[uy - 1][ux] = 3;
 }
 }
 //當(dāng)上面幾種return的情況都沒(méi)遇到,人肯定會(huì)移動(dòng),移動(dòng)操作如下
 map[y][x] = 0;
 map[uy][ux] = 2;
 //更新人的坐標(biāo)
 y = uy; 
} 

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

6、moveLeft()

這里大致都和上面一樣,就是在記錄左邊坐標(biāo)時(shí),應(yīng)該應(yīng)該是lx = x - 1。

void moveLeft(){
 //定義變量存放人物左邊的坐標(biāo)
 int lx, ly; 
 
 //當(dāng)左邊沒(méi)有元素時(shí),直接return 
 if(x == 0){
 return;
 }
 
 //記錄左邊坐標(biāo)
 lx = x - 1;
 ly = y; 
 
 //左邊為已完成方塊
 if(map[ly][lx] == 5){
 return;
 } 
 
 //假設(shè)左邊為墻,直接return 
 if(map[ly][lx] == 1){
 return;
 }
 
 //假設(shè)左邊為箱子
 if(map[ly][lx] == 3){
 //判斷箱子左邊是否為墻 
 if(map[ly][lx - 1] == 1){
  return;
 }
 
 //判斷箱子左邊是否為球
 if(map[ly][lx - 1] == 4){
  //將箱子左邊內(nèi)容賦值為5★ 
  map[ly][lx - 1] = 5;
  map[ly][lx] = 0;
 
  //箱子的數(shù)目減1 
  boxs--; 
 }else{
  //移動(dòng)箱子 
  map[ly][lx - 1] = 3; 
 }
 }
 map[y][x] = 0;
 map[ly][lx] = 2;
 x = lx; 
}

7、moveDown()

這里在判斷邊界時(shí),判斷的是 y == HEIGHT - 1。

void moveDown(){
 //定義變量存放人物下方的坐標(biāo)
 int dx, dy; 
 
 //當(dāng)下方?jīng)]有元素時(shí),直接return 
 if(y == HEIGHT - 1){
 return;
 }
 
 //記錄下方坐標(biāo)
 dx = x;
 dy = y + 1; 
 
 //下方為已完成方塊
 if(map[dy][dx] == 5){
 return;
 } 
 
 //假設(shè)下方為墻,直接return 
 if(map[dy][dx] == 1){
 return;
 }
 
 //假設(shè)下方為箱子
 if(map[dy][dx] == 3){
 //判斷箱子下方是否為墻 
 if(map[dy + 1][dx] == 1){
  return;
 }
 
 //判斷箱子下方是否為球
 if(map[dy + 1][dx] == 4){
  //將箱子下面內(nèi)容賦值為5★ 
  map[dy + 1][dx] = 5;
  map[dy][dx] = 0;
  
  //箱子的數(shù)目減1 
  boxs--; 
 }else{
  //移動(dòng)箱子
  map[dy + 1][dx] = 3; 
 }
 }
 map[y][x] = 0;
 map[dy][dx] = 2;
 y = dy; 
}

8、moveRight()

這里也沒(méi)什么特別說(shuō)的:

void moveRight(){
 //定義變量存放人物右邊的坐標(biāo)
 int rx, ry; 
 
 //當(dāng)右邊沒(méi)有元素時(shí),直接return 
 if(x == WIDTH - 1){
 return;
 }
 
 //記錄右邊坐標(biāo)
 rx = x + 1;
 ry = y; 
 
 //右邊為已完成方塊
 if(map[ry][rx] == 5){
 return;
 } 
 
 //假設(shè)右邊為墻,直接return 
 if(map[ry][rx] == 1){
 return;
 }
 
 //假設(shè)右邊為箱子
 if(map[ry][rx] == 3){
 //判斷箱子右邊是否為墻 
 if(map[ry][rx + 1] == 1){
  return;
 }
 
 //判斷箱子左邊是否為球
 if(map[ry][rx + 1] == 4){
  //將箱子右邊內(nèi)容賦值為5★ 
  map[ry][rx + 1] = 5;
  map[ry][rx] = 0;
  
  //箱子的數(shù)目減1 
  boxs--; 
 }else{
  //移動(dòng)箱子 
  map[ry][rx + 1] = 3; 
 }
 }
 map[y][x] = 0;
 map[ry][rx] = 2;
 x = rx; 
}

三、總結(jié)

現(xiàn)在再回顧開(kāi)始的運(yùn)行步驟

  • 清除屏幕
  • 繪制地圖
  • 判斷游戲是否結(jié)束
  • 對(duì)用戶(hù)按下的按鈕進(jìn)行反饋

這里把判斷游戲是否結(jié)束放到了重繪圖像后面,因?yàn)樵趯?duì)用戶(hù)進(jìn)行反饋的時(shí)候只是改變了map中的數(shù)據(jù),實(shí)際上最后一個(gè)箱子推到終點(diǎn)的圖像還沒(méi)有顯示出來(lái),所以要在重繪之后再判斷是否結(jié)束游戲。

代碼有很多冗余的地方,一方面是想大家更好的理解,還有一方面出于懶。哈哈,代碼運(yùn)行起來(lái)沒(méi)有問(wèn)題,源碼和源程序我會(huì)上傳,有興趣的可以下下來(lái),或者直接復(fù)制代碼運(yùn)行也是沒(méi)問(wèn)題的。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • c++ using定義類(lèi)型別名的具體使用

    c++ using定義類(lèi)型別名的具體使用

    本文主要介紹了c++ using定義類(lèi)型別名的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • C字符串與C++中string的區(qū)別詳解

    C字符串與C++中string的區(qū)別詳解

    以下是對(duì)C字符串與C++中string的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下
    2013-09-09
  • 用C語(yǔ)言實(shí)現(xiàn)自動(dòng)售貨機(jī)

    用C語(yǔ)言實(shí)現(xiàn)自動(dòng)售貨機(jī)

    這篇文章主要為大家詳細(xì)介紹了用C語(yǔ)言實(shí)現(xiàn)自動(dòng)售貨機(jī),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • dev-c++創(chuàng)建lib(靜態(tài)鏈接庫(kù))文件的實(shí)現(xiàn)步驟

    dev-c++創(chuàng)建lib(靜態(tài)鏈接庫(kù))文件的實(shí)現(xiàn)步驟

    本文主要介紹了dev-c++創(chuàng)建lib(靜態(tài)鏈接庫(kù))文件的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • C++解決大數(shù)組棧內(nèi)存不夠問(wèn)題的方法分析

    C++解決大數(shù)組棧內(nèi)存不夠問(wèn)題的方法分析

    這篇文章主要介紹了C++解決大數(shù)組棧內(nèi)存不夠問(wèn)題的方法,結(jié)合實(shí)例形式對(duì)比分析了C++針對(duì)大數(shù)組棧內(nèi)存不足情況的常見(jiàn)解決方法及其優(yōu)缺點(diǎn),具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2018-05-05
  • 淺談2路插入排序算法及其簡(jiǎn)單實(shí)現(xiàn)

    淺談2路插入排序算法及其簡(jiǎn)單實(shí)現(xiàn)

    這篇文章主要介紹了淺談2路插入排序算法及其簡(jiǎn)單實(shí)現(xiàn),雖算不上是常用的排序方法,但在數(shù)據(jù)庫(kù)等方面依然有用上的機(jī)會(huì),需要的朋友可以參考下
    2015-08-08
  • 深入解析C++中派生類(lèi)的構(gòu)造函數(shù)

    深入解析C++中派生類(lèi)的構(gòu)造函數(shù)

    這篇文章主要介紹了深入解析C++中派生類(lèi)的構(gòu)造函數(shù),是C++入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • Qt可視化大屏布局的實(shí)現(xiàn)

    Qt可視化大屏布局的實(shí)現(xiàn)

    數(shù)據(jù)可視化大屏在項(xiàng)目中的使用很常見(jiàn),本文主要介紹了Qt可視化大屏布局的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • C語(yǔ)言超詳細(xì)i講解雙向鏈表

    C語(yǔ)言超詳細(xì)i講解雙向鏈表

    在實(shí)際生活中,我們用到的最多的兩種鏈表結(jié)構(gòu)就是單鏈表和雙向帶頭鏈表,上一篇已經(jīng)介紹了單鏈表的實(shí)現(xiàn)以及一些應(yīng)用,接下來(lái)我為大家詳細(xì)介紹一下雙向鏈表,以及一些鏈表oj題
    2022-05-05
  • QT基于TCP網(wǎng)絡(luò)聊天室

    QT基于TCP網(wǎng)絡(luò)聊天室

    這篇文章主要為大家詳細(xì)介紹了QT基于TCP網(wǎng)絡(luò)聊天室,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評(píng)論