推箱子——带有图形界面

1.前言

前面编写了两次拖箱子,一次普通版本,一次完善了基本功能,这次给推箱子加上图形界面,因此这次主要是讲图形界面的添加;如果想要了解前面的设计可以看看我下面这两篇博客
第一次简单图箱子设计链接;
功能完善版推箱子链接;

2.效果展示

在这里插入图片描述

3.图形界面如何添加

3.1工具的选择

百度 easyx图形库
在这里插入图片描述

3.2 easyx库中一些函数的使用

3.2.1头文件的包含

想要调用一些函数,首先得先在头文件夹中包含 graphics.h表示调用easyx这个库,这和我们平时使用其它的标准库是一样的;

3.2.2 加载一个图形化界面

平时我们的窗口是编译器自带的是不能显示图片的,因此我们需要加载一个新的图形化窗口;
在这里插入图片描述

3.2.3 图片变量的声明

平常我们使用变量都需要声明定义,图形变量也是一样的,不过它的关键字是IMAGE;同时我们想要显示图片还得加载图片,然后再选择从什么位置开始显示图片;
在这里插入图片描述
我们还可以改变加载图片的大小
在这里插入图片描述

3.2.4 图片的储存位置

记得将图片存储在我们代码所在的文件夹,这样才能加载出来,否则加载函数内部填写的路径就要改为绝对路径

4.图片定义和打印

4.1图片的定义

如下面代码所示:
首先将需要的图片素材改好名字存放在对应的文件夹里;
定义我们需要的图片,调用一个图形窗口,将需要的图片加载进来;

//定义图片变量
IMAGE mm;//背景
IMAGE room;//地板
IMAGE box;//箱子
IMAGE people;//人物
IMAGE wall;//墙壁
IMAGE lable;//目标点
IMAGE over;//箱子进入目标点
IMAGE people2;//人物进入目标点

void Load()
{
	initgraph(1000, 1000);
	loadimage(&room,"room.jpg",50, 50);
	loadimage(&mm, "mm.jpg", 1000, 1000);
	loadimage(&box, "box.jpg", 50, 50);
	loadimage(&people, "people.jpg", 50, 50);
	loadimage(&wall, "wall.jpg", 50, 50);
	loadimage(&lable, "lable.jpg", 50, 50);
	loadimage(&over, "over.jpg", 50, 50);
	loadimage(&people2, "people2.jpg", 50, 50);
}

4.2图片的打印

如图所示我们以前是直接输出字符,但是在调用的图形窗口之中,打印函数需要变为putimage(x, y, &over);即将对应的图片打印出来而不是将我们的符号打印出来

void ShowMap(char arr[][LINE])//打印地图
{ //x,y代表在窗口的什么位置开始打印图片,因为图片是由大小的,所以我们的打印坐标需要改变,
//本次加载的图片大小为50*50,因此我们需要改变x和y的坐标
	putimage(0, 0, &mm);
	int x = 0;
	int y = 0;
	for (int i = 0; i < ROW; i++)
	{
		y = i * 50;
		for (int j = 0; j < LINE; j++)
		{
			x = j * 50;
			if (arr[i][j]==1)//地板
				putimage(x, y, &room);
			if (arr[i][j] == 0)//墙壁
				putimage(x, y, &wall);
			else if (arr[i][j] == 2)//打印箱子
				putimage(x, y, &box);
			else if (arr[i][j] == 3)//打印目的点
				putimage(x, y, &lable);
			else if (arr[i][j] == 4)//打印人物
				putimage(x, y, &people);
			else if (arr[i][j] == 5)//打印人物和目标点重叠后的图案
				putimage(x, y, &people2);
			else if (arr[i][j] == 6)//箱子进入目标点后的图案
				putimage(x, y, &over);
		}
	}
}

5.完整代码

#include "game.h"

//定义图片变量
IMAGE mm;//背景
IMAGE room;//地板
IMAGE box;//箱子
IMAGE people;//人物
IMAGE wall;//墙壁
IMAGE lable;//目标点
IMAGE over;//箱子进入目标点
IMAGE people2;//人物进入目标点

void Load()//加载窗口和图片
{
	initgraph(1000, 1000);
	loadimage(&room,"room.jpg",50, 50);
	loadimage(&mm, "mm.jpg", 1000, 1000);
	loadimage(&box, "box.jpg", 50, 50);
	loadimage(&people, "people.jpg", 50, 50);
	loadimage(&wall, "wall.jpg", 50, 50);
	loadimage(&lable, "lable.jpg", 50, 50);
	loadimage(&over, "over.jpg", 50, 50);
	loadimage(&people2, "people2.jpg", 50, 50);
}

void ShowMap(char arr[][LINE])//打印地图
{
	putimage(0, 0, &mm);
	int x = 0;
	int y = 0;
	for (int i = 0; i < ROW; i++)
	{
		y = i * 50;
		for (int j = 0; j < LINE; j++)
		{
			x = j * 50;
			if (arr[i][j]==1)//地板
				putimage(x, y, &room);
			if (arr[i][j] == 0)//墙壁
				putimage(x, y, &wall);a
			else if (arr[i][j] == 2)//打印箱子
				putimage(x, y, &box);
			else if (arr[i][j] == 3)//打印目的点
				putimage(x, y, &lable);
			else if (arr[i][j] == 4)//打印人物
				putimage(x, y, &people);
			else if (arr[i][j] == 5)//打印人物和目标点重叠后的图案
				putimage(x, y, &people2);
			else if (arr[i][j] == 6)//箱子进入目标点后的图案
				putimage(x, y, &over);
		}
	}
}
void Move(char arr[][LINE], int *row, int *line, char retarr[][LINE], int *retrow, int *retline)//移动小人儿
{
	while (1)
	{
		int newrow = *row;
		int newline = *line;
		int quit = 0;
		outtextxy(0,500,"请通过w,s,a,d,控制上下左右,输入r返回");
		//printf("请通过w,s,a,d,控制上下左右,输入r返回\n");
		int move = 0;
		int c = 0;
		while (!quit)
		{
			move = getchar();//从标准输入读取字符
			while ((c = getchar()) != '\n');//吃掉多余的字符以及空格
			switch (move)
			{
			case 'w':
				newrow--;//向上移动
				quit = 1;
				break;
			case 's':
				newrow++;//向下移动
				quit = 1;
				break;
			case 'a':
				newline--;//向左移动
				quit = 1;
				break;
			case 'd':
				newline++;//向右移动
				quit = 1;
				break;
			case 'r':
				quit = 1;
				break;
			default:
				outtextxy(0, 500, "输入有误,请从新输入");
				//printf("输入有误,请从新输入\n");
				break;
			}
		}
		if (move == 'r')//返回
		{
			cleardevice();
			ShowMap(retarr);//打印旧地图
			Retain(arr, retarr);//地图内容更换为上一步的内容
			//将小人坐标替换为上一步的小人坐标
			*row = *retrow;
			*line = *retline;
			break;
		}
		Save(retarr, arr, row, line, retrow, retline);//此时已经不需要返回,坐标更新前保存一份
		if (arr[newrow][newline] == 0)//下一个坐标为墙壁
		{
			printf("禁止前行\n");
			break;
		}

		else//前面为空白,箱子,或者目标点,或者箱子到目标点后的结合图案(也是箱子)
		{
			if (arr[newrow][newline] == 1)//为空白
			{
				arr[newrow][newline] = 4;//将小人移动到坐标点
				if (arr[*row][*line] == 5)//此时小人与目标重合,
				{
					arr[*row][*line] = 3;//那么出来后就变成目标点了;
				}
				else
				{
					arr[*row][*line] = 1;//小人的地方变为空白
				}
				//坐标更新
				*row = newrow;
				*line = newline;
			}
			else if (arr[newrow][newline] == 3)//为目标点
			{
				arr[newrow][newline] = 5;//小人儿和目标点重合的图像

				if (arr[*row][*line] == 5)//此时小人与目标重合,
				{
					arr[*row][*line] = 3;//那么出来后就变成目标点了;
				}
				else
				{
					arr[*row][*line] = 1;//小人的地方变为空白
				}
				//坐标更新
				*row = newrow;
				*line = newline;
			}
			else if (arr[newrow][newline] == 2 || arr[newrow][newline] == 6)//下一个点为箱子或者箱子和目标点的结合图案
			{
				int nextrow = newrow;
				int nextline = newline;
				if (move == 'w')//上
					nextrow = newrow - 1;
				else if (move == 's')//下
					nextrow = newrow + 1;
				else if (move == 'a')//左
					nextline = newline - 1;
				else//右
					nextline = newline + 1;
				if (arr[nextrow][nextline] == 0 || arr[nextrow][nextline] == 2 || arr[nextrow][nextline] == 6)
					//箱子前面是墙壁或者箱子或者箱子和目标点的结合
				{
					printf("移动不了,箱子前方有障碍\n");
					break;
				}

				else //箱子前面不是墙壁
				{
					if (arr[nextrow][nextline] == 3)//箱子前面是目标点
					{
						arr[nextrow][nextline] = 6;//箱子前挪,图案变成箱子和目标点重合的图案
					}
					else//箱子前面是空白
					{
						arr[nextrow][nextline] = 2;//空白处变成箱子
					}
					if (arr[newrow][newline] == 6)//原箱子位置是目标点
					{
						arr[newrow][newline] = 5;//变成目标点和小人儿的结合
					}
					else
					{
						arr[newrow][newline] = 4;//箱子位置变为人
					}
					if (arr[*row][*line] == 5)//此时小人与目标点重合,
					{
						arr[*row][*line] = 3;//那么出来后就变成目标点了;
					}
					else
					{
						arr[*row][*line] = 1;//小人的地方变为空白
					}
					//坐标更新
					*row = newrow;
					*line = newline;
				}
			}

		}
		//进行移动之后的地图打印;
		cleardevice();
		ShowMap(arr);
		break;
	}

}
void  Judge(char arr[][LINE], int *boxs)
{
	int temp = 0;
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < LINE; j++)
		{
			if (arr[i][j] == 3 || arr[i][j] == 5)//剩余目标点数以及人物进入了目标点	
				temp++;
		}
	}
	*boxs = temp;
}
void Retain(char retarr[][LINE], char arr[][LINE])//保存旧地图
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < LINE; j++)
		{
			retarr[i][j] = arr[i][j];
		}
	}
}
void Save(char retarr[][LINE], char arr[][LINE], int *row, int *line, int *retrow, int *retline)//更新前内容保存
{
	Retain(retarr, arr);//内容新前将其保存一份;
	//小人坐标更新前保存一份
	*retrow = *row;
	*retline = *line;
}

void SlectMap(char arr[][LINE], char map[][ROW][LINE], int select)//选择地图
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < LINE; j++)
		{
			arr[i][j] = map[select][i][j];
		}
	}
}
char map[2][10][10] = { //0位墙壁■,1位空白,2为箱子●,3为目的点¤,4为人♀,5为小人儿与目标点重合★,6为箱子进入了目标点☆

	{
		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
		{ 0, 0, 3, 1, 0, 0, 0, 1, 0, 0 },
		{ 0, 0, 1, 1, 1, 1, 1, 3, 1, 0 },
		{ 0, 1, 1, 1, 2, 1, 1, 1, 0, 0 },
		{ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
		{ 0, 1, 2, 1, 0, 1, 2, 0, 0, 0 },
		{ 0, 0, 0, 1, 1, 1, 1, 1, 0, 0 },
		{ 0, 0, 0, 1, 1, 1, 1, 1, 3, 0 },
		{ 0, 3, 1, 2, 1, 4, 1, 1, 0, 0 },
		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
	},//地图1
	{
		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
		{ 0, 3, 0, 0, 0, 0, 0, 1, 3, 0 },
		{ 0, 3, 0, 1, 1, 1, 1, 3, 1, 0 },
		{ 0, 1, 1, 1, 2, 1, 2, 1, 1, 0 },
		{ 0, 1, 2, 1, 1, 1, 1, 0, 0, 0 },
		{ 0, 1, 1, 2, 0, 1, 1, 0, 0, 0 },
		{ 0, 1, 0, 1, 1, 1, 2, 1, 1, 0 },
		{ 0, 3, 0, 2, 1, 0, 1, 1, 0, 0 },
		{ 0, 3, 1, 1, 1, 4, 1, 1, 0, 0 },
		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
	},
};

void Game()
{
	Load();
	char arr[ROW][LINE];
	int select = 0;
	int quit = 0;
	while (!quit)
	{
		outtextxy(0,0,"请选择你的关卡");
		outtextxy(0,30,"###########################");
		outtextxy(0,60,"1.第一关##########2.第二关###");
		outtextxy(0,90,"###########################");
		scanf("%d", &select);
		switch (select)
		{
		case 1:
			select = 0;//数组下标从0开始
			SlectMap(arr, map, select);
			quit = 1;
			break;
		case 2:
			select = 1;
			SlectMap(arr, map, select);
			quit = 1;
			break;
		default:
			outtextxy(0, 0, "输入有误,请从新输入");
		}
	}
	ShowMap(arr);
	int row = 8, line = 5;//小人初始横纵坐标
	int boxs = 4;//还未到达目标点的盒子数
	char retarr[ROW][LINE];
	Retain(retarr, arr);//先保存一份,直接按返回不会出错
	int retrow = row, retline = line;//旧的小人地址
	while (boxs)
	{
		Move(arr, &row, &line, retarr, &retrow, &retline);//移动小人
		Judge(arr, &boxs);//剩余目标点数
		if (boxs == 0)
			outtextxy(0, 0, "恭喜你,通关成功");
	}
}



#ifndef _GAME_H_
#define _GAME_H_

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#pragma warning (disable :4996)
#include <graphics.h>



#define ROW 10
#define LINE 10

void Load();
void SlectMap(char arr[][LINE], char[][ROW][LINE], int select);
void Game();
void Retain(char retarr[][LINE], char arr[][LINE]);
void Save(char retarr[][LINE], char arr[][LINE], int *row, int *line, int *retrow, int *retline);
#endif
#include "game.h"

int main()
{

	Game();

	getchar();
	return 0;
}
  • 17
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
这是一个比较复杂的任务,需要涉及到很多方面的知识,包括 Java GUI 编程、事件处理、游戏逻辑设计等。以下是一个简单的实现示例,仅供参考。 首先,你需要创建一个 JFrame 对象作为游戏窗口,并为其设置标题、大小和默认关闭操作。然后,你需要在窗口中添加一个 JPanel 对象,用于绘制游戏地图和游戏元素。 接下来,你需要实现游戏地图和游戏元素的模型。可以使用一个二维数组来表示游戏地图,其中每个元素表示一个格子的状态,例如: - 0:空地 - 1:墙壁 - 2:目标点 - 3:玩家 - 4:箱子 在游戏开始时,你需要读取地图数据并初始化游戏元素。可以使用 JLabel 对象来表示游戏元素,并将它们添加到 JPanel 上。可以使用 ImageIcon 对象来加载游戏元素的图片,并使用 setIcon() 方法将其设置为 JLabel 的图标。 接下来,你需要为游戏元素添加事件处理。对于玩家元素,可以使用键盘监听器来处理玩家移动操作。当玩家按下方向键时,你需要判断玩家能否移动到目标位置,如果可以,就更新玩家的位置并重新绘制游戏地图。对于箱子元素,你需要判断箱子能否移动到目标位置。如果可以,就更新箱子和玩家的位置,并重新绘制游戏地图。 最后,你需要实现游戏结束的判断。当所有箱子都被移动到目标点时,游戏结束,弹出提示框显示游戏时间和步数,可以使用 JOptionPane 类来实现。 下面是一个简单的示例代码,仅供参考: ```java import javax.swing.*; import java.awt.*; import java.awt.event.*; public class SokobanGame extends JFrame implements KeyListener { private JPanel gamePanel; private JLabel[][] map; private ImageIcon floorIcon, wallIcon, targetIcon, playerIcon, boxIcon; private int[][] mapData = { {1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 2, 0, 3, 1, 0, 1}, {1, 0, 4, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 1}, {1, 1, 1, 1, 1, 1, 1, 1}, }; private int playerX, playerY, boxX, boxY; private int steps = 0; private long startTime; public SokobanGame() { setTitle("Sokoban Game"); setSize(400, 400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); gamePanel = new JPanel(); gamePanel.setLayout(new GridLayout(mapData.length, mapData[0].length)); add(gamePanel); floorIcon = new ImageIcon("floor.png"); wallIcon = new ImageIcon("wall.png"); targetIcon = new ImageIcon("target.png"); playerIcon = new ImageIcon("player.png"); boxIcon = new ImageIcon("box.png"); map = new JLabel[mapData.length][mapData[0].length]; for (int i = 0; i < mapData.length; i++) { for (int j = 0; j < mapData[i].length; j++) { JLabel label = new JLabel(); label.setIcon(getIcon(mapData[i][j])); map[i][j] = label; gamePanel.add(label); if (mapData[i][j] == 3) { playerX = j; playerY = i; } else if (mapData[i][j] == 4) { boxX = j; boxY = i; } } } startTime = System.currentTimeMillis(); addKeyListener(this); setFocusable(true); } private ImageIcon getIcon(int type) { switch (type) { case 0: return floorIcon; case 1: return wallIcon; case 2: return targetIcon; case 3: return playerIcon; case 4: return boxIcon; default: return null; } } private boolean canMove(int x, int y) { if (mapData[y][x] == 1) { return false; } else if (mapData[y][x] == 4) { int dx = x - playerX; int dy = y - playerY; int nx = x + dx; int ny = y + dy; if (mapData[ny][nx] != 0 && mapData[ny][nx] != 2) { return false; } } return true; } private void movePlayer(int x, int y) { mapData[playerY][playerX] = 0; mapData[y][x] = 3; map[playerY][playerX].setIcon(getIcon(0)); map[y][x].setIcon(playerIcon); playerX = x; playerY = y; steps++; } private void moveBox(int x, int y) { mapData[boxY][boxX] = 0; mapData[y][x] = 4; map[boxY][boxX].setIcon(getIcon(0)); map[y][x].setIcon(boxIcon); boxX = x; boxY = y; } private boolean isWin() { for (int i = 0; i < mapData.length; i++) { for (int j = 0; j < mapData[i].length; j++) { if (mapData[i][j] == 4) { return false; } } } return true; } @Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); int dx = 0, dy = 0; switch (keyCode) { case KeyEvent.VK_UP: dy = -1; break; case KeyEvent.VK_DOWN: dy = 1; break; case KeyEvent.VK_LEFT: dx = -1; break; case KeyEvent.VK_RIGHT: dx = 1; break; } int nx = playerX + dx; int ny = playerY + dy; if (canMove(nx, ny)) { if (mapData[ny][nx] == 4) { int bx = boxX + dx; int by = boxY + dy; if (canMove(bx, by)) { moveBox(bx, by); movePlayer(nx, ny); } } else { movePlayer(nx, ny); } if (isWin()) { long endTime = System.currentTimeMillis(); long time = (endTime - startTime) / 1000; JOptionPane.showMessageDialog(this, "You win!\nSteps: " + steps + "\nTime: " + time + "s"); dispose(); } } } @Override public void keyTyped(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { } public static void main(String[] args) { SokobanGame game = new SokobanGame(); game.setVisible(true); } } ``` 注意:这份代码并没有实现登陆界面,如果你需要实现登陆界面,可以参考 Java Swing 的 GUI 编程教程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值