手把手教你做遊戲——JAVA GUI 推箱子(一)

閱讀這篇博客需要一點的編程基礎,一點即可。關於本項目請看博主博客。本教程採用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 推箱子(五)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章