🎈 作者:Linux猿
🎈 簡介:CSDN博客專家🏆,C/C++、面試、刷題、演算法盡管咨詢我,關注我,有問題私聊!
🎈 關注專欄:C/C++課程設計(優質好文持續更新中……)🚀
目錄
一、界面設計
1.1 主界面
1.2 游戲界面
二、設計思路
三、源代碼
四、總結
推箱子游戲大家應該非常熟悉,非常經典的一款游戲,本文來詳細講解下推箱子游戲的制作程序,趕緊來看下吧!
首先,看下效果圖:
一、界面設計
1.1 主界面
主界面如下所示:

主界面主要包括開始游戲和退出游戲,
1.2 游戲界面
游戲界面是通過讀取檔案中的資料,然后顯示到終端界面,如下所示:

二、設計思路
包括的各個函式有:
void showMap(); //輸出地圖
void move(char ch); //移動
void hideCursor(); //隱藏游標
void getCoord(int x, int y);//游標定位
void menu(); //選擇界面
void readGameData(); //讀取游戲資料
void sokoban(); //游戲主要流程
包含的資料結構有:
struct Location {
int x, y;
}target[NUM*NUM];
char map[NUM][NUM];
其中,target[NUM*NUM] 用于存盤目標位置的坐標,map[NUM][NUM]用于存盤地圖,
主流程如下所示:
//游戲主流程
void sokoban()
{
showMap(); //展示地圖
hideCursor(); //隱藏游標
while (true) {
if(_kbhit()) {
char ch = _getch(); //獲取用戶輸入
switch (ch) {
case 'w': //上
move(ch); break;
case 's': //下
move(ch); break;
case 'a': //左
move(ch); break;
case 'd': //右
move(ch); break;
}
}
Sleep(10);
}
}
設計思路如下:
1. 讀取游戲地圖資料;
2. 等待用戶輸入;
3. 根據用戶輸入移動人;
4. 判斷是否移動成功;
5. 回圈 2 ~ 4,一直到游戲成功;
三、源代碼
原始碼如下,可直接運行,
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <stdbool.h>
#define GAMEDATAPATH "data.txt"
#define NUM 200
int lx = 10, ly = 17;
char map[NUM][NUM];
int numTarget = 0;
int nx, ny, sx, sy, mb, n=1;
struct Location {
int x, y;
}target[NUM*NUM];
void showMap(); //輸出地圖
void move(char ch); //移動
void hideCursor(); //隱藏游標
void getCoord(int x, int y);//游標定位
void menu(); //選擇界面
void readGameData(); //讀取游戲資料
void sokoban(); //游戲主要流程
//隱藏游標
void hideCursor()
{
CONSOLE_CURSOR_INFO cursor= { 1, 0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor);
}
//設定顏色
void color(int a)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), a);
}
//游標重定位,用于在游標處輸出
void getCoord(int x, int y)
{
COORD pos = { x,y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void checkTargetGraph() {
int i;
for(i = 0; i < numTarget; ++i) {
int x = target[i].x;
int y = target[i].y;
if(map[x][y] == '2') {
getCoord((y+ly)*2, x+lx); color(4); printf("★"); color(7);
}
}
}
bool checkSuccess() {
int i;
for(i = 0; i < numTarget; ++i) {
int x = target[i].x;
int y = target[i].y;
if(map[x][y] != 'B') {
return false;
}
}
return true;
}
//從檔案中讀取游戲地圖資料
void readGameData()
{
int i, j;
FILE* fp = fopen(GAMEDATAPATH, "r");
if (fp == NULL) {
printf("Error: Failed to read data!");
return;
}
//讀取行和列
fscanf(fp, "%d %d %d %d", &nx, &ny, &sx, &sy);
//讀取資料
for(i = 0; i < nx; ++i) {
fscanf(fp, "%s", map[i]);
}
for(i = 0; i < nx; ++i) {
for(j = 0; j < ny; ++j) {
if(map[i][j] == 'C') {
target[numTarget].x = i;
target[numTarget++].y = j;
}
}
}
fclose(fp);
}
//輸出游戲地圖
void showMap()
{
system("cls"); //清屏
int i, j;
for(i = 0; i < nx; ++i) {
for(j = 0; j < ny; ++j){
getCoord((j+ly)*2, i+lx);
if(map[i][j] == '1') {
color(52); printf("■");
} else if(map[i][j] == '2') {
printf(" ");
} else if(map[i][j] == 'A') {
color(1); printf("♀");
} else if(map[i][j] == 'B') {
color(6); printf("■");
} else if(map[i][j] == 'C') {
color(4); printf("★");
}
color(7);
}
}
}
//主界面
int main()
{
system("chcp 65001"); //語言支持
system("mode con cols=90 lines=30");//設定終端大小
system("cls");
menu();//選單
sokoban(); //主要流程
return 0;
}
void menu()//主流程
{
system("cls"); //清屏
getCoord(39, 8); color(9); printf("推箱子游戲"); color(7);
getCoord(38, 12); color(9); printf("1. 開始游戲"); color(7);
getCoord(38, 14); color(9); printf("2. 退出游戲"); color(7);
hideCursor();
while(true) {
char chn=_getch();//選擇
if(chn == '1') {
readGameData(); //讀取游戲資料
break;
} else if (chn == '2') { //退出游戲
system("cls");
getCoord(39, 8); printf("推箱子游戲");
getCoord(38, 15); printf("歡迎下次光臨");
Sleep(3000);
exit(1);
} else {
getCoord(39, 18); printf("輸入錯誤!");
Sleep(1000);
getCoord(39, 18); printf(" ");
}
}
}
void move(char ch)
{
if(ch == 'd') {
if(sy + 1 < ny && map[sx][sy+1] != '1') {// 人右邊沒有超出方框,且右邊不是墻
if(map[sx][sy+1] == '2' || map[sx][sy+1] == 'C') {//是空格或目標直接走過去
getCoord((sy+ly)*2, sx+lx); printf(" ");
getCoord((sy+ly)*2+2, sx+lx); color(1); printf("♀"); color(7);
map[sx][sy] = '2';
map[sx][sy+1] = 'A';
sy = sy + 1;
} else if(map[sx][sy+1] == 'B' && sy + 2 < ny && (map[sx][sy+2] == '2' || map[sx][sy+2] == 'C')) {//人 箱子 空格
getCoord((sy+ly)*2+4, sx+lx); printf(" ");
getCoord((sy+ly)*2+4, sx+lx); color(6); printf("■"); color(7);
getCoord((sy+ly)*2+2, sx+lx); color(1); printf("♀"); color(7);
getCoord((sy+ly)*2, sx+lx); printf(" ");
map[sx][sy+2] = 'B';
map[sx][sy+1] = 'A';
map[sx][sy] = '2';
sy = sy + 1;
}
}
} else if(ch == 'a') {
if(sy - 1 >= 0 && map[sx][sy-1] != '1') {// 人左邊沒有超出方框,且左邊不是墻
if(map[sx][sy-1] == '2' || map[sx][sy-1] == 'C') {//是空格直接走過去
getCoord((sy+ly)*2, sx+lx); printf(" ");
getCoord((sy+ly)*2-2, sx+lx); color(1); printf("♀"); color(7);
map[sx][sy] = '2';
map[sx][sy-1] = 'A';
sy = sy - 1;
} else if(map[sx][sy-1] == 'B' && sy - 2 >= 0 && (map[sx][sy-2] == '2' || map[sx][sy-2] == 'C')) {//空格 箱子 人
getCoord((sy+ly)*2-4, sx+lx); printf(" ");
getCoord((sy+ly)*2-4, sx+lx); color(6); printf("■"); color(7);
getCoord((sy+ly)*2-2, sx+lx); color(1); printf("♀"); color(7);
getCoord((sy+ly)*2, sx+lx); printf(" ");
map[sx][sy-2] = 'B';
map[sx][sy-1] = 'A';
map[sx][sy] = '2';
sy = sy - 1;
}
}
} else if(ch =='w') {
if(sx - 1 >= 0 && map[sx-1][sy] != '1') {// 人上面沒有超出方框,且上面不是墻
if(map[sx-1][sy] == '2' || map[sx-1][sy] == 'C') {//是空格直接走過去
getCoord((sy+ly)*2, sx+lx); printf(" ");
getCoord((sy+ly)*2, sx+lx-1); color(1); printf("♀"); color(7);
map[sx][sy] = '2';
map[sx-1][sy] = 'A';
sx = sx - 1;
} else if(map[sx-1][sy] == 'B' && sx - 2 >= 0 && (map[sx-2][sy] == '2' || map[sx-2][sy] == 'C')) {//空格 箱子 人
getCoord((sy+ly)*2, sx+lx-2); printf(" ");
getCoord((sy+ly)*2, sx+lx-2); color(6); printf("■"); color(7);
getCoord((sy+ly)*2, sx+lx-1); color(1); printf("♀"); color(7);
getCoord((sy+ly)*2, sx+lx); printf(" ");
map[sx-2][sy] = 'B';
map[sx-1][sy] = 'A';
map[sx][sy] = '2';
sx = sx - 1;
}
}
} else if(ch =='s') {
if(sx + 1 < nx && map[sx+1][sy] != '1') {// 人上面沒有超出方框,且上面不是墻
if(map[sx+1][sy] == '2' || map[sx+1][sy] == 'C') {//是空格直接走過去
getCoord((sy+ly)*2, sx+lx); printf(" ");
getCoord((sy+ly)*2, sx+lx+1); color(1); printf("♀"); color(7);
map[sx][sy] = '2';
map[sx+1][sy] = 'A';
sx = sx + 1;
} else if(map[sx+1][sy] == 'B' && sx + 2 >= 0 && (map[sx+2][sy] == '2' || map[sx+2][sy] == 'C')) {//空格 箱子 人
getCoord((sy+ly)*2, sx+lx+2); printf(" ");
getCoord((sy+ly)*2, sx+lx+2); color(6); printf("■"); color(7);
getCoord((sy+ly)*2, sx+lx+1); color(1); printf("♀"); color(7);
getCoord((sy+ly)*2, sx+lx); printf(" ");
map[sx+2][sy] = 'B';
map[sx+1][sy] = 'A';
map[sx][sy] = '2';
sx = sx + 1;
}
}
}
checkTargetGraph(); //顯示目標,防止覆寫
bool flag = checkSuccess(); //檢查是否成功
if(flag) {
getCoord(38, 19); color(4); printf("Success\n"); color(7);
}
}
//游戲主流程
void sokoban()
{
showMap(); //展示地圖
hideCursor(); //隱藏游標
while (true) {
if(_kbhit()) {
char ch = _getch(); //獲取用戶輸入
switch (ch) {
case 'w': //上
move(ch); break;
case 's': //下
move(ch); break;
case 'a': //左
move(ch); break;
case 'd': //右
move(ch); break;
}
}
Sleep(10);
}
}
data.txt檔案游戲資料如下所示,放到和源檔案同目錄下,
7 10 3 2
1111111111
1122222111
11B1112221
12A2B22B21
12CC12B211
11CC122211
1111111111
四、總結
推箱子游戲的重點在于人的移動,人可以向上下左右四個方向移動,需要判斷人的前面的物體,游戲界面設計主要是根據用戶的輸入移動人,每次移動后判斷是否成功,
?好文推薦?
俄羅斯方塊游戲,重溫經典(C++詳解版)
【萬字整理】??8大排序演算法??【建議收藏】
3分鐘理解指標和參考的區別【??建議收藏??】
🎈 歡迎小伙伴們點贊👍、收藏?、留言💬
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/336605.html
標籤:其他
