手把手教你做游戏——JAVA GUI 推箱子(一)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_40176716/article/details/96454589

阅读这篇博客需要一点的编程基础,一点即可。关于本项目请看博主博客。本教程采用JAVA + Eclipse编写,不懂Eclipse请点击→传送门

 

创建项目并导入资源
创建项目并导入资源

​​​​

本篇博客目录

​​​​

地图编辑器的接口 MapConfig.java

 地图编辑器界面 CreatMap.java

1.界面创建

2.下拉列表框显示图片

 3.显示界面显示地图

4.保存地图

 5.代码优化

工具类 Utils.java

测试类test.java

最终效果


  • 地图编辑器的接口 MapConfig.java

我们要先设置地图编辑器的大小,地图编辑器上每个资源的大小,即每个格子的大小,通过简单的6个图片,构成一个完整的地图

本人默认设置地图为800*800,每个素材50*50。即每行每列都是18个素材

地图数组中,数字带边素材。0墙 1地板 2空箱子 3 箱子 4箱子点 5出生点

package cn.edu.caztc.sokobangame;

import javax.swing.ImageIcon;

public interface MapConfig {
	/**素材宽度*/
    int SOUREC_WIDTH = 50;
    /**素材高度*/
    int SOUREC_HEIGHT = 50;  
    /**地图宽度*/
    int MAP_WIDTH = 800;  
    /**地图高度*/
    int MAP_HEIGHT= 800;  
    /**地图保存的位置 */
    String PATH = "D:\\推箱子";  
   
    ImageIcon icon101 = new ImageIcon("images/墙.png"); 
    ImageIcon icon102 = new ImageIcon("images/地板.png"); 
    ImageIcon icon103 = new ImageIcon("images/空箱子.png"); 
    ImageIcon icon104 = new ImageIcon("images/箱子.png"); 
    ImageIcon icon105 = new ImageIcon("images/箱子点.png"); 
    ImageIcon icon106 = new ImageIcon("images/player.png");  
    
    //将所有的图片素材对象放入一个数组中,便于窗体上的下拉列表添加所有的图片素材  
    ImageIcon[] allicons = {icon101,icon102,icon103,icon104,icon105,icon106};
}
  •  地图编辑器界面 CreatMap.java

CreatMap()构造方法,用于创造界面及控件

void setBox(JComboBox<ImageIcon> box) 将接口里面的allicons中6个素材添加到box中,box为下拉列表

class PanelListenner 面板监听类,鼠标点击某位置,给位置对应的数组赋值

class MySetPanel  临时地图面板类,显示地图

class Buttonlistenner 按键监听类,点击保存地图按钮则保存地图文件

1.界面创建

设想中界面大致是这样的,左侧为显示界面,用于地图显示,jpanel实现。右侧配置,编辑框+按钮实现配置确认等。保存为保存按钮。其中有一个下拉图片框用于选择素材。

 代码:

package cn.edu.caztc.sokobangame;

import java.awt.Dimension;

import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;

public class CreatMap extends JFrame implements MapConfig {

	private JPanel contentPane;
	private JTextField tf_level;
	private JPanel panel;

	// 关卡变量
	int level = 1;

	// 用来选择素材的下拉表
	private JComboBox<ImageIcon> box;

	/**
	 * 创建界面
	 */
	public CreatMap() {

		// 设置标题
		setTitle("推箱子地图编辑器");
		// 设置关闭方式
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		// 设置大小位置
		setBounds(100, 100, 1180, 735);
		// 面板
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(null);

		// 滚动面板
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(14, 13, 800, 653);
		contentPane.add(scrollPane);

		// 地图面板
		panel = new JPanel();
		panel.setPreferredSize(new Dimension(800, 800));
		scrollPane.setViewportView(panel);
		scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

		// 标签
		JLabel lb_1 = new JLabel("关卡");
		lb_1.setBounds(874, 160, 111, 36);
		contentPane.add(lb_1);

		// 编辑框
		tf_level = new JTextField();
		// 设置默认关卡
		tf_level.setText(String.valueOf(level));
		tf_level.setColumns(10);
		tf_level.setBounds(1003, 158, 117, 40);
		contentPane.add(tf_level);

		// 下拉菜单
		box = new JComboBox<ImageIcon>();
		box.setBounds(939, 312, 123, 99);
		contentPane.add(box);

		// 界面居中
		setLocationRelativeTo(null);
		// 显示界面
		setVisible(true);
	}

}
创建界面效果

2.下拉列表框显示图片

 顾名思义,显示图片好选择啊。修改下面红框内容即可。

 代码:

//省略***********************************
//下拉菜单
		box = new JComboBox<ImageIcon>();
		setBox(box);
		box.setSelectedIndex(0);
		box.setBounds(939, 312, 123, 99);
		contentPane.add(box);
//省略
//省略*****************************************
//省略
// 设置地图中的素材下拉表
	public void setBox(JComboBox<ImageIcon> box) {
		for (int i = 0; i < allicons.length; i++) {
			box.addItem(allicons[i]);
		}
	}
下拉列表框显示图片效果

 3.显示界面显示地图

做了前面的准备我们当然要显示地图了啊。思路呢,就是JPanel的paint画出来。我们定义一个int型3维数组,用于保存地图。其中第一二位代表地图坐标,第三位代表地图图片所对应的数字。我默认为0墙 1地板 2空箱子 3 箱子 4箱子点 5出生点。一张地图必须且仅有一个5.再定义一个ImageIcon2维数组,用于保存所对应的图片。

package cn.edu.caztc.sokobangame;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;

public class CreatMap extends JFrame implements MapConfig {

	private JPanel contentPane;
	private JTextField tf_level;
	private JPanel panel;

	// 关卡变量
	int level = 1;

	// 用来选择素材的下拉表
	private JComboBox<ImageIcon> box;
	// 地图数组
	static int[][][] map1 = new int[MAP_WIDTH / SOUREC_WIDTH][MAP_HEIGHT / SOUREC_HEIGHT][1];
	// 图片数组,用于显示地图
	static ImageIcon[][] icons = new ImageIcon[MAP_WIDTH / SOUREC_WIDTH][MAP_HEIGHT / SOUREC_HEIGHT];

	/**
	 * 创建界面
	 */
	public CreatMap() {

		// 设置标题
		setTitle("推箱子地图编辑器");
		// 设置关闭方式
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		// 设置大小位置
		setBounds(100, 100, 1180, 735);
		// 面板
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(null);

		// 滚动面板
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(14, 13, 800, 653);
		contentPane.add(scrollPane);

		// 地图面板
		panel = new MySetPanel();
		panel.setPreferredSize(new Dimension(800, 800));
		scrollPane.setViewportView(panel);
		scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

		// 标签
		JLabel lb_1 = new JLabel("关卡");
		lb_1.setBounds(874, 160, 111, 36);
		contentPane.add(lb_1);

		// 编辑框
		tf_level = new JTextField();
		// 设置默认关卡
		tf_level.setText(String.valueOf(level));
		tf_level.setColumns(10);
		tf_level.setBounds(1003, 158, 117, 40);
		contentPane.add(tf_level);

		// 下拉菜单
		box = new JComboBox<ImageIcon>();
		setBox(box);
		box.setSelectedIndex(0);
		box.setBounds(939, 312, 123, 99);
		contentPane.add(box);

		// 保存地图按钮
		JButton btn_save = new JButton("保存地图");
		btn_save.setBounds(945, 578, 117, 40);
		contentPane.add(btn_save);

		// 给面板安装鼠标监听器
		PanelListenner plis = new PanelListenner();
		panel.addMouseListener(plis);

		// 界面居中
		setLocationRelativeTo(null);
		// 显示界面
		setVisible(true);
	}

	// 设置地图中的素材下拉表
	public void setBox(JComboBox<ImageIcon> box) {
		for (int i = 0; i < allicons.length; i++) {
			box.addItem(allicons[i]);
		}
	}

	/**
	 * 面板监听类
	 * 
	 * @author 莫言情难忘
	 */
	class PanelListenner extends MouseAdapter {
		public void mouseClicked(MouseEvent e) {
			int num = 0;
			// 得到该位置对应的数组下标
			int j = e.getX() / SOUREC_WIDTH;
			int i = e.getY() / SOUREC_HEIGHT;
			System.out.println(i + "<>" + j);
			// 得到选择框中的图片
			ImageIcon icon = (ImageIcon) box.getSelectedItem();
			// 0墙 1地板 2空箱子 3 箱子 4箱子点 5出生点
			int index = box.getSelectedIndex();
			if (index > 5) {
				index = 0;
				icons[i][j] = icon101;
			} else {
				map1[i][j][0] = index;
				icons[i][j] = icon;
			}
			panel.repaint();
		}
	}

	/**
	 * 临时地图面板类
	 * 
	 * @author 莫言情难忘
	 * 
	 */
	class MySetPanel extends JPanel {

		@Override
		public void paint(Graphics g) {
			super.paint(g);
			for (int i = 0; i < MAP_HEIGHT / SOUREC_HEIGHT; i++) {
				for (int j = 0; j < MAP_WIDTH / SOUREC_WIDTH; j++) {
					if (icons[i][j] != null) {
						g.drawImage(icons[i][j].getImage(), getDrawX(j), getDrawY(i), SOUREC_WIDTH, SOUREC_HEIGHT,
								null);
					}
				}
			}
		}

		// 将数组下标转化成对应的图片左上角坐标
		public int getDrawX(int j) {
			int x = j * 50;
			return x;
		}

		// 将数组下标转化成对应的图片左上角坐标
		public int getDrawY(int i) {
			int y = i * 50;
			return y;
		}
	}

}
显示界面效果

4.保存地图

最后一步,保存地图啊。因为我们有个int型3维数组,所以我们把这个数组依次保存即可。有一点注意,我们一个个把所有素材点出来很浪费时间,所以我们把0设置为墙的作用体现出来了。不用做墙默认也是墙。其中的一些方法,在下方工具类中包含。

package cn.edu.caztc.sokobangame;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.DataOutputStream;
import java.io.FileOutputStream;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;

public class CreatMap extends JFrame implements MapConfig {

	private JPanel contentPane;
	private JTextField tf_level;
	private JPanel panel;

	// 关卡变量
	int level = 1;

	// 用来选择素材的下拉表
	private JComboBox<ImageIcon> box;
	// 地图数组
	static int[][][] map1 = new int[MAP_WIDTH / SOUREC_WIDTH][MAP_HEIGHT / SOUREC_HEIGHT][1];
	// 图片数组,用于显示地图
	static ImageIcon[][] icons = new ImageIcon[MAP_WIDTH / SOUREC_WIDTH][MAP_HEIGHT / SOUREC_HEIGHT];

	/**
	 * 创建界面
	 */
	public CreatMap() {

		// 设置标题
		setTitle("推箱子地图编辑器");
		// 设置关闭方式
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		// 设置大小位置
		setBounds(100, 100, 1180, 735);
		// 面板
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(null);

		// 滚动面板
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(14, 13, 800, 653);
		contentPane.add(scrollPane);

		// 地图面板
		panel = new MySetPanel();
		panel.setPreferredSize(new Dimension(800, 800));
		scrollPane.setViewportView(panel);
		scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

		// 标签
		JLabel lb_1 = new JLabel("关卡");
		lb_1.setBounds(874, 160, 111, 36);
		contentPane.add(lb_1);

		// 编辑框
		tf_level = new JTextField();
		// 设置默认关卡
		tf_level.setText(String.valueOf(level));
		tf_level.setColumns(10);
		tf_level.setBounds(1003, 158, 117, 40);
		contentPane.add(tf_level);

		// 下拉菜单
		box = new JComboBox<ImageIcon>();
		setBox(box);
		box.setSelectedIndex(0);
		box.setBounds(939, 312, 123, 99);
		contentPane.add(box);

		// 保存地图按钮
		JButton btn_save = new JButton("保存地图");
		btn_save.setBounds(945, 578, 117, 40);
		contentPane.add(btn_save);

		// 给面板安装鼠标监听器
		PanelListenner plis = new PanelListenner();
		panel.addMouseListener(plis);

		// 给按钮安装事件监听器
		Buttonlistenner blis = new Buttonlistenner();
		btn_save.addActionListener(blis);
		// 界面居中
		setLocationRelativeTo(null);
		// 显示界面
		setVisible(true);
	}

	// 设置地图中的素材下拉表
	public void setBox(JComboBox<ImageIcon> box) {
		for (int i = 0; i < allicons.length; i++) {
			box.addItem(allicons[i]);
		}
	}

	/**
	 * 面板监听类
	 * 
	 * @author 莫言情难忘
	 */
	class PanelListenner extends MouseAdapter {
		public void mouseClicked(MouseEvent e) {
			int num = 0;
			// 得到该位置对应的数组下标
			int j = e.getX() / SOUREC_WIDTH;
			int i = e.getY() / SOUREC_HEIGHT;
			System.out.println(i + "<>" + j);
			// 得到选择框中的图片
			ImageIcon icon = (ImageIcon) box.getSelectedItem();
			// 0墙 1地板 2空箱子 3 箱子 4箱子点 5出生点
			int index = box.getSelectedIndex();
			if (index > 5) {
				index = 0;
				icons[i][j] = icon101;
			} else {
				map1[i][j][0] = index;
				icons[i][j] = icon;
			}
			panel.repaint();
		}
	}

	/**
	 * 临时地图面板类
	 * 
	 * @author 莫言情难忘
	 * 
	 */
	class MySetPanel extends JPanel {

		@Override
		public void paint(Graphics g) {
			super.paint(g);
			for (int i = 0; i < MAP_HEIGHT / SOUREC_HEIGHT; i++) {
				for (int j = 0; j < MAP_WIDTH / SOUREC_WIDTH; j++) {
					if (icons[i][j] != null) {
						g.drawImage(icons[i][j].getImage(), getDrawX(j), getDrawY(i), SOUREC_WIDTH, SOUREC_HEIGHT,
								null);
					}
				}
			}
		}

		// 将数组下标转化成对应的图片左上角坐标
		public int getDrawX(int j) {
			int x = j * 50;
			return x;
		}

		// 将数组下标转化成对应的图片左上角坐标
		public int getDrawY(int i) {
			int y = i * 50;
			return y;
		}
	}

	/**
	 * 按键监听类
	 * 
	 * @author 莫言情难忘
	 * 
	 */
	class Buttonlistenner implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			// 如果按下了创建按钮,就保存地图
			if (e.getActionCommand().equals("保存地图")) {
				level = Integer.parseInt(tf_level.getText());
				if (Utils.IsExistence(PATH + "\\diy" + level + ".map")) {
					int n = JOptionPane.showConfirmDialog(null, "地图已存在,是否覆盖?", "警告", JOptionPane.YES_NO_OPTION);// 0确定
																												// 1取消
					if (n == 0) {
						// 确定即保存
						CreatMapTxt();
					}
				} else {
					// 不存在文件则创建文件
					CreatMapTxt();
				}
			}
		}
	}

	/**
	 * 创建地图文件
	 */
	void CreatMapTxt() {
		try {
			// 得到文件输出流
			FileOutputStream fos = new FileOutputStream(PATH + "\\diy" + level + ".map");
			// 将文件输出流包装成基本数据输出流
			DataOutputStream dos = new DataOutputStream(fos);
			// 从配置的接口中得到二维数组的大小(由于本类已经实现了上面的Mapconfig接口,所以可以直接用里面的数据)
			int i = MAP_HEIGHT / SOUREC_HEIGHT;
			int j = MAP_WIDTH / SOUREC_WIDTH;
			// 先数组的大小写入文件
			dos.writeInt(i);
			dos.writeInt(j);
			// 按顺序将三维数组写入文件,后面游戏读取地图的时候也要按这种顺序读回来
			for (int ii = 0; ii < i; ii++) {
				for (int jj = 0; jj < j; jj++) {
					dos.writeInt(map1[ii][jj][0]);
				}
			}
			// 强制流中的数据完全输出完
			dos.flush();
			// 关闭输出流
			dos.close();
		} catch (Exception ef) {
			ef.printStackTrace();
		}
		System.out.println("保存成功");
	}

}

 5.代码优化

其实,代码中有许多地方可以优化,我并未优化。因为可能涉及到后面的东西。比如,我们完全可以不需要imageicon数组保存各个坐标的图片,完全可以用数字替代图片,当paint到坐标时,从int数组中取出数字,然后通过一个getimage胡奥渠道其所对应的图片。再比如,没有必要设置一个按键监听类。因为他就一个按键。。。

  • 工具类 Utils.java

当然,工具类必不可少啊,所用的工具类

package cn.edu.caztc.sokobangame;

import java.io.File;

public class Utils{
	
	/**
	 * 判断是否存在文件file
	 * 
	 * @param file 如:D:\\推箱子\\1.map
	 * @return 存在即为true
	 */
	static boolean IsExistence(String file) {
		File fileuser = new File(file);
		if (!fileuser.exists()) {
			return false;
		}
		return true;
	}

}
  • 测试类test.java

这样地图编辑器就做好了,我们简单创建一个test类测试一下

最终效果

若有问题,可联系QQ1179307527.大佬若发现有错误,烦请指正。

手把手教你做游戏——JAVA GUI 推箱子(一)

手把手教你做游戏——JAVA GUI 推箱子(二)

手把手教你做游戏——JAVA GUI 推箱子(三)

手把手教你做游戏——JAVA GUI 推箱子(四)

手把手教你做游戏——JAVA GUI 推箱子(五)

猜你喜欢

转载自blog.csdn.net/qq_40176716/article/details/96454589