`

【纯JAVA语言做RPG游戏】1.做个瓷砖地图生成器

阅读更多

开个坑,想做个JAVA游戏。

虽然现在有着各种游戏引擎,使得做游戏的效率提高了很多,但是用着别人的代码来做感觉对自己也没啥提升,而且在游戏的模式上也不得不去迎合别人的思维,所以露珠准备应用前面学到的所有JAVA知识,来完成这个不用引擎的游戏项目,也算是一个对前面知识的总结与复习吧 O(∩_∩)O~

嗯,下面开始正题。

 

    说到RPG游戏,首先想到的是现在市面上各种各类的3D巨作,可这些是我这种菜鸟暂时无法企及的,所以呢,目标就定为2D的RPG游戏了.

    一想到2D的RPG游戏,立马回想起了一系列的以前电子词典上面的《金庸群侠传》《侠客行》之类的,这种游戏的共同点便是,所有的游戏元素都是一个一个的小方块,而游戏画面也就是由这一个一个的小方块构成。

    这些不同的小方块组成了游戏的地图,因为他们的上下左右都是对齐的,这样我们自然的就想到了用一种熟悉的数据结构来在游戏内部表示和储存它,那便是二维数组。我们用二维数组的位置i,j来确定小方块在地图中的坐标位置,而二维数组中元素的值便用来代表这一格元素的类型,例如用0来代表草地,用1来代表石头等等...

    这样选择好游戏的基本数据结构之后,我们首先想象我们的游戏已经完成,打开游戏程序后要进行的第一件事便是出现游戏的窗体,也就是说第一件事就是得载入游戏的地图,所以做这个游戏第一步便是在游戏开始之前就要编辑好一个二维数组,这个二维数组就是游戏的地图。

    这个数组我们不可能凭空去给他赋值,所以就需要一个图形化界面来让我们方便的去设置数组中的值:

    这便是这次的任务,做一个瓷砖地图编辑器,编辑完之后保存一个二维数组到一个文件中,以后写的游戏程序就能直接调用那个保存好的地图文件来载入地图了。

    由于是自己写的编辑器,就可以按自己的需求来配置这个地图编辑器的内容了

 

------------------------------------------------------------------------------------------------------------------------

 

1.首先写一个Mapconfig的接口,用来设置我们生成的地图的一些基本配置。(用接口来做配置文件是因为其他的类)

public interface MapConfig {
	//素材的大小
	int eleWidth = 50;
	int eleHeight = 50;
	//地图的大小
	int MapWidth = 2000;
	int MapHeight= 2000;
	//地图保存的位置
	String path = "D:\\mygame\\map\\map1.map";
	
	//用到的图片素材
	ImageIcon icon0 = new ImageIcon("000草地.png");
	ImageIcon icon100 = new ImageIcon("100红树.png");
	ImageIcon icon101 = new ImageIcon("101绿树.png");
	ImageIcon icon102 = new ImageIcon("102绿竹.png");
	//将所有的图片素材对象放入一个数组中,便于窗体上的下拉列表添加所有的图片素材
	ImageIcon[] allicons = {icon0,icon100,icon101,icon102}; 
}

 2.接下来便是写一个窗口类来实现上面那个地图配置接口,用来作为我们设置地图的窗口。(这里又有了一个问题,一个地图中有一些地形是可以通过的,而有一些地形是不能过的。这里我采用的区别方式是一个地图用三个二维数组表示,这三个数组分别代表【人物脚下的素材】,和【人物同一平面的素材】,以及【人物头上的素材】,这样分层定义地图,规定同一个层面的素材都是互斥不能通过的,就很好的解决了这个问题)

/**
 * 图形化设置地图数组
 * @author yy
 *
 */
public class SetMap extends JFrame implements MapConfig{
	//用来选择素材的下拉表(前面)
	JComboBox<ImageIcon> box;
	//用来选择素材层数的下拉表
	JComboBox<Integer> boxtype;
	//用来储存建立的地图数组的二维数组   (map1脚下素材   map2地表素材   map3上层素材)
	static int[][] map1 = new int[40][40];
	static int[][] map2 = new int[40][40];
	static int[][] map3 = new int[40][40];
	//用来存储对应的图片的二维数组 (这里的icon数组,只是用来将我们设置好的数组在界面上显示出来,不用保存进文件)
	static ImageIcon[][] icons1 = new ImageIcon[40][40];
	static ImageIcon[][] icons2 = new ImageIcon[40][40];
	static ImageIcon[][] icons3 = new ImageIcon[40][40];
	//编辑中的地图显示的面板
	static JPanel panel;
	/**
	 * 程序入口主函数
	 * @param args
	 */
	public static void main(String[] args) {
		SetMap sm = new SetMap();
		sm.init();
	}
	/**
	 * 设置窗体的方法
	 */
	public void init(){
		this.setTitle("地图数组生成");
		this.setSize(1000, 700);
		this.setDefaultCloseOperation(3);
		this.setLayout(new FlowLayout());
		//设置面板类
		panel = new MySetPanel();
		panel.setPreferredSize(new Dimension(MapWidth, MapHeight));
		JScrollPane jsp = new JScrollPane(panel);
		jsp.setPreferredSize(new Dimension(600, 600));
		jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		
		//创建选择素材层的下拉列表 (这里选择1表示当前编辑的是第一层的元素,2表示的当前编辑第二层元素,3同前面)
		boxtype = new JComboBox<Integer>();
		boxtype.addItem(1);
		boxtype.addItem(2);
		boxtype.addItem(3);
		
		//创建选择素材的下拉列表
		box = new JComboBox<ImageIcon>();
		//将我们前面配置文件中的所有图片素材放入下拉表的方法
		setBox(box);
		
		//创建按钮
		JButton create = new JButton("创建");
		create.setActionCommand("create");
		
		
		this.add(jsp);
		this.add(boxtype);
		this.add(box);
		this.add(create);
		this.setVisible(true);
		
		//给面板安装鼠标监听器
		PanelListenner plis = new PanelListenner();
		panel.addMouseListener(plis);
		//给按钮安装事件监听器
		Buttonlistenner blis = new Buttonlistenner();
		create.addActionListener(blis);
	}
	
	//设置地图中的素材下拉表
	public void setBox(JComboBox box){
		for(int i=0;i<allicons.length;i++){
			box.addItem(allicons[i]);
		}
	}
	
	/**
	 * 临时地图面板类
	 * @author yy
	 *
	 */
	class MySetPanel extends JPanel{
		
		@Override
		public void paint(Graphics g) {
			super.paint(g);
			for(int i=0;i<MapHeight/eleHeight;i++){
				for(int j=0;j<MapWidth/eleWidth;j++){
					//画第一层元素
					if(icons1[i][j]!=null){
						g.drawImage(icons1[i][j].getImage(), getDrawX(j), getDrawY(i), eleWidth, eleHeight, null);
					}
					//画第二层元素
					if(icons2[i][j]!=null){
						g.drawImage(icons2[i][j].getImage(), getDrawX(j), getDrawY(i), eleWidth, eleHeight, null);
					}
					//画第三层元素
					if(icons3[i][j]!=null){
						g.drawImage(icons3[i][j].getImage(), getDrawX(j), getDrawY(i), eleWidth, eleHeight, null);
					}
				}
			}
		}
		
		//将数组下标转化成对应的图片左上角坐标
		public int getDrawX(int j){
			int x = j*50;
			return x;
		}
		//将数组下标转化成对应的图片左上角坐标
		public int getDrawY(int i){
			int y = i*50; 	
			return y;
		}
	}
	
	/**
	 * 按键监听类
	 * @author yy
	 *
	 */
	class Buttonlistenner implements ActionListener{

		@Override
		public void actionPerformed(ActionEvent e) {
			//如果按下了创建按钮,就保存当前设置好的3个二维数组
			if(e.getActionCommand().equals("create")){
				try{
				System.out.println("开始保存");
				//得到文件输出流
				FileOutputStream fos = new FileOutputStream(path);
				//将文件输出流包装成基本数据输出流
				DataOutputStream dos = new DataOutputStream(fos);
				//从配置的接口中得到二维数组的大小(由于本类已经实现了上面的Mapconfig接口,所以可以直接用里面的数据)
				int i = MapHeight/eleHeight;
				int j = MapWidth/eleWidth;
				//先数组的大小写入文件
				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]);
						dos.writeInt(map2[ii][jj]);
						dos.writeInt(map3[ii][jj]);
					}
				}
				//强制流中的数据完全输出完
				dos.flush();
				//关闭输出流
				dos.close();
				System.out.println("保存完成");
				
				}catch(Exception ef){
					ef.printStackTrace();
				}
			}
		}
	}
	
	
	
	/**
	 * 面板监听类
	 * @author yy
	 *
	 */
	class PanelListenner extends MouseAdapter{
		public void mouseClicked(MouseEvent e) {
			//得到该位置对应的数组下标
			int j = e.getX()/eleWidth;
			int i = e.getY()/eleHeight;
			System.out.println(i+"<>"+j);
			//得到选择框中的图片
			ImageIcon icon = (ImageIcon)box.getSelectedItem();
			//得到该图片的编号,此处默认取名字的前三位数字   PS:这里也可以用其它的处理方式,楼主只是想复习一下string
			int num = str2int(icon.toString().substring(0, 3));
			//修改数组中的值
			if((int)boxtype.getSelectedItem()==1){
				map1[i][j] = num;
				icons1[i][j] = icon;
			}else if((int)boxtype.getSelectedItem()==2){
				map2[i][j] = num;
				icons2[i][j] = icon;
			}else if((int)boxtype.getSelectedItem()==3){
				map3[i][j] = num;
				icons3[i][j] = icon;
			}
			System.out.println((int)boxtype.getSelectedItem());
			
			panel.repaint();
		}
		
		/**
		 * 将一个三位的字符串,转为一个int
		 * @param numstr
		 * @return
		 */
		public int str2int(String numstr){
			for(int i=0;i<3;i++){
				if(numstr.charAt(i)!=0){
					numstr = numstr.substring(i);
					int num = Integer.parseInt(numstr);
					return num;
				}
			}
			numstr = numstr.substring(2);
			int num = Integer.parseInt(numstr);
			return num;
		}
		
	}
}

 3.程序启动如下

 

 这样就可以通过控制两个下拉列表选择素材的层,和素材的类型,然后通过鼠标点击面板中来该表相应数组中元素的值了,完了之后点击【创建】按钮来将编辑好的地图存入文件。

这只是一个初步的模版,以后要加入什么NPC或者是什么传送门,还是野怪之类的,就换不同的素材就行了,以后的地图就可以用这个模式来创建了,游戏的第一步地图的生成也算是基本上完成了...

写这么一篇没什么内容的博客比码几个小时的代码都累,o(︶︿︶)o 唉,对程序员来说表达能力是大问题啊

 

 

 

  • 大小: 76.6 KB
15
4
分享到:
评论
6 楼 kotoko 2017-01-30  
还有,想请问一下,我用自己的图片,事先已调成50*50,为什么画图时会报错呢?图片还有什么其他要求吗?弄得我还以为是PanelListenner的问题。
5 楼 kotoko 2017-01-30  
你的PanelListenner 没有实现吧
4 楼 Y_1746119035 2014-10-24  
单身旅行 写道
用FX吧,感觉比用swing强点儿。。。

目前只学了Swing,就顺便拿来当个复习了..
3 楼 Y_1746119035 2014-10-24  
Night舞夜 写道
不知道楼主想做个什么样的游戏。

就是那种像RPG Maker做出来的那种类型的吧...
2 楼 单身旅行 2014-10-24  
用FX吧,感觉比用swing强点儿。。。
1 楼 Night舞夜 2014-10-24  
不知道楼主想做个什么样的游戏。

相关推荐

Global site tag (gtag.js) - Google Analytics