前言:不好意思啊,昨天去柯桥了趟,基本没怎么碰电脑, 不过脑子里还是想这点这个地图编辑器的问题的,开始一直在想怎么解决外部文件读入导致换行符的混入,后来发现BufferedReader类的readLine方法,爽,直接过滤,省了我不少的麻烦,嘿嘿。还有就是我对地图文件做了稍稍的改动,头部加上了两个表示地图大小的标注,希望以后能用到。好,废话少说,看具体的吧~我截图都截好了那~ 都已经弄了这么晚了,看来又要明天凌晨才能发稿了……厄,这个,不是我臭屁,但是想来想去还是说一下,版权所有,如要转载清注明出处http://www.blog.net/Sozell 和作者:SosoAyaen。小弟我写点东西不容易,谢谢。
先说下关于上次做过的地图的载入问题。我是通过一个设置Layout布局来决定图片的布局规格的,而当要载入地图时来推算到底是几行几列的我觉得没有必要(不是说算法不能实现,而是为了这么两个int变量而去浪费时间换算行列,在速度和空间上得不偿失),所以我改了下地图文件的格式,在首两行加入行和列的值,这样程序拿到这个地图时,首先得到的就是地图的大小,而不是通过内容去把大小算出来(当然了,如果有兴趣的话不妨去写个算法出来,不难)。因为我们是通过maps这个char的数组来存储地图文件的,所以在写地图文件的时候有一个困扰:是就按照地图的2维方式存储呢还是以一维方式存储。个人觉得可能在性能上来说,一维存储快些,因为至少你可以一次readLine就能把所有内容读入,而二维多行存储势必要分行多次读取,众所周知,设备IO的速度相对于计算机其它的传输来说是最慢最耗时的,所以,这里也不妨是一个提高速度的地方(不要希嘘,我是要拿手机上去跑的,我手机主频又没有2.66GHZ)。不过这里既然是地图编辑器的话,自然可以在PC上跑,所以不故意一下也没什么大关系。考虑到现在只是用到了从外面把地图文件读进来,所以其实还只是做了一个地图显示的功能,所以大部份的地图还是在文本编辑器里面用手打出来的,所以这里用到二维就比较重要了,便于人看么不是。自然你也可以先用二维的画好后就再回过头把N行变为一行,不要想了,就是手动删除回车换行那;如果地图是5×5之类的还好,只要删除4次回车换行,要是地图大的话(当然地图不可能只有那么小,20×20起码的)那你就等着敲吧,当然,聪明的人会用上替换,哎,我是懒惰的人,大不了后面我再写个Method定义一维的读入好,我很懒的。既然是二维的话就要考虑到回车换行问题了。前面提到了readLine方法,它是属于BufferedReader类的(此类的其他方法参看JDK文档),它有个好处就是一行一行读,并且读进来后直接过滤回车换行符,这对于用于储存地图内容的字符串数组简直就是天大的福音啊!不用去自己过滤了!岂不爽歪歪(妈妈的,忘记了是什么儿童饮料名称,太恶心了!鄙视,也许是我太会YY了)!先给个地图样貌和文件的内容样式吧:
10 10 EEEEEEEEEE EGGGGGGGGE EGFGFGFGFE EEEEGGFGGE EEEEEFFGEE EEEEGGFEEE EEEGGGGGGE EEEEEEEEEE EEGGGGGGGE EEEEEEEEEE
开头就是宽和高的参数了。既然是专门用来读取地图文件的,所以我就直接给它做了个类:MapFileReader 。下面给出这个类的代码:
import
java.io.
*
;
public
class
MapFileReader
...
{ private BufferedReader buffReader; private int mapX, mapY; private String mapStr; /** */ /** * Method MapFileReader * * @param fileName */ public MapFileReader(String fileName) throws FileNotFoundException, IOException ... { // TODO: 在这添加你的代码 buffReader = new BufferedReader ( new FileReader(fileName) ); mapX = Integer.parseInt ( buffReader.readLine() ); mapY = Integer.parseInt ( buffReader.readLine() ); String str; StringBuffer strBuff = new StringBuffer(); while ((str = buffReader.readLine()) != null ) ... { strBuff.append(str); } mapStr = strBuff.toString(); } /** */ /** * Method close * close the BufferedReader * */ public void close() throws IOException ... { // TODO: 在这添加你的代码 buffReader.close(); } /** */ /** * Method getMapX * 得到地图的宽 * * * @return * */ public int getMapX() ... { // TODO: 在这添加你的代码 return this .mapX; } /** */ /** * Method getMapY * 得到地图的高 * * @return * */ public int getMapY() ... { // TODO: 在这添加你的代码 return this .mapY; } /** */ /** * Method getMapFileToString * * * @return * */ public String getMapFileToString() ... { // TODO: 在这添加你的代码 return this .mapStr; } /** */ /** * Method main * * * @param args * */ public static void main(String[] args) ... { // TODO: 在这添加你的代码 try ... { char [] buf; MapFileReader mfr = new MapFileReader( " ../mapFile/map1.txt " ); buf = mfr.getMapFileToString().toCharArray(); System.out.println (mfr.getMapFileToString()); System.out.println (buf); for ( int i = 0 ; i < 10 * 10 ; i ++ ) ... { System.out.printf( " %d " , LandStylePic.getIndex(buf[i])); } System.out.println(); } catch (FileNotFoundException e) ... { e.printStackTrace(); } catch (IOException e) ... { e.printStackTrace(); } } }
因为每个类我都单独做了测试,所以都有一个main(String[] args)主函数。这个不会变成方法带入类中,所以其他类中用到此类也不会有其中的代码执行。注意:FileReader 是现在用到的读入字符的类(具体自己看JDK,里面有详细说明),而它是没有readLine方法的,而BufferedReader 是带缓冲的Reader ,可以把FileReader 作为BufferedReder 构造的参数,就像套水管一样,套上BufferedReader 出来的就能用BufferedReader 的方法了。至于String 和StringBuffer 的区别不在本文讨论范围内,记住String 是不能改变而StringBuffer 是可变的就行了,为了不频繁申请内存资源,所以用StringBuffer 比较好。readLine读进来的是字符串(String ),开始的两行是要存到Int 变量中去的,所以要调用Inetger .parseInt(String)方法把String 转化为Int, 而Integer 是Int 的类表示方法(理解性说法),它有很多方法,而Int 之类的类型如Float 、Double 、char 不是类,所以他们声明的变量从严格的意义上来说不是对象,所以有了对应的wrap 类来提供对应的方法。
这个文件要加到前面的工程中去,或者放到前面那些程序的同文件夹下,然后再编译执行这个文件你就会看到一个比较有趣的画面,它对地图文件做了内部翻译,结果是内部索引号,说白了就是变成数字序列了。这是给“翻译图片”程序用的,呵呵。给个执行结果:
那么前面的MapsEditorFrame.java也要做相应的改动了。其实也就是把maps数组不手写,而直接把MapFileReader 的对象的getMapFileToSting()的地图内容字符串给它就行了,由于返回的是个String类型,而String本身就带一个toCharArray()的方法,所以两次调用就直接把地图内容给放到maps的char类型数组里面了,而其他程序几乎不需要大的改动。(改动还是有的,比如添加了个设置地图大小的方法setMapSize(int x, int y))
import
java.awt.
*
;
import
java.awt.event.
*
;
import
javax.swing.
*
;
import
java.util.
*
;
import
java.io.
*
;
/** */
/** * Sample application using JFrame. * * @author SosoAyaen * @version 1.00 06/08/10 */
public
class
MapsEditorFrame
extends
JFrame
implements
ActionListener
...
{ // 容器组件等 private JButton jbOK = null , jbCancel = null , jbIcon = null , jbSave = null , jbLoadMapFromFile = null ; private JPanel jpCenter = null , jpIcon = null , jpSouth = null , jpNorth = null , jpEast = null , jpEastCo = null ; private JLabel jlMap = null , jlTitle = null , jlTips = null ; private JMenu jmenu = null ; private JMenuItem jmiExit = null ; private JMenuBar jmb = null ; private JTextField jtf = null ; private int change = 1 ; // 控制点击同一按钮后控制不同控件 // 临时测试用的地图文件数组 private char [] maps; // 随机数 private Random rand = new Random(); private int WIDTH = 5 , HEIGHT = 5 ; private final String mapFilePath = " ../mapFile/ " ; // private Dimension d = null; /** */ /** * The constructor. */ public MapsEditorFrame (String title) ... { super (title); this .setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 载入地图文件 try ... { MapFileReader mfr = new MapFileReader (mapFilePath + " map1.txt " ); maps = mfr.getMapFileToString().toCharArray(); this .setMapSize (mfr.getMapX(), mfr.getMapY()); mfr.close(); } catch (FileNotFoundException e) ... { e.printStackTrace(); } catch (IOException e) ... { e.printStackTrace(); } // d = new Dimension(11, 20); // JMenu JMenu jmFile = new JMenu( " 文件 " ); // 临时定义组件 JMenuItem jmiLoad = new JMenuItem( " 载入地图 " ); jmiLoad.addActionListener( this ); jmFile.add(jmiLoad); jmiExit = new JMenuItem( " 退出 " ); jmiExit.addActionListener( this ); jmFile.add(jmiExit); JMenu jmEdit = new JMenu( " 编辑 " ); JMenuItem jmiUndo = new JMenuItem( " 撤销 " ); jmEdit.add(jmiUndo); // JMenuBar jmb = new JMenuBar(); jmb.add(jmFile); jmb.add(jmEdit); this .setJMenuBar(jmb); // JTextField jtf = new JTextField( 10 ); jtf.setEditable( false ); // JLabel // jlMap = new JLabel(mapsWater[0]); jlTitle = new JLabel( " SLG地图编辑器 " ); jlTips = new JLabel(); // JButton jbLoadMapFromFile = new JButton( " Load Maps " ); jbLoadMapFromFile.addActionListener( this ); jbSave = new JButton( " Save Maps " ); jbSave.addActionListener( this ); jbOK = new JButton( " OK " ); // jbOK.setMaximumSize(new Dimension(6, 12)); jbOK.addActionListener( this ); // jbOK.setSize(d); jbCancel = new JButton( " Cancel " ); jbCancel.setEnabled( false ); jbIcon = new JButton( " WaterMiddle " , LandStylePic.LANDSTYLES[LandStylePic.getIndex( " water_right " )]); // JPanel jpSouth = new JPanel( new FlowLayout()); jpSouth.add(jbOK); jpSouth.add(jbCancel); jpNorth = new JPanel( new FlowLayout()); jpNorth.add(jlTitle); jpEast = new JPanel( new GridLayout( 0 , 1 )); jpEastCo = new JPanel( new FlowLayout()); jpEastCo.add(jbIcon); jpEast.add(jpEastCo); jpEastCo = new JPanel( new FlowLayout()); jpEastCo.add(jbSave); jpEast.add(jpEastCo); jpEastCo = new JPanel( new FlowLayout()); jpEastCo.add(jbLoadMapFromFile); jpEast.add(jpEastCo); jpEastCo = new JPanel( new FlowLayout()); jpEastCo.add(jtf); jpEast.add(jpEastCo); jpEastCo = new JPanel( new FlowLayout()); jpEastCo.add(jlTips); jpEast.add(jpEastCo); jpIcon = new JPanel( new GridLayout(HEIGHT,WIDTH, 0 , 0 )); /**/ /* for(int i = 0, j = 0; i<HEIGHT*WIDTH; i++) { j = rand.nextInt(4); jlMap = new JLabel(LandStylePic.LANDSTYLES[j]); jpIcon.add(jlMap); } //*/ // 按数组内容添加地图图片 for ( int i = 0 ; i < HEIGHT * WIDTH; i ++ ) ... { jlMap = new JLabel( LandStylePic.LANDSTYLES[LandStylePic.getIndex(maps[i])] ); jpIcon.add(jlMap); } // 保证jpIcon内的JLabel不会因为外部窗口的拉伸而走样 jpCenter = new JPanel( new FlowLayout()); jpCenter.add(jpIcon); // JFrame this .setLayout( new BorderLayout()); this .pack(); this .setResizable( false ); this .add(BorderLayout.NORTH, jpNorth); this .add(BorderLayout.SOUTH, jpSouth); this .add(BorderLayout.CENTER, jpCenter); this .add(BorderLayout.EAST, jpEast); } /** */ /** * Method setMapSize * * * @param x * @param y * */ public void setMapSize ( int x, int y) ... { // TODO: 在这添加你的代码 this .WIDTH = x; this .HEIGHT = y; } /** */ /** * Method actionPerformed * * * @param e * */ public void actionPerformed(ActionEvent e) ... { // TODO: 在这添加你的代码 if (e.getActionCommand().equals( " OK " )) ... { System.exit( 0 ); } else if (e.getActionCommand().equals( " Save Maps " )) ... { change *= - 1 ; if (change > 0 ) ... { jtf.setText( "Code Test!! " ); jlTips.setText( "" ); } else ... { jlTips.setText( " Two pigs " ); jtf.setText( "" ); } } else if (e.getActionCommand().equals( " Load Maps " ) || e.getActionCommand().equals( " 载入地图 " )) ... { System.out.println( " Map loaded... " ); } else if (e.getActionCommand().equals( " 退出 " )) ... { System.exit( 0 ); } } }
当然,里面乱七八糟的控件还是一大堆,不久的将来偶就会亲自来个大扫除的说~嘿嘿。
关于里面的throws IOException啊,try/catch之类的我就不讲了,那个讲起来太多了,而且我自己也快被那个弄了晕头转向了,怕误人子弟,自己看去吧。不过话又说回来,异常这个东西还真好,这里没时间和精力去弄它,不过在不久的将来我一定会重新定义过异常类来适应我自己的这个地图编辑器的代码,大概初步定下来是开学搞吧,也就一个月不到么,嘿嘿。