本篇博客主要是对推箱子地图编辑器功能的代码讲解。
首先给出这段代码的部分运行截图:
重难点:
地图编辑器主要有三个重难点:
需要有一个绘制地图的界面
能够实现地图绘制的功能
地图绘制完成后需要将地图内容保存下来
下面就是每块内容的代码片段:
界面显示
界面显示分成绘图区与功能区
绘图区为label数组(大小为20*20)
功能区为8个按钮,对应各自的功能
public void init() {//界面显示
for(i=0;i<20;i++) {
for(j=0;j<20;j++) {
mymap[i][j]=0;
jl[i][j]=new JLabel(new ImageIcon());//实例化label
this.add(jl[i][j]);
jl[i][j].addMouseListener(new mouse());//label添加监听器
jl[i][j].setBounds(i*30+90, j*30+20, 30, 30);//设置label位置和大小
jl[i][j].setOpaque(true);//true表示不透明,false表示透明
}
}
//窗体添加控件
this.add(jb1);this.add(jb2);
this.add(jb3);this.add(jb4);
this.add(jb5);this.add(jb6);
this.add(jb7);this.add(jb8);
//按钮设置位置和大小
jb1.setBounds(35, 640, 80, 40);jb2.setBounds(125, 640, 80, 40);
jb3.setBounds(215, 640, 80, 40);jb4.setBounds(305, 640, 80, 40);
jb8.setBounds(395, 640, 80, 40);jb5.setBounds(485, 640, 80, 40);
jb6.setBounds(575, 640, 80, 40);jb7.setBounds(665, 640, 80, 40);
//给按钮添加鼠标事件
jb1.addMouseListener(new mouse());jb2.addMouseListener(new mouse());
jb3.addMouseListener(new mouse());jb4.addMouseListener(new mouse());
jb5.addMouseListener(new mouse());jb6.addMouseListener(new mouse());
jb7.addMouseListener(new mouse());jb8.addMouseListener(new mouse());
//设置按钮背景
jb1.setBackground(new Color(140,199,181));jb2.setBackground(new Color(140,199,181));
jb3.setBackground(new Color(140,199,181));jb4.setBackground(new Color(140,199,181));
jb5.setBackground(new Color(140,199,181));jb6.setBackground(new Color(140,199,181));
jb7.setBackground(new Color(140,199,181));jb8.setBackground(new Color(140,199,181));
}
主要功能实现
地图的绘制功能需要鼠标先点击想要绘制的图片相对应的按钮,然后再点击label后就可以在点击的label上面显示相对应的图片。但对于墙块,空白块一个个点击太过繁琐,所以可以使用持续按压进行绘制,但由于java中没有专门对鼠标持续按压进行监听的监听器,所以只能通过对鼠标按压与释放,进入的监听器进行组合实现上述功能。
当鼠标按压时,标识符为1,当鼠标释放时,标识符为0,只有当标识符为1且进入label就改变label的图片。
class mouse extends MouseAdapter{
@Override
public void mousePressed(MouseEvent e) {//鼠标按压事件
// TODO Auto-generated method stub
if(e.getSource()==jb1) {pd=1;}//点击“墙块”按钮
else if(e.getSource()==jb2) {pd=2;}//点击“玩家”按钮
else if(e.getSource()==jb3) {pd=3;}//点击“箱子”按钮
else if(e.getSource()==jb4) {pd=4;}//点击“目的地”按钮
else if(e.getSource()==jb5) {//点击“清空”按钮
for(i=0;i<20;i++) {
for(j=0;j<20;j++) {
jl[i][j].setIcon(new ImageIcon());//改变label图片
mymap[i][j]=0;//改变label对应数据
}
}
}
else if(e.getSource()==jb6) {save();}//点击“保存”按钮
else if(e.getSource()==jb7) {new game_tui_1();dispose();}//点击“返回”按钮
else if(e.getSource()==jb8) {pd=5;}//点击“空白块”按钮
else {//点击label
for(i=0;i<20;i++) {
for(j=0;j<20;j++) {
if(e.getSource()==jl[i][j]) {//获取点击了哪个label
pd_press=1;//用于标识判断按压
if(pd==0) {}//pd=0表示没有点击任何按钮,点击label不做任何操作
else if(pd==1) {jl[i][j].setIcon(new ImageIcon("shiyan4_image/wall.png"));mymap[i][j]=1;}//将label显示图片墙块
else if(pd==2) {jl[i][j].setIcon(new ImageIcon("shiyan4_image/player.png"));mymap[i][j]=5;}//将label显示图片玩家
else if(pd==3) {jl[i][j].setIcon(new ImageIcon("shiyan4_image/box1.png"));mymap[i][j]=3;}//将label显示图片箱子
else if(pd==4) {jl[i][j].setIcon(new ImageIcon("shiyan4_image/destination.png"));mymap[i][j]=4;}//将label显示图片目的地
else if(pd==5) {jl[i][j].setIcon(new ImageIcon());mymap[i][j]=0;}//将label显示空白块
}
}
}
}
}
@Override
public void mouseReleased(MouseEvent e) {//鼠标释放事件
// TODO Auto-generated method stub
for(int i=0;i<20;i++) {
for(int j=0;j<20;j++) {
if(e.getSource()==jl[i][j]) {
pd_press=0;//释放将按压标识改回0
}
}
}
}
@Override
public void mouseEntered(MouseEvent e) {//鼠标进入事件
// TODO Auto-generated method stub
//长按绘图
for(int i=0;i<20;i++) {
for(int j=0;j<20;j++) {
if(e.getSource()==jl[i][j]&&pd_press==1) {//鼠标进入label且处在按压
if(pd==0) {}//pd=0表示没有点击任何按钮,点击label不做任何操作
else if(pd==1) {jl[i][j].setIcon(new ImageIcon("shiyan4_image/wall.png"));mymap[i][j]=1;}//绘图墙块
else if(pd==5) {jl[i][j].setIcon(new ImageIcon());mymap[i][j]=0;}//绘图空白块
}
}
}
}
}
地图写入
地图写入是在点击保存按钮后需要实现的,且地图不是任何时候都能保存的,需要一个简单的判断,需要满足以下条件:
存在玩家控制的方块,且只有一个
存在箱子 和 目的地
箱子和目的地的数量相等
这些判断条件可以使玩家绘制出的地图更具有可玩性。
public void save() {//保存数据到文件
// TODO Auto-generated method stub
String content="";FileOutputStream fout;byte[] b;
try {
File file=new File("shiyan4_maps\\11.map");//文件路径,根据实际自行修改
if(!file.exists()) file.createNewFile();//判断11.map文件是否存在,不存在新建一个
fout=new FileOutputStream(file,false); //创建文件输出流,false代表覆盖修改,ture代表添加修改
//覆盖修改:覆盖之前的内容 添加修改:保留之前的内容,在原来基础上添加内容
for(int i=0;i<20;i++) {
for(int j=0;j<20;j++) {
content=content+mymap[j][i];
}
if(i!=19)
content=content+"\r\n";//“\r\n” 是回车
}
b=content.getBytes();
if(pd_save()==1) {//判断是否要保存
fout.write(b);//文件写入
JOptionPane.showMessageDialog(null, " 文件写入成功!!", "消息",JOptionPane.PLAIN_MESSAGE);
}
else {JOptionPane.showMessageDialog(null, " 文件写入失败!!", "消息",JOptionPane.ERROR_MESSAGE);
}
}
catch (IOException e) {
// TODO Auto-generated catch block
e.getMessage();
}
}
public int pd_save() {//判断是否要保存
//保存要满足的条件:存在玩家控制,箱子数要等于目的地数
int num_player=0,num_end=0,num_box=0;
for(int i=0;i<20;i++) {
for(int j=0;j<20;j++) {
if(mymap[i][j]==5) num_player++;
else if(mymap[i][j]==4) num_end++;
else if(mymap[i][j]==3) num_box++;
}
}
if(num_player!=1||num_end!=num_box||num_end==0)return 0;
else return 1;
}
最后附上 推箱子 地图编辑器功能 完整的代码
地图编辑器完整代码
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class game_tui_3 extends JFrame{
JButton jb1 =new JButton("墙块");
JButton jb2 =new JButton("玩家");
JButton jb3 =new JButton("箱子");
JButton jb4 =new JButton("目的地");
JButton jb8 =new JButton("空白块");
JButton jb5 =new JButton("清空");
JButton jb6 =new JButton("保存");
JButton jb7 =new JButton("返回");
JLabel[][] jl=new JLabel[20][20];
int[][] mymap=new int[20][20];int pd=0;
int i=0,j=0;int pd_press=0;
public game_tui_3() {
//自定义方法
init();//初始化
//窗口属性
this.setTitle("地图编辑器");//窗体名称
this.setSize(800, 730);//窗体大小
this.setDefaultCloseOperation(3);//窗体关闭按钮功能
this.setLocationRelativeTo(null);//窗体居中
this.setResizable(false);//窗体不可拉伸
this.setLayout(null);
this.getContentPane().setBackground(new Color(214,213,183));//设置背景颜色
this.setVisible(true);//窗体可视
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new game_tui_3();
}
public void save() {//保存地图数据到文件
// TODO Auto-generated method stub
String content="";FileOutputStream fout;byte[] b;
try {
File file=new File("shiyan4_maps\\11.map");//文件路径,根据实际自行修改
if(!file.exists()) file.createNewFile();//判断11.map文件是否存在,不存在新建一个
fout=new FileOutputStream(file,false); //创建文件输出流,false代表覆盖修改,ture代表添加修改
//覆盖修改:覆盖之前的内容 添加修改:保留之前的内容,在原来基础上添加内容
for(int i=0;i<20;i++) {
for(int j=0;j<20;j++) {
content=content+mymap[j][i];
}
if(i!=19)
content=content+"\r\n";//“\r\n” 是回车
}
b=content.getBytes();
if(pd_save()==1) {//判断是否要保存
fout.write(b);
JOptionPane.showMessageDialog(null, " 文件写入成功!!", "消息",JOptionPane.PLAIN_MESSAGE);
}
else {JOptionPane.showMessageDialog(null, " 文件写入失败!!", "消息",JOptionPane.ERROR_MESSAGE);
}
}
catch (IOException e) {
// TODO Auto-generated catch block
e.getMessage();
}
}
public int pd_save() {//判断是否要保存
//保存要满足的条件:存在玩家控制,箱子数要等于目的地数
int num_player=0,num_end=0,num_box=0;
for(int i=0;i<20;i++) {
for(int j=0;j<20;j++) {
if(mymap[i][j]==5) num_player++;
else if(mymap[i][j]==4) num_end++;
else if(mymap[i][j]==3) num_box++;
}
}
if(num_player!=1||num_end!=num_box||num_end==0)return 0;
else return 1;
}
public void init() {//界面显示
for(i=0;i<20;i++) {
for(j=0;j<20;j++) {
mymap[i][j]=0;
jl[i][j]=new JLabel(new ImageIcon());//实例化label
this.add(jl[i][j]);
jl[i][j].addMouseListener(new mouse());//label添加监听器
jl[i][j].setBounds(i*30+90, j*30+20, 30, 30);//设置label位置和大小
jl[i][j].setOpaque(true);//true表示不透明,false表示透明
}
}
//窗体添加控件
this.add(jb1);this.add(jb2);
this.add(jb3);this.add(jb4);
this.add(jb5);this.add(jb6);
this.add(jb7);this.add(jb8);
//按钮设置位置和大小
jb1.setBounds(35, 640, 80, 40);jb2.setBounds(125, 640, 80, 40);
jb3.setBounds(215, 640, 80, 40);jb4.setBounds(305, 640, 80, 40);
jb8.setBounds(395, 640, 80, 40);jb5.setBounds(485, 640, 80, 40);
jb6.setBounds(575, 640, 80, 40);jb7.setBounds(665, 640, 80, 40);
//给按钮添加鼠标事件
jb1.addMouseListener(new mouse());jb2.addMouseListener(new mouse());
jb3.addMouseListener(new mouse());jb4.addMouseListener(new mouse());
jb5.addMouseListener(new mouse());jb6.addMouseListener(new mouse());
jb7.addMouseListener(new mouse());jb8.addMouseListener(new mouse());
//设置按钮背景
jb1.setBackground(new Color(140,199,181));jb2.setBackground(new Color(140,199,181));
jb3.setBackground(new Color(140,199,181));jb4.setBackground(new Color(140,199,181));
jb5.setBackground(new Color(140,199,181));jb6.setBackground(new Color(140,199,181));
jb7.setBackground(new Color(140,199,181));jb8.setBackground(new Color(140,199,181));
}
class mouse extends MouseAdapter{
@Override
public void mousePressed(MouseEvent e) {//鼠标按压事件
// TODO Auto-generated method stub
if(e.getSource()==jb1) {pd=1;}//点击“墙块”按钮
else if(e.getSource()==jb2) {pd=2;}//点击“玩家”按钮
else if(e.getSource()==jb3) {pd=3;}//点击“箱子”按钮
else if(e.getSource()==jb4) {pd=4;}//点击“目的地”按钮
else if(e.getSource()==jb5) {//点击“清空”按钮
for(i=0;i<20;i++) {
for(j=0;j<20;j++) {
jl[i][j].setIcon(new ImageIcon());//改变label图片
mymap[i][j]=0;//改变label对应数据
}
}
}
else if(e.getSource()==jb6) {save();}//点击“保存”按钮
else if(e.getSource()==jb7) {/*new game_tui_1();dispose();*/}//点击“返回”按钮,由于单独代码,所以页面跳转代码注释了
else if(e.getSource()==jb8) {pd=5;}//点击“空白块”按钮
else {//点击label
for(i=0;i<20;i++) {
for(j=0;j<20;j++) {
if(e.getSource()==jl[i][j]) {//获取点击了哪个label,图片路径根据实际自行修改
pd_press=1;//用于标识判断按压
if(pd==0) {}//pd=0表示没有点击任何按钮,点击label不做任何操作
else if(pd==1) {jl[i][j].setIcon(new ImageIcon("shiyan4_image/wall.png"));mymap[i][j]=1;}//将label显示图片墙块
else if(pd==2) {jl[i][j].setIcon(new ImageIcon("shiyan4_image/player.png"));mymap[i][j]=5;}//将label显示图片玩家
else if(pd==3) {jl[i][j].setIcon(new ImageIcon("shiyan4_image/box1.png"));mymap[i][j]=3;}//将label显示图片箱子
else if(pd==4) {jl[i][j].setIcon(new ImageIcon("shiyan4_image/destination.png"));mymap[i][j]=4;}//将label显示图片目的地
else if(pd==5) {jl[i][j].setIcon(new ImageIcon());mymap[i][j]=0;}//将label显示空白块
}
}
}
}
}
@Override
public void mouseReleased(MouseEvent e) {//鼠标释放事件
// TODO Auto-generated method stub
for(int i=0;i<20;i++) {
for(int j=0;j<20;j++) {
if(e.getSource()==jl[i][j]) {
pd_press=0;//释放将按压标识改回0
}
}
}
}
@Override
public void mouseEntered(MouseEvent e) {//鼠标进入事件
// TODO Auto-generated method stub
//长按绘图
for(int i=0;i<20;i++) {
for(int j=0;j<20;j++) {
if(e.getSource()==jl[i][j]&&pd_press==1) {//鼠标进入label且处在按压,图片路径根据实际自行修改
if(pd==0) {}//pd=0表示没有点击任何按钮,点击label不做任何操作
else if(pd==1) {jl[i][j].setIcon(new ImageIcon("shiyan4_image/wall.png"));mymap[i][j]=1;}//绘图墙块
else if(pd==5) {jl[i][j].setIcon(new ImageIcon());mymap[i][j]=0;}//绘图空白块
}
}
}
}
}
}