visual 2019编写推箱子游戏的代码
时间: 2024-03-09 16:51:31 浏览: 147
好的,这里是Visual Studio 2019中使用MFC库实现推箱子游戏的代码示例:
首先在项目中添加一个对话框,然后在对话框上添加一个静态文本框、若干个按钮和一个消息框控件。在头文件中定义游戏状态的结构体和一些常量:
```
struct GameStatus {
int map[10][10]; // 地图
int playerX, playerY; // 玩家位置
int boxNum; // 箱子数量
int boxX[10], boxY[10]; // 箱子位置
int targetNum; // 目标位置数量
int targetX[10], targetY[10]; // 目标位置
};
const int MAP_WIDTH = 10;
const int MAP_HEIGHT = 10;
const int BLOCK_SIZE = 32;
const int PLAYER_IMG = 0;
const int BOX_IMG = 1;
const int TARGET_IMG = 2;
const int WALL_IMG = 3;
const int FLOOR_IMG = 4;
```
然后在对话框类中添加以下成员变量和函数:
```
class CMyDlg : public CDialogEx {
public:
GameStatus m_gameStatus; // 游戏状态
CStatic m_mapCtrl; // 显示地图的静态文本框
CButton m_leftCtrl, m_rightCtrl, m_upCtrl, m_downCtrl; // 按钮
CButton m_restartCtrl; // 重新开始游戏的按钮
CButton m_exitCtrl; // 退出游戏的按钮
CFont m_font; // 字体
afx_msg void OnLeftBtnClicked(); // 左移按钮的响应函数
afx_msg void OnRightBtnClicked(); // 右移按钮的响应函数
afx_msg void OnUpBtnClicked(); // 上移按钮的响应函数
afx_msg void OnDownBtnClicked(); // 下移按钮的响应函数
afx_msg void OnRestartBtnClicked(); // 重新开始游戏的响应函数
afx_msg void OnExitBtnClicked(); // 退出游戏的响应函数
virtual BOOL OnInitDialog(); // 初始化对话框的函数
virtual void DoDataExchange(CDataExchange* pDX); // 数据交换函数
DECLARE_MESSAGE_MAP()
};
```
在OnInitDialog函数中初始化游戏状态和界面:
```
BOOL CMyDlg::OnInitDialog() {
CDialogEx::OnInitDialog();
// 初始化游戏状态
m_gameStatus = initGameStatus();
// 初始化地图控件
m_mapCtrl.SetWindowText(_T(""));
m_mapCtrl.MoveWindow(10, 10, BLOCK_SIZE * MAP_WIDTH, BLOCK_SIZE * MAP_HEIGHT, TRUE);
m_mapCtrl.SetFont(&m_font, TRUE);
// 初始化按钮控件
m_leftCtrl.MoveWindow(420, 10, 100, 30, TRUE);
m_leftCtrl.SetFont(&m_font, TRUE);
m_rightCtrl.MoveWindow(540, 10, 100, 30, TRUE);
m_rightCtrl.SetFont(&m_font, TRUE);
m_upCtrl.MoveWindow(480, 50, 100, 30, TRUE);
m_upCtrl.SetFont(&m_font, TRUE);
m_downCtrl.MoveWindow(480, 90, 100, 30, TRUE);
m_downCtrl.SetFont(&m_font, TRUE);
m_restartCtrl.MoveWindow(420, 130, 100, 30, TRUE);
m_restartCtrl.SetFont(&m_font, TRUE);
m_exitCtrl.MoveWindow(540, 130, 100, 30, TRUE);
m_exitCtrl.SetFont(&m_font, TRUE);
// 设置按钮文本
m_leftCtrl.SetWindowText(_T("左移"));
m_rightCtrl.SetWindowText(_T("右移"));
m_upCtrl.SetWindowText(_T("上移"));
m_downCtrl.SetWindowText(_T("下移"));
m_restartCtrl.SetWindowText(_T("重新开始"));
m_exitCtrl.SetWindowText(_T("退出"));
// 设置字体
m_font.CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("宋体"));
// 显示地图
updateMap();
return TRUE;
}
```
在DoDataExchange函数中添加以下代码:
```
void CMyDlg::DoDataExchange(CDataExchange* pDX) {
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_STATIC_MAP, m_mapCtrl);
DDX_Control(pDX, IDC_BUTTON_LEFT, m_leftCtrl);
DDX_Control(pDX, IDC_BUTTON_RIGHT, m_rightCtrl);
DDX_Control(pDX, IDC_BUTTON_UP, m_upCtrl);
DDX_Control(pDX, IDC_BUTTON_DOWN, m_downCtrl);
DDX_Control(pDX, IDC_BUTTON_RESTART, m_restartCtrl);
DDX_Control(pDX, IDC_BUTTON_EXIT, m_exitCtrl);
}
```
在消息响应函数中添加以下代码:
```
BEGIN_MESSAGE_MAP(CMyDlg, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON_LEFT, &CMyDlg::OnLeftBtnClicked)
ON_BN_CLICKED(IDC_BUTTON_RIGHT, &CMyDlg::OnRightBtnClicked)
ON_BN_CLICKED(IDC_BUTTON_UP, &CMyDlg::OnUpBtnClicked)
ON_BN_CLICKED(IDC_BUTTON_DOWN, &CMyDlg::OnDownBtnClicked)
ON_BN_CLICKED(IDC_BUTTON_RESTART, &CMyDlg::OnRestartBtnClicked)
ON_BN_CLICKED(IDC_BUTTON_EXIT, &CMyDlg::OnExitBtnClicked)
END_MESSAGE_MAP()
```
在游戏初始化函数中,我们可以使用随机数生成一个随机的地图和箱子位置:
```
GameStatus initGameStatus() {
GameStatus gs = { 0 };
srand((unsigned)time(NULL));
// 初始化地图和障碍物
for (int i = 0; i < MAP_HEIGHT; i++) {
for (int j = 0; j < MAP_WIDTH; j++) {
if (i == 0 || j == 0 || i == MAP_HEIGHT - 1 || j == MAP_WIDTH - 1) {
gs.map[i][j] = WALL_IMG;
}
else {
gs.map[i][j] = FLOOR_IMG;
}
}
}
// 随机生成箱子和目标位置
gs.boxNum = 0;
gs.targetNum = 0;
while (gs.boxNum < 5 || gs.targetNum < 5) {
int x = rand() % MAP_WIDTH;
int y = rand() % MAP_HEIGHT;
if (gs.map[y][x] == FLOOR_IMG) {
if (gs.boxNum < 5) {
gs.boxX[gs.boxNum] = x;
gs.boxY[gs.boxNum] = y;
gs.map[y][x] = BOX_IMG;
gs.boxNum++;
}
else if (gs.targetNum < 5) {
gs.targetX[gs.targetNum] = x;
gs.targetY[gs.targetNum] = y;
gs.map[y][x] = TARGET_IMG;
gs.targetNum++;
}
}
}
// 随机生成玩家位置
while (true) {
int x = rand() % MAP_WIDTH;
int y = rand() % MAP_HEIGHT;
if (gs.map[y][x] == FLOOR_IMG) {
gs.playerX = x;
gs.playerY = y;
gs.map[y][x] = PLAYER_IMG;
break;
}
}
return gs;
}
```
在更新地图的函数中,我们需要根据游戏状态的地图数组,生成一幅位图,然后将其显示在地图控件上:
```
void CMyDlg::updateMap() {
CBitmap bmp;
bmp.CreateBitmap(MAP_WIDTH * BLOCK_SIZE, MAP_HEIGHT * BLOCK_SIZE, 1, 32, NULL);
CDC memDC;
memDC.CreateCompatibleDC(NULL);
memDC.SelectObject(bmp);
// 绘制地图
for (int i = 0; i < MAP_HEIGHT; i++) {
for (int j = 0; j < MAP_WIDTH; j++) {
switch (m_gameStatus.map[i][j]) {
case PLAYER_IMG:
drawImage(&memDC, j * BLOCK_SIZE, i * BLOCK_SIZE, _T("player.bmp"));
break;
case BOX_IMG:
drawImage(&memDC, j * BLOCK_SIZE, i * BLOCK_SIZE, _T("box.bmp"));
break;
case TARGET_IMG:
drawImage(&memDC, j * BLOCK_SIZE, i * BLOCK_SIZE, _T("target.bmp"));
break;
case WALL_IMG:
drawImage(&memDC, j * BLOCK_SIZE, i * BLOCK_SIZE, _T("wall.bmp"));
break;
case FLOOR_IMG:
drawImage(&memDC, j * BLOCK_SIZE, i * BLOCK_SIZE, _T("floor.bmp"));
break;
}
}
}
// 显示地图
m_mapCtrl.SetBitmap(bmp);
}
```
在绘制位图的函数中,我们使用GDI+库中的函数来加载图片,并绘制到位图上:
```
void CMyDlg::drawImage(CDC* pDC, int x, int y, LPCTSTR filename) {
Gdiplus::Bitmap* image = Gdiplus::Bitmap::FromFile(filename);
Gdiplus::Graphics g(pDC->GetSafeHdc());
g.DrawImage(image, x, y, BLOCK_SIZE, BLOCK_SIZE);
delete image;
}
```
在按钮的响应函数中,我们需要根据按钮的方向检查箱子是否能够移动,并更新游戏状态和界面:
```
void CMyDlg::OnLeftBtnClicked() {
moveBox(-1, 0);
}
void CMyDlg::OnRightBtnClicked() {
moveBox(1, 0);
}
void CMyDlg::OnUpBtnClicked() {
moveBox(0, -1);
}
void CMyDlg::OnDownBtnClicked() {
moveBox(0, 1);
}
void CMyDlg::moveBox(int dx, int dy) {
int playerX = m_gameStatus.playerX;
int playerY = m_gameStatus.playerY;
int boxX = -1, boxY = -1;
// 检查箱子是否能够移动
for (int i = 0; i < m_gameStatus.boxNum; i++) {
if (m_gameStatus.boxX[i] == playerX + dx && m_gameStatus.boxY[i] == playerY + dy) {
if (m_gameStatus.map[playerY + 2 * dy][playerX + 2 * dx] == FLOOR_IMG ||
m_gameStatus.map[playerY + 2 * dy][playerX + 2 * dx] == TARGET_IMG) {
boxX = m_gameStatus.boxX[i];
boxY = m_gameStatus.boxY[i];
break;
}
else {
return;
}
}
}
// 移动箱子
if (boxX != -1) {
m_gameStatus.map[boxY][boxX] = FLOOR_IMG;
m_gameStatus.map[boxY + dy][boxX + dx] = BOX_IMG;
m_gameStatus.boxX[i] = boxX + dx;
m_gameStatus.boxY[i] = boxY + dy;
}
// 移动玩家
m_gameStatus.map[playerY][playerX] = FLOOR_IMG;
m_gameStatus.map[playerY + dy][playerX + dx] = PLAYER_IMG;
m_gameStatus.playerX += dx;
m_gameStatus.playerY += dy;
// 更新地图
updateMap();
}
```
最后,在重新开始游戏和退出游戏的响应函数中,我们需要清空游戏状态和关闭对话框:
```
void CMyDlg::OnRestartBtnClicked() {
m_gameStatus = initGameStatus();
updateMap();
}
void CMyDlg::OnExitBtnClicked() {
CDialogEx::OnCancel();
}
```
以上就是使用Visual Studio 2019和MFC库实现推箱子游戏的代码示例,希望对您有所帮助。
阅读全文