今天开始做战斗,回合制战斗代码实现第三篇,特殊的回合制游戏Slg(策略战棋)
2015-08-16 08:16
661 查看
喜欢玩火焰纹章吗?【这个是我最喜欢的游戏】fc时期放假的时候,可以一次玩一天的游戏,梦幻模拟战,最早接触的电脑游戏《天使帝国》(我这个人比较奇怪,人家都是先玩红警,我最早接触的游戏除了486麻将,殖民计划,就是天使帝国了),加上光荣公司的3款开天辟地的slg大作,《三国英杰传》,《三国孔明传》,《三国曹操传》,还有台湾汉堂的几款游戏(炎龙骑士团,阿玛迪斯战记等等)加上后期的《风色幻想》,共同支撑起了当年Slg的鼎盛时期,不过在快节奏的今天,战棋游戏的滑落非常明显,虽然《火焰纹章》可以全球发售,在全球范围内都维护了大量粉丝,但最新版《觉醒》全球销量却并不是很尽如人意,为什么呢,并不是游戏的人气下落了,或者玩家少了,而是因为一场战斗花费太多的时间令玩家招架不住了,这个在单机游戏市场如此,在网络游戏市场就更是如此,战棋类网游吃螃蟹的日韩企业不是没有,早在03年就有《佣兵传说》这样的网游问世,国内也有盛大推出的《三国豪侠传》,但无一不是失败了,不过既然战棋有自己独特的魅力,又有固定稳定的玩家群体,那么只要想出解决时间开销问题的解决方法,相信赚钱也不是不可能,我们不讨论如何真把战棋搬到网络上。
我们今天只是聊聊战棋怎么做,当然因为市面上没有相关网游代码,单机代码也是很久以前的,所以大家凑合着看看就行了,等如果那一天战棋类网游真的火了,那么我们在加篇幅讨论。先看看这些曾经失败的作品
![](http://img.blog.csdn.net/20150813100015464?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150813100026882?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150813100037660?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
其实盛大的三国豪侠传做的还挺好玩的,但是说实话,战棋游戏因为一次战斗要耗费太多时间,所以真要让玩家在网络上玩,还真要考虑些新的玩法,佣兵传说就不说了,这个游戏做的有问题,无pvp和pve区分,混战,有时候野外杀个怪,最后没血了,有人强制加入你的战斗,把你杀了,结果什么保护都没有,佣兵要花钱去酒馆雇佣,佣兵死亡无法复活(就是个坑钱的玩应),所有战斗都会消耗佣兵,一天赚的钱只够买两个佣兵,最后玩过的人都说,要想在这个游戏生存下去,最主要的就是玩游戏不带一个佣兵(它倒我不奇怪,奇怪的是它在日韩居然比国服多支撑了好几年,真是奇迹,难为日韩的玩家了)说不说,还说了这么多。
我们下面讨论怎么做。我们先抛开通篇代码的枷锁看看SLG寻路,寻路一直是SLG战棋最难的一个部分,因为不同的地形所生成的步数不同,时时更新,需要相当全面的考虑,我们看下这个寻路算法
这个是j2me的启动app类,因为j2me不像正常java程序那样有public static void main(String[] args){}这个方法,需要在MIDlet的子类里面起一个绘图类的线程
继承Canvas和Runnable接口,这样这个类就有了画笔和run这个方法,通过run这个死循环,不停的对画布做更新,这个就是j2me的原理,上面的代码写的很简洁基本实现了站起游戏的功能,因为j2me这个项目在10年的时候就停止更新了,jdk需要1.5以下的版本支持,所以想要调试很麻烦(现在想找个老版本的安装真的是不容易),所以我这直接贴出代码,大家自己看看,寻找下思路如果想进一步了解战棋游戏的做法,那么我们往下看,下面我们会几种分析一个java的例子,因为这个不需要上面j2me环境的限制,所以我们那下面这个java例子来分析这个java例子的作者是cping1982大神,做过java小游戏的可能都对他的Lgame引擎都有个耳闻,这里我们看看他写的SLG小例子
![](http://img.blog.csdn.net/20150815175733337?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150815175804727?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150815175808337?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20150815175819576)
代码,惯例从启动开始
这个类中有一个方法,就是我上面说的public static void main(String[] args){},这个是我们程序要执行的,它里面定义了一个死循环,这个跟j2me很像了,因为Lgame可以j2ee和j2me之间相互移植,所以看上去一样也很正常,真佩服作者,这个类里面没有什么东西,我们接着看GameCanvas,这个是画布,我们需要的东西应该都在这
这个类里面有很多东西,我们从头开始看,
绘制screen,我们看下Utility类
寻路
可以说每个地方地很详细
期间用到的另外3个类
代码是贴完了,不过一个问题来了,战棋游戏因为玩法的独特性,所以貌似做成网游难度很大,现在放眼网游(手游)市场,类似产品只有《战龙兵团》勉强算,纯的战棋游戏
《三国鼎立》也是刚刚回归国服,归其原因还是因为玩法上面特殊,时间消耗太大,战龙兵团为了规避走格子消耗太多的时间,发明了战役挂机---这个想法不错《我叫Mt》外传也是战役挂机,不过游戏搞得已经不是战棋游戏了,看上去是一款顶视图的《刀塔传奇》,把2d的玩法加了一个z轴,变成了3d玩法而已,战龙兵团怎么还有个pvp模式,可以真正体验战棋的乐趣(虽然一场仗要打10几20个小时,不过随时退出游戏,随时加入游戏都不限制,可以根据自己时间安排休闲),日本去年12月份上线了一款纯战棋手游,国内火焰vs众筹失败,所以近期吃螃蟹的公司可能不会有,毕竟风险很大,不过风险与机遇是并存的,当年火焰纹章的策划案提出的时候,也是被压了2年时间,当时任天堂内部也是很多声音,怀疑这种游戏类型能否被玩家接受,但后来事实证明,火纹被全世界玩家所喜爱(可能说的有点绝对,但火纹的消费群绝不是掌机那小小的一群人),市场其实还是挺大的,或许不久的将来战棋类型网游真的能成功也说不定。
当然策略游戏也可以归为SLG游戏,不过这里不做讨论。
我们今天只是聊聊战棋怎么做,当然因为市面上没有相关网游代码,单机代码也是很久以前的,所以大家凑合着看看就行了,等如果那一天战棋类网游真的火了,那么我们在加篇幅讨论。先看看这些曾经失败的作品
其实盛大的三国豪侠传做的还挺好玩的,但是说实话,战棋游戏因为一次战斗要耗费太多时间,所以真要让玩家在网络上玩,还真要考虑些新的玩法,佣兵传说就不说了,这个游戏做的有问题,无pvp和pve区分,混战,有时候野外杀个怪,最后没血了,有人强制加入你的战斗,把你杀了,结果什么保护都没有,佣兵要花钱去酒馆雇佣,佣兵死亡无法复活(就是个坑钱的玩应),所有战斗都会消耗佣兵,一天赚的钱只够买两个佣兵,最后玩过的人都说,要想在这个游戏生存下去,最主要的就是玩游戏不带一个佣兵(它倒我不奇怪,奇怪的是它在日韩居然比国服多支撑了好几年,真是奇迹,难为日韩的玩家了)说不说,还说了这么多。
我们下面讨论怎么做。我们先抛开通篇代码的枷锁看看SLG寻路,寻路一直是SLG战棋最难的一个部分,因为不同的地形所生成的步数不同,时时更新,需要相当全面的考虑,我们看下这个寻路算法
SLG中搜索某个角色可移动区域的算法 可根据地形的不同,以及角色能力的不同来判断可移动区域。例如骑士在平地上可以移动更大的范围。代码如下: /** * 搜索可走区域 * @param map 当前地图表 * @param row 行 * @param col 列 * @param locomotivity 该角色的默认移动力 * @param direction 方向 */ public void scanMovableArea(byte map[][], int row, int col, int locomotivity, int direction){ if(locomotivity > map[row][col]) map[row][col] = (byte)locomotivity; else return; /** 向上判断 **/ if(direction != 1){ int loco1 = locomotivity - mapExpendLocomotivity(row, col - 1); if(loco1 >=0) scanMovableArea(map, row, col - 1, loco1, 2); } /** 向下判断 **/ if(direction != 2){ int loco2 = locomotivity - mapExpendLocomotivity(row, col + 1); if(loco2 >= 0) scanMovableArea(map, row, col + 1, loco2, 1); } /** 向左判断 **/ if(direction != 4){ int loco3 = locomotivity - mapExpendLocomotivity(row - 1, col); if(loco3 >= 0) scanMovableArea(map, row - 1, col, loco3, 8); } /** 向右判断 **/ if(direction != 8){ int loco4 = locomotivity - mapExpendLocomotivity(row + 1, col); if(loco4 >= 0) scanMovableArea(map, row + 1, col, loco4, 4); } } ---------------------------------------------- /** * 地形对移动力的消耗 * @param row 行 * @param col 列 * @return 移动力消耗值 */ public int mapExpendLocomotivity(int row, int col){ //这里我就不一一实现了,有兴趣的朋友可以自己扩展这个方法。 //下面给个伪代码 //如果是草地 if(gameMap[row][col] == GAME_MAP_GRASS){ //如果是士兵 if(type == SOLIDER){ return 1; } } //超出边界 if(row < 0 || col < 0 || row > gameWidth || col > gameHeight) { return 1000; } //具体的情况各位朋友可以根据自己的游戏来设计。 } 找到可以移动的区域后,就可以确定要移动的具体位置。这时候又要涉及到找路算法了。对于与A*算法(以前有一位同事写过)。不过下次我会用递归算法来实现,速度更快,更简单。 差点忘记说明了以上得到的map数组怎么使用。这时一个记录了剩余移动力的数组。在显示可移动的区域的时候只要判断map里面的值是否为空,不为空就画出一个矩形,代表该区域可走。 /** * 走路 * @param curX 当前位置 (x方向) * @param curY 当前位置 (y方向) * @param destX 目标位置(x方向) * @param destY 目标位置 (y方向) * @return 路径矢量 */ public Vector scanPath(int curX, int curY, int destX, int destY){ Vector vector = null; short dest[] = { (short)destX, (short)destY }; if(curX == destX && curY == destY){ vector = new Vector(); vector.addElement((Object)dest); return vector; } byte byte0 = 0; byte byte1 = 0; byte byte2 = 0; byte byte3 = 0; if(destY > 0) byte0 = _mapped_terrains[destX][destY - 1]; if(destY < _map_height - 1) byte1 = _mapped_terrains[destX][destY + 1]; if(destX > 0) byte2 = _mapped_terrains[destX - 1][destY]; if(destX < _map_width - 1) byte3 = _mapped_terrains[destX + 1][destY]; int max = Math.max(Math.max((int)byte0, (int)byte1), Math.max((int)byte2, (int)byte3)); if(max == byte0) vector = scanPath(curX, curY, destX, destY - 1); else if(max == byte1) vector = scanPath(curX, curY, destX, destY + 1); else if(max == byte2) vector = scanPath(curX, curY, destX - 1, destY); else if(max == byte3) vector = scanPath(curX, curY, destX + 1, destY); vector.addElement((Object)dest); return vector; } 还记得上个帖子上函数中传入的map参数吗,实际上通过那个函数就可以得到一个map,然后应用于现在的找路算法中,也就是上面代码段看到的_mapped_terrains 还有两个陌生的变量就是 _map_height和_map_width ,这个很简单了,就是SLG地图中的长度和宽度。 呵呵,希望这些代码段对SLG的朋友有些帮助很详细的讲解以及寻路设定,小伙伴完全可以根据这个来改动一下,当然,我们如果考虑通篇的SlG制作,那么我们看下面的j2me源码
import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import java.lang.Thread; public class MainMid extends MIDlet { MainPit myScreen; boolean first=true; public MainMid() { myScreen = new MainPit(this); } protected void destroyApp(boolean unconditional) { } protected void pauseApp() { } protected void startApp() { Display.getDisplay(this).setCurrent(myScreen); if(first) { try { Thread myThread = new Thread(myScreen); myThread.start(); } catch(Error e) { destroyApp(false); notifyDestroyed(); } first = false; } } //游戏结束 public void exit() { destroyApp(true); notifyDestroyed(); } }
这个是j2me的启动app类,因为j2me不像正常java程序那样有public static void main(String[] args){}这个方法,需要在MIDlet的子类里面起一个绘图类的线程
/*SLG战略实现 小图模式 1:光标移动OK 2:滚屏OK 3:人物动作OK 4:人物移动OK 5:移动范围限定OK 6:显示菜单OK 7:多人物模式OK 8:移动完成后的攻击判断,并且根据判断绘制菜单. 9:选择菜单攻击指令后,绘制攻击范围 10:选择攻击目标 11:攻击过程 12:带有地图限定的移动模式 13:其它限定移动 14:整理以方便移植,除去攻击血量显示外,其余已调整完成 ,适配其它机型调整参数即可 15:开始菜单,相关其它显示内容的接口,分离光标的参数调整与绘制 16:移动过程人物寻路 17:全局信息读入 18:加入人物参数及其相关参数导入 */ import javax.microedition.lcdui.Image; import java.lang.Math; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Graphics; import java.lang.Thread; import java.lang.Runnable; import java.io.InputStream; import javax.microedition.rms.*; import java.io.DataOutputStream; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; import java.io.DataInputStream; //import com.nokia.mid.ui.FullCanvas; //class MainPit extends FullCanvas implements Runnable class MainPit extends Canvas implements Runnable { MainMid myMid; private String mainMenuText[] = { "开始游戏", "继续游戏", "读取进度", "帮助信息", "结束游戏" }; //按键 final static byte UP = -1; final static byte DOWN = -2; final static byte LEFT = -3; final static byte RIGHT = -4; final static byte OK = -5; final static byte LCOMMAND = -6; final static byte RCOMMAND = -7; //状态 private int STATE = 1; //屏幕大小 private int SCREEN_WIDTH = 128; private int SCREEN_HEIGHT = 128; //瓷砖大小 private int TILE_WIDTH = 16; private int TILE_HEIGHT =16; private int TILE_SIZE = 16; //屏幕单元数目最大数 private int SCREEN_MAX_WIDTH = 7; private int SCREEN_MAX_HEIGHT = 7; //地图单元数目 private int MAP_MAX_WIDTH = 15; private int MAP_MAX_HEIGHT = 15; //职业相关参数 private byte vocation[][] = { {22,5,5,5,5,4,1},//人剑 {22,5,7,4,4,8,2},//人骑 {25,6,5,5,4,6,2},//蛮骑 {25,5,5,7,3,6,3},//蛮骑射 {20,6,2,8,4,7,3},//羽射 {20,6,6,4,4,3,1},//河洛 {28,7,7,3,3,5,1},//夸父 {20,7,2,6,5,3,1},//魅 {22,4,4,6,6,3,1}//术 }; //图片偏移系数 //人物图片偏移[人物类型][y偏移][x偏移] private byte actorpos[][] = { //女剑士1 //无焦点 {0,2}, {-1,1}, //有焦点 {0,1}, {2,-8}, //正面下移 {2,-1}, {2,-2}, //背面上移 {2,0}, {2,0}, //左移 {3,0}, {2,0}, //右移 {-5,0}, {-5,0}, //骑士 //无焦点 {1,-3}, {0,-6}, //有焦点 {-4,-6}, {0,-9}, //正面下移 {2,-7}, {2,-9}, //背面上移 {-1,-6}, {-1,-8}, //左移 {-2,-6}, {-2,-5}, //右移 {-5,-6}, {-7,-5} }; //人物动作图片位置 //[人物类型][动作类型] //人物类型0:主角1 //动作类型0:无焦点,1:有焦点,2:正面下移,3:背面上移,4:左移,5:右移 private byte actpic[][] = { {0,2,4,6,8,10}, {12,14,16,18,20,22} }; //红方信息 //0:类型,1:x坐标,2:y坐标,3:等级,4:五行属性,5:HP,6:ATK,7:DEF,8:DEX,9,AGI,10:MOV,11:攻击范围) private byte redinfo[][] = new byte[9][12]; //蓝方信息 //0:类型,1:x坐标,2:y坐标,3:等级,4:五行属性,5:HP,6:ATK,7:DEF,8:DEX,9,AGI,10:MOV,11:攻击范围) private byte blueinfo[][] = new byte[9][12]; private byte infored[][] = {//类型,坐标,等级,属性 {0,0,0,3,0}, {1,5,6,4,1}, {2,3,9,4,2}, {3,1,6,2,3}, {4,8,10,5,4}, {5,2,7,2,0}, {6,12,12,3,1}, {7,14,11,3,2}, {8,15,15,5,3} }; //出场人物信息数组(人物类型,人物地图坐标,人物移动能力,攻击范围最小值,攻击范围最大值) private int infoact[][] = { {0, 0, 0, 6, 0, 1}, {1, 6, 5, 4, 0, 1}, {1, 8,10, 4, 1, 3}, {0, 1, 1, 2, 1, 4}, {1, 2, 7, 5, 0, 2} }; //出场人物个数 private int actnum = 5; //出场人物处理编号 private int idact[] = {0,1,2,3,4}; //红方数量 private byte rednum; //蓝方数量 private byte bluenum; /*//蓝方编号 private byte redindex[]; //红方编号 private byte blueindex[]; */ //计数器 private int tally; //光标计数器 /**光标计数器*/ private int cursortally; //动作类型 //0:未得焦点 //1:得到焦点 //2:正面下移 //3:背面上移 //4:左面侧移 //5:右面侧移 //private byte motionkind[]={0,4,8,12,16,20}; //人物类型 //0:主角 //private byte actpickind[]={0,24}; //地图 /**地图*/ private byte map[][] ={ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,3,3,3,0,0,0,0}, {0,0,0,0,0,0,0,3,3,3,0,3,0,0,0,0}, {0,1,0,0,0,0,0,3,0,0,0,3,0,0,0,0}, {0,1,1,0,0,0,0,3,0,3,3,3,0,0,0,0}, {0,1,1,0,0,0,3,3,0,3,0,0,0,0,0,0}, {0,0,0,0,0,3,3,0,0,3,0,0,0,0,0,0}, {0,0,0,0,3,3,0,0,3,3,0,0,2,0,0,0}, {0,0,0,0,0,0,0,3,3,0,0,2,2,2,0,0}, {0,0,0,0,0,0,3,3,0,0,0,2,2,2,2,2}, {0,1,1,0,0,0,3,0,0,0,2,2,2,2,2,2}, {0,0,1,0,0,0,3,0,0,0,2,2,2,2,2,2}, {0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2}, {0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }; private String mapname[] = {"草","林","沙","山"}; //地图能力修正[防御,闪避][修正值] private byte maprevise[][] = { //草地,林地,沙地,建筑 {0,1,2,3},//防御 {0,20,10,30}//回避 }; //地图类型对人物移动能力的修正[地图类型][人物类型] private byte mappos[][] = { //剑士,骑士 {1,1},//草地 {1,2},//林地 {2,2},//沙地 {10,10} }; //移动能力 private byte move[][] = { {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }; //菜单内容 public String MenuContent[][] = { {"终了","中断","状况","部队"}, {"待机","攻击"} }; //菜单信息 public byte MenuInfo[] = {4, 1}; //当前菜单焦点 public int MenuFocus; private byte CurrentMenu;//当前菜单 private byte CurrentScene;//当前场景 private boolean atkrangeshow;//显示攻击范围 private byte atktarget[] = {0,0,0,0,0,0,0,0,0,0,0};//攻击目标 private byte currentatk;//当前攻击对象 //光标在地图中位置 private int cursorMX; private int cursorMY; //光标在屏幕中位置 private int cursorSX; private int cursorSY; //屏幕左上角瓷砖在地图中位置 private byte x; private byte y; //光标式样 private int cursorkind; //按键已按标记 private boolean hasPressed; //屏幕滚动标记 private boolean rollmapflag; //按键记忆 private int kCode; //延时 private int hangfire; //选中目标标记 private int currentact; /****************************************************************************/ //选中目标参数 //选中目标类型 private int currentactkind; //选中目标攻击范围下限 private int currentactatkmin; //选中目标攻击范围下限 private int currentactatkmax; //选中目标位置坐标 //屏幕中位置 private int currentactSX; private int currentactSY; //地图中位置 private int currentactMX; private int currentactMY; //选中目标状态 private int currentactstate; //选中目标动作标记 private int currentactcg; //选中目标移动偏移 private int currentactmovex; private int currentactmovey; //选中目标移动标记 private boolean moveaction; //移动对象坐标 private int targetSX; private int targetSY; //选中目标状态 private int targetstate; //选中目标移动范围 private int currentactmovearea; //移动范围显示标记 private boolean showmovearea; /********************************************************************************/ //文字框架颜色方案数组 private int frameColor[][] = { {0x00c8c8d0,0x00d8d8a8,0x00003088,0x000050b0},//开始菜单 {0x00605838,0x00605838,0x00f8f8c8,0x005858c0},//游戏菜单 {0x00605838,0x00f8f8c8},//地形修正 {0x00504830,0x00f8f0c8,0x00f87079,0x00f86800},//攻击血量显示蓝方 {0x00504830,0x00f8f0c8,0x00404090,0x0010b0f8},//攻击血量显示红方 {0x00d0d8f8,0x005858a8,0x00a0a0f8}//人物基本信息蓝方 }; /************************************/ //游戏相关 //游戏章节 private byte gameChapter; Image back_buffer;//缓存 Image static_buffer;//静态图形缓存 Image picmap[] = new Image[4];//地图 Image piccursor[] = new Image[4];//光标 Image picact[] = new Image[24];//人物 Graphics gb; Graphics gs; private RecordStore myStore = null; public MainPit(MainMid Mid) { gameChapter = 0; myMid = Mid; try { back_buffer = Image.createImage(SCREEN_WIDTH,SCREEN_HEIGHT); static_buffer = Image.createImage(SCREEN_WIDTH,SCREEN_HEIGHT); //图片载入, for(int i = 0; i < 24; i++) { if(i < 4) { piccursor[i] = Image.createImage("/pic/cursor/c" + i + ".png"); picact[i] = Image.createImage("/pic/act/m" + i + ".png"); picmap[i] = Image.createImage("/pic/map/m" + i + ".png"); } else { picact[i] = Image.createImage("/pic/act/m" + i + ".png"); } } //readStaticInfo(); } catch(Exception e) {} gb = back_buffer.getGraphics(); gs = static_buffer.getGraphics(); System.out.println("11111111111111"); //System.out.println("22222222222"); newGame(); //System.out.println("3333333333333"); } public void loadGameItem(byte chaper) { } public void newGame() { //菜单焦点 MenuFocus = 0; //计数器 tally = 0; cursortally = 0; CurrentScene = 1;//当前场景 //光标在地图中位置 cursorMX = 0; cursorMY = 0; //光标在屏幕中位置 cursorSX = 0; cursorSY = 0; //屏幕左上角瓷砖在地图中位置 x = 0; y = 0; //光标式样 tally = 0; //按键已按标记 hasPressed = false; //屏幕滚动标记 rollmapflag = false; //按键记忆 kCode = 0; //延时 hangfire = 0; //选中目标标记 currentact = -1; /****************************************************************************/ //选中目标参数 //选中目标位置坐标 //屏幕中位置 currentactSX = -1; currentactSY = -1; //地图中位置 currentactMX = -1; currentactMY = -1; //选中目标状态 currentactstate = 0; //选中目标动作标记 currentactcg = -1; //选中目标移动偏移 currentactmovex = 0; currentactmovey = 0; //选中目标移动标记 moveaction = false; //移动对象坐标 targetSX = -1; targetSY = -1; //选中目标状态 targetstate = 0; //选中目标移动范围 currentactmovearea = 0; //移动范围显示标记 showmovearea = false; //System.out.println("444444444444444"); //readChapterInfo(gameChapter); DrawStaticPic(gs); //System.out.println("end"); } public void paint(Graphics g) { g.drawImage(back_buffer,0,0,g.LEFT|g.TOP); } //主菜单 public void mainMenu() { gb.setColor(0,0,0); gb.fillRect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT); for(int i = 0; i < 5; i++) { drawMainMenu(gb, mainMenuText[i], (SCREEN_WIDTH - 72) / 2, ((SCREEN_HEIGHT - 22 * 5)/6 + 22)*i + (SCREEN_HEIGHT - 22 * 5)/6, 72, 22);//, 2, 6); } DealCursor(); } //绘制菜单(内容,菜单坐标,宽高,字体位置) /**绘制菜单(内容,菜单坐标,宽高,字体位置)*/ public void drawMainMenu(Graphics g, String s,int x,int y, int w, int h)//,int tx,int ty) { DrawFrame(g,x,y,w,h,4,frameColor,0); g.setColor(255,255,255); g.drawString(s,x+16,y+3,g.TOP|g.LEFT); } public void DealCursorMove() { if(hasPressed&&!moveaction) { switch(kCode) { case 2: if(cursorSY > 2)//静止背景时光标移动 { cursorSY--; cursorMY--; } else if(cursorSY > 0&&cursorMY > 2)//背景随光标移动 { cursorMY--; y--; RollScreen(gs,2); } else if(cursorMY > 0)//边界光标移动情况 { cursorMY--; cursorSY--; } break; case 8: if(cursorSY < SCREEN_MAX_HEIGHT - 2) { cursorSY++; cursorMY++; } else if(cursorMY < MAP_MAX_HEIGHT - 2&&cursorSY < SCREEN_MAX_HEIGHT) { cursorMY++; y++; RollScreen(gs,8); } else if(cursorMY < MAP_MAX_HEIGHT) { cursorSY++; cursorMY++; } break; case 4: if(cursorSX > 2) { cursorSX--; cursorMX--; } else if(cursorMX > 2&&cursorSX > 0) { x--; cursorMX--; RollScreen(gs,4); } else if(cursorMX > 0) { cursorSX--; cursorMX--; } break; case 6: if(cursorSX < SCREEN_MAX_WIDTH - 2) { cursorSX++; cursorMX++; } else if(cursorMX < MAP_MAX_WIDTH - 2&&cursorSX < SCREEN_MAX_WIDTH) { x++; cursorMX++; RollScreen(gs,6); } else if(cursorMX < MAP_MAX_WIDTH) { cursorSX++; cursorMX++; } break; } tally = 0; } } /***移动判定*/ public void DealPersonMove() { if(moveaction) { hasPressed = true; boolean endmove = true; if(endmove&&targetSY + y + 1 <= MAP_MAX_HEIGHT) { if(move[targetSY+y][targetSX+x] == move[targetSY+y+1][targetSX+x] + mappos[map[targetSY+y+1][targetSX+x]][currentactkind])//下走 { currentactstate = 2; currentactmovey++; if(currentactmovey % TILE_HEIGHT == 0) { targetSY++; } endmove = false; } } if(endmove&&targetSY+y-1 >= 0) { if(move[targetSY+y][targetSX+x] == move[targetSY+y-1][targetSX+x] + mappos[map[targetSY+y-1][targetSX+x]][currentactkind])//上走 { currentactstate = 3; currentactmovey--; if(currentactmovey % TILE_HEIGHT == 0) { targetSY--; } endmove = false; } } if(endmove&&targetSX+x+1 <= MAP_MAX_WIDTH) { if(move[targetSY+y][targetSX+x] == move[targetSY+y][targetSX+x+1] + mappos[map[targetSY+y][targetSX+x+1]][currentactkind])//右走 { currentactstate = 5; currentactmovex++; if(currentactmovex % TILE_WIDTH == 0) { targetSX++; } endmove = false; } } if(endmove&&targetSX+x-1 >= 0) { if(move[targetSY+y][targetSX+x] == move[targetSY+y][targetSX+x-1] + mappos[map[targetSY+y][targetSX+x-1]][currentactkind])//左走 { currentactstate = 4; currentactmovex--; if(currentactmovex % TILE_WIDTH == 0) { targetSX--; } endmove=false; } } if(endmove) { targetstate = 2; moveaction = false; hasPressed = false; CurrentScene = 2; CurrentMenu = 1; MenuFocus = 0; MenuInfo[1] = 1;//没有攻击目标 byte s = 1; //移动完成后的可攻击判断 for(int j = -currentactatkmax; j <= currentactatkmax; j++) { for(int i = targetSX - (currentactatkmax - Math.abs(j)); i <= targetSX + (currentactatkmax - Math.abs(j)); i++) { for(int m = 0; m < actnum; m++) { if(m == currentact) { continue; } if(infoact[idact[m]][1] - x == i&&infoact[idact[m]][2] - y == j + targetSY) { MenuInfo[1] = 2;//有攻击目标 currentatk = 1; atktarget[s] = (byte)m; s++; break; } } } } } } } public void playGame() { switch(CurrentScene) { case 0://章节显示,并载入相关信息 break; case 1://游戏大地图状态 //光标移动判断 DealCursorMove(); //游戏中屏幕坐标与地图坐标相关 currentactSX = currentactMX - x; currentactSY = currentactMY - y; //人物移动 DealPersonMove(); DrawBuffer(gb);//绘制静态缓存 DrawPerson(gb);//绘制人物 DealCursor();//绘制光标 DealMapRevise();//地形修正 //DealPersonInfo(); break; case 2://菜单1(待机,攻击) DrawBuffer(gb);//绘制静态缓存 DrawPerson(gb);//绘制人物 DrawMenu(gb,CurrentMenu); DealCursor(); break; case 3://攻击选定 DrawBuffer(gb);//绘制静态缓存 if(targetstate == 2)//攻击对象选定 { DrawRange(gb, targetSX, targetSY, currentactatkmin, currentactatkmax, 0x00ff0000); DrawPerson(gb);//绘制人物 DealCursor(); } else if(targetstate == 3)//攻击过程 { atkcg(gb); targetstate = 0; currentactstate = 0; CurrentScene = 1; } break; } } public void run() { while(true) { tally++; cursortally++; switch(STATE) { case 0://logo break; case 1://开始菜单 mainMenu(); break; case 2://游戏 playGame(); break; } //System.out.println("cursorMX="+cursorMX+" cursorSX="+cursorSX+" cursorMY="+cursorMY+" cursorSY="+cursorSY); //System.out.println("currentactSX="+currentactSX+" currentactSY="+currentactSY+" currentactMY="+currentactMY+" currentactMY="+currentactMY); repaint(); System.gc(); try { Thread.sleep(hangfire); } catch(Exception e) {} } } //绘制文字容器框(位置x,y,大小w,h,边框层数n,颜色c,框架类型k) public void DrawFrame(Graphics g, int x, int y, int w, int h, int n, int c[][],int k) { for(int i = 0; i < n;i++) { g.setColor(c[k][i]); g.fillRect(x + i, y+i, w - 2 * i, h - 2 * i); } } //绘制范围(g,目标位置,范围下限,范围上限颜色) public void DrawRange(Graphics g, int x, int y, int rmin, int rmax, int c) { gb.setColor(c); for(int i = 0; i <= rmax; i++) { //右下 gb.drawLine((x + i) * TILE_SIZE + TILE_SIZE, (y + (rmax - i)) * TILE_SIZE + TILE_SIZE, (x + i) * TILE_SIZE + TILE_SIZE, (y + (rmax - i)) * TILE_SIZE); gb.drawLine((x + i) * TILE_SIZE + TILE_SIZE, (y + (rmax - i)) * TILE_SIZE + TILE_SIZE, (x + i) * TILE_SIZE, (y + (rmax - i)) * TILE_SIZE + TILE_SIZE); //右上 gb.drawLine((x + i) * TILE_SIZE + TILE_SIZE, (y - (rmax - i)) * TILE_SIZE, (x + i) * TILE_SIZE, (y - (rmax - i)) * TILE_SIZE); gb.drawLine((x + i) * TILE_SIZE + TILE_SIZE, (y - (rmax - i)) * TILE_SIZE, (x + i) * TILE_SIZE + TILE_SIZE, (y - (rmax - i)) * TILE_SIZE + TILE_SIZE); //左下 gb.drawLine((x - i) * TILE_SIZE, (y + (rmax - i)) * TILE_SIZE + TILE_SIZE, (x - i) * TILE_SIZE, (y + (rmax - i)) * TILE_SIZE); gb.drawLine((x - i) * TILE_SIZE, (y + (rmax - i)) * TILE_SIZE + TILE_SIZE, (x - i) * TILE_SIZE + TILE_SIZE, (y + (rmax - i)) * TILE_SIZE + TILE_SIZE); //左上 gb.drawLine((x - i) * TILE_SIZE, (y - (rmax - i)) * TILE_SIZE, (x - i) * TILE_SIZE + TILE_SIZE, (y - (rmax - i)) * TILE_SIZE); gb.drawLine((x - i) * TILE_SIZE, (y - (rmax - i)) * TILE_SIZE, (x - i) * TILE_SIZE, (y - (rmax - i)) * TILE_SIZE + TILE_SIZE); if(i <= rmin)//绘制下限 { //右下 gb.drawLine((x - i) * TILE_SIZE, (y - (rmin - i)) * TILE_SIZE, (x - i) * TILE_SIZE + TILE_SIZE, (y - (rmin - i)) * TILE_SIZE); gb.drawLine((x - i) * TILE_SIZE, (y - (rmin - i)) * TILE_SIZE, (x - i) * TILE_SIZE, (y - (rmin - i)) * TILE_SIZE + TILE_SIZE); //右上 gb.drawLine((x - i) * TILE_SIZE, (y + (rmin - i)) * TILE_SIZE + TILE_SIZE, (x - i) * TILE_SIZE, (y + (rmin - i)) * TILE_SIZE); gb.drawLine((x - i) * TILE_SIZE, (y + (rmin - i)) * TILE_SIZE + TILE_SIZE, (x - i) * TILE_SIZE + TILE_SIZE, (y + (rmin - i)) * TILE_SIZE + TILE_SIZE); //左下 gb.drawLine((x + i) * TILE_SIZE + TILE_SIZE, (y - (rmin - i)) * TILE_SIZE, (x + i) * TILE_SIZE, (y - (rmin - i)) * TILE_SIZE); gb.drawLine((x + i) * TILE_SIZE + TILE_SIZE, (y - (rmin - i)) * TILE_SIZE, (x + i) * TILE_SIZE + TILE_SIZE, (y - (rmin - i)) * TILE_SIZE + TILE_SIZE); //左上 gb.drawLine((x + i) * TILE_SIZE + TILE_SIZE, (y + (rmin - i)) * TILE_SIZE + TILE_SIZE, (x + i) * TILE_SIZE + TILE_SIZE, (y + (rmin - i)) * TILE_SIZE); gb.drawLine((x + i) * TILE_SIZE + TILE_SIZE, (y + (rmin - i)) * TILE_SIZE + TILE_SIZE, (x + i) * TILE_SIZE, (y + (rmin - i)) * TILE_SIZE + TILE_SIZE); } } } //绘制攻击血槽 public void DrawLifeShow(Graphics g, int blue, int red) { int m; int d; int n; //System.out.println(" blue = " + blue + " red = "+red); if(infoact[idact[red]][2] - y < 4) { d = 80; } else { d = 0; } //攻击方 //血量显示 m = 16 - 3; n = d + 16; //框 DrawFrame(g,m,n,54,30,4,frameColor,4); //槽 g.setColor(232,144,0); g.drawRect(16 + m + 2, 1 + 8 + n + 4 + 3, 25, 6); g.setColor(112,48,0); g.fillRect(16 + m + 3, 2 + 8 + n + 4 + 3, 23, 4); //血 g.setColor(248, 248, 0); g.fillRect(16 + m + 4, 3 + 8 + n + 4 + 3, 18, 2); //人物名称显示 m = 24-3; n = d + 8; DrawFrame(g,m,n,38,22,4,frameColor,4); //反击方 m = 64+3; n = d + 16; DrawFrame(g,m,n,54,30,4,frameColor,3); //人物名称显示 m = 72+3; n = d + 8; DrawFrame(g,m,n,38,22,4,frameColor,3); } public void DrawMenu(Graphics g, int k)//绘制菜单,k:菜单类型 { int s = MenuInfo[k]; int m = SCREEN_WIDTH - 3 * TILE_SIZE; if(cursorSX >=4) { m = TILE_SIZE; } else { m = SCREEN_WIDTH - 3 *TILE_SIZE;; } DrawFrame(g, m, TILE_SIZE, 37, TILE_SIZE * s + 5,4,frameColor,1); g.setColor(255,255,255); for(int i = 0; i < s; i++) { g.drawString(MenuContent[k][s - i - 1], m + TILE_SIZE+3, 2+TILE_SIZE + TILE_SIZE * i, g.TOP|g.HCENTER); } } //人物基本信息 public void DealPersonInfo() { if(cursorSX > SCREEN_MAX_WIDTH / 2) { DrawPersonInfo(gb, 5, 5); } else { DrawPersonInfo(gb, SCREEN_WIDTH - 53, 5); } } public void DrawPersonInfo(Graphics g,int x,int y) { DrawFrame(gb,x,y,48,32,3,frameColor,5); } //地图修正信息处理 /**地图修正信息处理*/ public void DealMapRevise() { if(cursorSX > SCREEN_MAX_WIDTH / 2) { DrawMapRevise(gb, 5, SCREEN_HEIGHT - 41, map[cursorMY][cursorMX]); } else { DrawMapRevise(gb, SCREEN_WIDTH - 41, SCREEN_HEIGHT - 41, map[cursorMY][cursorMX]); } } public void DrawMapRevise(Graphics g,int x,int y, int mk) { DrawFrame(gb,x,y,36,36,2,frameColor,2); g.setColor(88,88,192); g.fillRect(x+2,y+2,32,16); g.setColor(255,255,255); g.drawString(mapname[mk],x+2+11,y+2,g.TOP|g.LEFT); g.setColor(0,0,0); g.drawString("DEF:" + maprevise[1][mk],x+2,y+2+16,g.TOP|g.LEFT); g.drawString("AVO:" + maprevise[0][mk],x+2,y+2+24,g.TOP|g.LEFT); } /**将静态缓存绘制到背景缓存中*/ public void DrawBuffer(Graphics g)//将静态缓存绘制到背景缓存中 { g.drawImage(static_buffer,0,0,g.LEFT|g.TOP); } //攻击动画 /***攻击动画*/ public void atkcg(Graphics g) { int c1 = 0; int c2 = 0; int picnum; for(int i = 0; i < 16;i++) { tally++; cursortally++; DrawBuffer(g);//绘制静态缓存 c1 = 0; c2 = 0; if(i/2 == 1||i/2 == 2) { c1 = 1; } if(i/2 == 5||i/2 == 6) { c2 = 1; } if(infoact[atktarget[currentatk]][1] > infoact[currentact][1]) { picnum = actpic[infoact[atktarget[currentatk]][0]][4] + (tally/10)%2; g.drawImage(picact[picnum], (infoact[atktarget[currentatk]][1] - x) * 16 - c1 + actorpos[picnum][0], (infoact[atktarget[currentatk]][2] - y) * 16 + actorpos[picnum][1], g.LEFT|g.TOP); picnum = actpic[infoact[currentact][0]][5] + (tally/10)%2; g.drawImage(picact[picnum], (infoact[currentact][1] - x) * 16 + c2 + actorpos[picnum][0], (infoact[currentact][2] - y) * 16 + actorpos[picnum][1], g.LEFT|g.TOP); } else if(infoact[atktarget[currentatk]][1] < infoact[currentact][1]) { picnum = actpic[infoact[atktarget[currentatk]][0]][5] + (tally/10)%2; g.drawImage(picact[picnum], (infoact[atktarget[currentatk]][1] - x) * 16 + c1 + actorpos[picnum][0], (infoact[atktarget[currentatk]][2] - y) * 16 + actorpos[picnum][1], g.LEFT|g.TOP); picnum = actpic[infoact[currentact][0]][4] + (tally/10)%2; g.drawImage(picact[picnum], (infoact[currentact][1] - x) * 16 - c2 + actorpos[picnum][0], (infoact[currentact][2] - y) * 16 + actorpos[picnum][1], g.LEFT|g.TOP); } else if(infoact[atktarget[currentatk]][2] > infoact[currentact][2]) { picnum = actpic[infoact[atktarget[currentatk]][0]][3] + (tally/10)%2; g.drawImage(picact[picnum], (infoact[atktarget[currentatk]][1] - x) * 16 + actorpos[picnum][0], (infoact[atktarget[currentatk]][2] - y) * 16 - c1 + actorpos[picnum][1], g.LEFT|g.TOP); picnum = actpic[infoact[currentact][0]][2] + (tally/10)%2; g.drawImage(picact[picnum], (infoact[currentact][1] - x) * 16 + actorpos[picnum][0], (infoact[currentact][2] - y) * 16 + c2 + actorpos[picnum][1], g.LEFT|g.TOP); } else { picnum = actpic[infoact[atktarget[currentatk]][0]][2] + (tally/10)%2; g.drawImage(picact[picnum], (infoact[atktarget[currentatk]][1] - x) * 16 + actorpos[picnum][0], (infoact[atktarget[currentatk]][2] - y) * 16 + c1 + actorpos[picnum][1], g.LEFT|g.TOP); picnum = actpic[infoact[currentact][0]][3] + (tally/10)%2; g.drawImage(picact[picnum], (infoact[currentact][1] - x) * 16 + actorpos[picnum][0], (infoact[currentact][2] - y) * 16 - c2 + actorpos[picnum][1], g.LEFT|g.TOP); } DrawPerson(g); DrawLifeShow(g, currentact, atktarget[currentatk]); repaint(); try { Thread.sleep(100); } catch(Exception e) {} } } public void DrawMoveRange(Graphics g,int c) { for(int j = 0;j<= MAP_MAX_HEIGHT;j++) { for(int i = 0; i<= MAP_MAX_WIDTH;i++) { if(i - x > SCREEN_MAX_WIDTH||i - x < 0||j - y > SCREEN_MAX_HEIGHT||j - y < 0) { continue; } if(move[j][i] > -1) { g.setColor(c); g.drawRect((i - x) * TILE_SIZE,(j - y) * TILE_SIZE,TILE_SIZE,TILE_SIZE); } } } } public void DrawPerson(Graphics g) { int picnum; for(int i = 0; i < actnum; i++)//绘制人物 { if(infoact[idact[i]][2] - y < 0||infoact[idact[i]][2] - y > 7||infoact[idact[i]][1] - x < 0||infoact[idact[i]][1] - x > 7||idact[idact[i]] == currentact)//屏幕显示外和获得焦点的人物不绘制 { continue; } if(targetstate == 3&&idact[idact[i]] == atktarget[currentatk]) { continue; } picnum = actpic[infoact[idact[i]][0]][0] + (tally/10)%2; g.drawImage(picact[picnum], (infoact[idact[i]][1] - x) * TILE_SIZE + actorpos[picnum][0], (infoact[idact[i]][2] - y) * TILE_SIZE + actorpos[picnum][1], g.LEFT|g.TOP); } if(targetstate != 3) { if(currentact >= 0)//有人获得焦点的情况下绘制 { if(showmovearea)//绘制选中人物移动范围 { DrawMoveRange(gb,0x000000ff); } //绘制人物 picnum = actpic[currentactkind][currentactstate] + (tally/10)%2; g.drawImage(picact[picnum], currentactSX * TILE_SIZE + actorpos[picnum][0] + currentactmovex, currentactSY * TILE_SIZE + actorpos[picnum][1] + currentactmovey, g.LEFT|g.TOP); } } } /***处理光标*/ public void DealCursor()//处理光标 { switch(STATE) { case 1: DrawCursor(gb,(SCREEN_WIDTH - 72) / 2, ((SCREEN_HEIGHT - 22 * 5)/6 + 22) * MenuFocus, 56, 6); break; case 2: switch(CurrentScene) { case 1://地图移动 for(int i = 0; i < actnum; i++) { if(targetstate == 0) { if(cursorSX == infoact[idact[i]][1] - x&&cursorSY == infoact[idact[i]][2] - y) { cursortally = 0; currentact = idact[i]; targetSX = cursorSX; targetSY = cursorSY; chooseact(currentact);//选中目标 DealPersonInfo(); break; } } if(targetstate == 0) { currentact = -1; } } if(!moveaction) { DrawCursor(gb,cursorSX * TILE_SIZE,cursorSY * TILE_SIZE,0,0); } break; case 2://菜单选择 if(cursorSX >=4) { DrawCursor(gb,16,TILE_SIZE + MenuFocus * TILE_SIZE,16,0); } else { DrawCursor(gb,80,TILE_SIZE + MenuFocus * TILE_SIZE,16,0); } break; case 3://攻击目标选择 DrawCursor(gb,(infoact[idact[atktarget[currentatk]]][1] - x) * TILE_SIZE,(infoact[idact[atktarget[currentatk]]][2] - y) * TILE_SIZE,0,0); break; } break; } } //绘制光标(光标位置,光标框的大小) public void DrawCursor(Graphics g, int x, int y, int w, int h) { g.drawImage(piccursor[0], x + 0 + (cursortally/30)%2, y + 0 + (cursortally/30)%2, g.LEFT|g.TOP); g.drawImage(piccursor[1], x + 10 - (cursortally/30)%2 + w, y + 0 + (cursortally/30)%2, g.LEFT|g.TOP); g.drawImage(piccursor[2], x + 0 + (cursortally/30)%2, y + 10 - (cursortally/30)%2 + h, g.LEFT|g.TOP); g.drawImage(piccursor[3], x + 10 - (cursortally/30)%2 + w, y + 10 - (cursortally/30)%2 + h, g.LEFT|g.TOP); } public void DrawStaticPic(Graphics g)//绘制静态图形 { DrawMap(g);//绘制显示地图 } public void DrawMap(Graphics g)//绘制地图 { for(int j = 0; j <= SCREEN_MAX_HEIGHT; j++) { for(int i = 0; i <= SCREEN_MAX_WIDTH; i++) { g.drawImage(picmap[map[y + j][x + i]], i * TILE_SIZE, j * TILE_SIZE, g.TOP|g.LEFT); } } } //滚屏 public void RollScreen(Graphics g, int dir) { switch(dir) { case 2: gb.drawImage(static_buffer, 0, TILE_SIZE, gb.TOP|gb.LEFT); g.drawImage(back_buffer, 0, 0, g.TOP|g.LEFT); for(int i = 0; i <= SCREEN_MAX_WIDTH; i++) { g.drawImage(picmap[map[cursorMY-2][x + i]], i * TILE_SIZE, 0, g.TOP|g.LEFT); } break; case 8: gb.drawImage(static_buffer, 0, -TILE_SIZE, gb.TOP|gb.LEFT); g.drawImage(back_buffer, 0, 0, g.TOP|g.LEFT); for(int i = 0; i <= SCREEN_MAX_WIDTH; i++) { g.drawImage(picmap[map[cursorMY+2][x + i]], i * TILE_SIZE, TILE_SIZE * SCREEN_MAX_HEIGHT, g.TOP|g.LEFT); } break; case 4: gb.drawImage(static_buffer, TILE_SIZE, 0, gb.TOP|gb.LEFT); g.drawImage(back_buffer, 0, 0, g.TOP|g.LEFT); for(int j = 0; j <= SCREEN_MAX_HEIGHT; j++) { g.drawImage(picmap[map[y + j][cursorMX-2]], 0, j * TILE_SIZE, g.TOP|g.LEFT); } break; case 6: gb.drawImage(static_buffer, -TILE_SIZE, 0, gb.TOP|g.LEFT); g.drawImage(back_buffer, 0, 0, g.TOP|g.LEFT); for(int j = 0; j <= SCREEN_MAX_HEIGHT; j++) { g.drawImage(picmap[map[y + j][cursorMX+2]], SCREEN_MAX_WIDTH * TILE_SIZE, j * TILE_SIZE, g.TOP|g.LEFT); } break; } } //移动能力判断 public boolean movejudge(int x,int y) { if(move[y][x] != -1) { return true; } return false; } public void chooseact(int act) { currentactkind = infoact[act][0]; currentactMX = infoact[act][1]; currentactMY = infoact[act][2]; currentactmovearea = infoact[act][3]; currentactatkmin = infoact[act][4]; currentactatkmax = infoact[act][5]; currentactSX = currentactMX - x; currentactSY = currentactMY - y; currentactmovex = 0; currentactmovey = 0; } //递规实现可移动范围的设定(地图限定数组,可移动数组(1为可以移动),当前人物位置,当前人物移动能力) void fmove(int mx,int my,int n) { if(mx < 0||my < 0||mx > SCREEN_WIDTH||my > SCREEN_HEIGHT) { return; } n = n - mappos[map[my][mx]][currentactkind]; for(int k = 0; k < actnum; k++)//对于有敌人的位置是不可移动的 { if(idact[k] == currentact) { continue; } if(infoact[idact[k]][2] == my&&infoact[idact[k]][1] == mx) { n = n - 100; break; } } if(n < 0) { // try{Thread.sleep(20); // } // catch(Exception e) // {} return; } else { if(move[my][mx] == -1) { move[my][mx] = (byte)n; } else if(move[my][mx] < n) { move[my][mx] = (byte)n; } if(mx+1 <= MAP_MAX_HEIGHT) { fmove(mx+1,my,n); } if(mx-1 >= 0) { fmove(mx-1,my,n); } if(my+1 <= MAP_MAX_WIDTH) { fmove(mx,my+1,n); } if(my-1 >= 0) { fmove(mx,my-1,n); } } } //寻路 void smove(int x,int y)//寻路算法 { if(y+1 <= MAP_MAX_HEIGHT) { if(move[y+1][x] == move[y][x] + mappos[map[y][x]][currentactkind]) { smove(x,y+1); } } if(y-1 >=0) { if(move[y-1][x] == move[y][x] + mappos[map[y][x]][currentactkind]) { smove(x,y-1); } } if(x+1 <= MAP_MAX_WIDTH) { if(move[y][x+1] == move[y][x] + mappos[map[y][x]][currentactkind]) { smove(x+1,y); } } if(x-1 >= 0) { if(move[y][x-1] == move[y][x] + mappos[map[y][x]][currentactkind]) { smove(x-1,y); } } move[y][x] = (byte)(move[y][x] + 10); } //初始化人物信息 public void initializeinfo() { for(int ih = 0; ih < rednum; ih++) { for(int iw = 5; iw < 12; iw++) { } } } public void keyPressed(int keyCode) { if(!hasPressed) { switch(keyCode) { case UP: keyAction(2); hasPressed = true; break; case DOWN: keyAction(8); hasPressed = true; break; case LEFT: keyAction(4); hasPressed = true; break; case RIGHT: keyAction(6); hasPressed = true; break; case OK: keyAction(5); hasPressed = true; break; case LCOMMAND: keyAction(5); hasPressed = true; break; case RCOMMAND: keyAction(3); hasPressed = true; break; } } } public void keyReleased(int keyCode) { hasPressed = false; hangfire = 0; if(targetstate == 0) { if(cursorSX == currentactSX&&cursorSY == currentactSY) { currentactstate = 1; } else { currentactstate = 0; } } } public void keyAction(int kC) { kCode = kC; switch(STATE) { case 0: break; case 1: switch(kC) { case 2: case 4: MenuFocus--; if(MenuFocus<0) { MenuFocus = 4; } break; case 8: case 6: MenuFocus++; if(MenuFocus>4) { MenuFocus = 0; } break; case 5: switch(MenuFocus) { case 0://开始新游戏 STATE = 2; newGame(); break; case 1: break; case 2: break; case 3: break; case 4: myMid.exit(); break; } break; } break; case 2: switch(CurrentScene) { case 1://光标移动状态 hangfire = 100; switch(kC) { case 5://按中键 switch(targetstate) { case 0://选择目标 if(currentactstate == 1)//目标获得焦点 { for(int i = 0; i<= MAP_MAX_HEIGHT; i++) { for(int j = 0; j <= MAP_MAX_WIDTH; j++) { move[i][j] = -1; } } fmove(currentactMX, currentactMY, currentactmovearea + mappos[map[currentactMY][currentactMX]][currentactkind]); currentactstate = 2; targetstate = 1; showmovearea = true; chooseact(currentact);//选中目标 } else if(currentactstate == 0) { CurrentMenu = 0; CurrentScene = 2; MenuFocus = 0; } break; case 1: if(movejudge(cursorMX,cursorMY)) { smove(cursorMX,cursorMY);//寻路 targetSX = currentactSX; targetSY = currentactSY; moveaction = true; showmovearea = false; } break; /* case 2: currentactSX = targetSX; currentactSY = targetSY; currentactMX = currentactSX + x; currentactMY = currentactSY + y; infoact[currentact][1] = currentactMX; infoact[currentact][2] = currentactMY; currentactmovex = 0; currentactmovey = 0; targetstate = 0; currentactstate = 0; break; */ } break; case 3: switch(targetstate) { case 1: currentactstate = 0; targetstate = 0; showmovearea = false; cursorSX = currentactSX; cursorSY = currentactSY; break; /*case 2: targetstate = 1; currentactmovex = 0; currentactmovey = 0; targetSX = currentactSX; targetSY = currentactSY; break;*/ } break; } break; case 2://菜单选择 switch(kC) { case 2://上键 MenuFocus--; if(MenuFocus < 0) { MenuFocus = MenuInfo[CurrentMenu] - 1; } break; case 8://下键 MenuFocus++; if(MenuFocus > MenuInfo[CurrentMenu] - 1) { MenuFocus = 0; } break; case 5://左软,中,键 switch(CurrentMenu) { case 0://系统菜单 switch(MenuFocus) { case 2://中断 MenuFocus = 0; STATE = 1; break; } break; case 1://攻击选择菜单 if(MenuFocus == MenuInfo[CurrentMenu] - 1)//待机 { CurrentScene = 1; currentactSX = targetSX; currentactSY = targetSY; currentactMX = currentactSX + x; currentactMY = currentactSY + y; infoact[currentact][1] = currentactMX; infoact[currentact][2] = currentactMY; currentactmovex = 0; currentactmovey = 0; targetstate = 0; currentactstate = 0; } else if(MenuFocus == MenuInfo[CurrentMenu] - 2)//攻击 { CurrentScene = 3; currentactSX = targetSX; currentactSY = targetSY; currentactMX = currentactSX + x; currentactMY = currentactSY + y; infoact[currentact][1] = currentactMX; infoact[currentact][2] = currentactMY; currentactmovex = 0; currentactmovey = 0; } break; } break; case 3://右软键 switch(CurrentMenu) { case 0: CurrentScene = 1; break; case 1: CurrentScene = 1; targetstate = 1; showmovearea = true; currentactmovex = 0; currentactmovey = 0; targetSX = currentactSX; targetSY = currentactSY; cursorSX = currentactSX; cursorSY = currentactSY; break; } break; } break; case 3://攻击模式 switch(kC) { case 2: case 4: currentatk--; if(currentatk == 0) { currentatk = atktarget[0]; } break; case 8: case 6: currentatk++; if(currentatk > atktarget[0]) { currentatk = 1; } break; case 5: switch(targetstate) { case 1: targetstate = 2; break; case 2: targetstate = 3; break; } break; case 3: CurrentScene = 2; targetstate = 1; break; } System.out.println(" " + currentatk + " " + atktarget[currentatk]); break; } break; } } /* //小图在图片中的坐标(ix,iy) //绘制在屏幕上的坐标(sx,xy) public void paintImage(Graphics g,Image pic, int ix, int iy, int width, int height,int sx, int sy) { g.setClip(sx,sy,width,height); g.drawImage(pic, sx - ix, sy - iy, g.LEFT|g.TOP); g.setClip(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); } */ /* //读取静态信息 private void readStaticInfo() { java.io.InputStream is = null; try { is = getClass().getResourceAsStream("/info/staticinfo.txt"); if (is != null) { readstatic(is); is.close(); } else { System.out.println("load static wrong"); } } catch (Exception e) { System.out.println("static "); } } //加载静态信息 public void readstatic(InputStream is) { try { int c; int actpicnum;//人物图片类型数目 int mappicnum;//地图图片类型数目 int vocationnum;//职业数目 //职业属性 //System.out.println("vocation"); c = is.read(); vocationnum = c; vocation = new byte[vocationnum][6]; for(int ih = 0; ih < vocationnum; ih++) { for(int iw = 0; iw < 6; iw++) { c = is.read(); vocation[ih][iw] = (byte)c; } } //System.out.println("0"); //图片偏移 c = is.read(); actpicnum = c; actorpos = new byte[actpicnum * 12][2]; for(int ih = 0; ih < actpicnum * 12; ih++) { for(int iw = 0; iw < 2; iw++) { c = is.read(); if(c >= 128) { c = 128 - c; } actorpos[ih][iw] = (byte)c; } } //System.out.println("1"); //图片位差 actpic = new byte[2][6]; for(int ih = 0; ih < 2; ih++) { for(int iw = 0; iw < 6; iw++) { c = is.read(); actpic[ih][iw] = (byte)c; //System.out.print(" "+c); } //System.out.println(""); } //System.out.println("2"); //地形修正 c = is.read(); mappicnum = c; maprevise = new byte[2][mappicnum]; for(int ih = 0; ih < 2; ih++) { for(int iw = 0; iw < mappicnum; iw++) { c = is.read(); maprevise[ih][iw] = (byte)c; //System.out.print(" "+c); } //System.out.println(""); } //System.out.println("3"); //地形移动力修正 mappos = new byte [mappicnum][actpicnum]; for(int ih = 0; ih < mappicnum; ih++) { for(int iw = 0; iw < actpicnum; iw++) { c = is.read(); mappos[ih][iw] = (byte)c; //System.out.print(" "+c); } //System.out.println(""); } //System.out.println("4"); c = is.read(); bluenum = (byte)c; //初始蓝方职业,等级,五行属性, for(int ih = 0; ih < bluenum; ih++) { c = is.read(); blueinfo[ih][0] = (byte)c;//职业 c = is.read(); blueinfo[ih][3] = (byte)c;//等级 c = is.read(); blueinfo[ih][4] = (byte)c;//五行属性 } } catch(Exception e) { System.out.println(e+"读取静态信息失败"); } } //按章节读入动态信息 private void readChapterInfo(byte chapter) { java.io.InputStream is = null; try { is = getClass().getResourceAsStream("/info/Chapter"+gameChapter+".txt"); if (is != null) { readchapter(is,chapter); is.close(); } else { System.out.println("load Chapter wrong"); } } catch (Exception e) { System.out.println("Chapter "); } } //加载动态信息 public void readchapter(InputStream is,byte chapter) { try { //System.out.println("6666666666"); int c; c = is.read(); MAP_MAX_WIDTH = c - 1;//地图宽 //System.out.println("MAP_MAX_WIDTH =" + MAP_MAX_WIDTH); c = is.read(); MAP_MAX_HEIGHT = c - 1;//地图高 //System.out.println("MAP_MAX_HEIGHT =" + MAP_MAX_HEIGHT); map = new byte[MAP_MAX_HEIGHT+1][MAP_MAX_WIDTH+1]; //System.out.println("9"); for(int ih = 0; ih <= MAP_MAX_HEIGHT; ih++) { for(int iw = 0; iw <= MAP_MAX_WIDTH; iw++) { c = is.read(); map[ih][iw] = (byte)c;//地图信息 //System.out.print(" "+map[ih][iw]); } //System.out.println(""); } c = is.read(); rednum = (byte)c;//红方数量 //System.out.println("rednum = "+rednum); redinfo = new byte[rednum][12]; for(int ih = 0; ih < rednum; ih++)//红方初始信息(类型,坐标,等级,属性) { for(int iw = 0; iw < 5; iw++) { c = is.read(); redinfo[ih][iw] = (byte)c;//人物信息 //System.out.print(""+redinfo[ih][iw]); } //System.out.println(); } //System.out.println("888888888888"); //蓝方初始信息(角色编号,坐标) for(int ih = 0; ih < bluenum; ih++) { for(int iw = 1; iw < 3; iw++) { c = is.read(); blueinfo[ih][iw] = (byte)c; } } } catch(Exception e) { System.out.println(""); } } //读取存盘记录 private void readStore(int index) { try { ByteArrayInputStream bais; DataInputStream dis; byte data[]; myStore = RecordStore.openRecordStore("save"+Integer.toString(index),true); try { data = myStore.getRecord(2); bais = new ByteArrayInputStream(data); dis = new DataInputStream(bais); // m[1] = dis.readInt(); dis.close(); } catch (Exception ioe) { System.out.println(ioe + "111111"); } myStore.closeRecordStore(); } catch (RecordStoreException rse) { System.out.println(rse + "22222"); } } //写入存盘记录 private void writeStore(int index) { try { ByteArrayOutputStream baos; DataOutputStream das; byte data[]; myStore = RecordStore.openRecordStore("save"+Integer.toString(index),true); try { baos = new ByteArrayOutputStream(); das = new DataOutputStream(baos); das.writeLong(System.currentTimeMillis()); // das.writeInt(s[1]); data = baos.toByteArray(); das.close(); } catch (Exception ioe) { throw new RecordStoreException(); } if (myStore.getNumRecords() == 0) { myStore.addRecord(data,0,8); myStore.addRecord(data,8,12); } else { myStore.setRecord(1,data,0,8); myStore.setRecord(2,data,8,12); } myStore.closeRecordStore(); } catch (RecordStoreException rse) { //System.out.println(rse + "333633"); } }*/ }
继承Canvas和Runnable接口,这样这个类就有了画笔和run这个方法,通过run这个死循环,不停的对画布做更新,这个就是j2me的原理,上面的代码写的很简洁基本实现了站起游戏的功能,因为j2me这个项目在10年的时候就停止更新了,jdk需要1.5以下的版本支持,所以想要调试很麻烦(现在想找个老版本的安装真的是不容易),所以我这直接贴出代码,大家自己看看,寻找下思路如果想进一步了解战棋游戏的做法,那么我们往下看,下面我们会几种分析一个java的例子,因为这个不需要上面j2me环境的限制,所以我们那下面这个java例子来分析这个java例子的作者是cping1982大神,做过java小游戏的可能都对他的Lgame引擎都有个耳闻,这里我们看看他写的SLG小例子
代码,惯例从启动开始
package org.loon.simple.slg.ai; import java.applet.Applet; import java.awt.Color; import java.awt.Frame; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; /** * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:ceponline@yahoo.com.cn * @version 0.1 */ public class Main extends Applet { /** * */ private static final long serialVersionUID = 1L; public void init() { this.setBackground(Color.black); this.add(new GameCanvas()); } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { Frame frame = new Frame(); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.add(new GameCanvas()); frame.pack(); frame.setResizable(false); frame.setTitle("Java战棋类游戏AI及寻径处理入门示例"); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } }
这个类中有一个方法,就是我上面说的public static void main(String[] args){},这个是我们程序要执行的,它里面定义了一个死循环,这个跟j2me很像了,因为Lgame可以j2ee和j2me之间相互移植,所以看上去一样也很正常,真佩服作者,这个类里面没有什么东西,我们接着看GameCanvas,这个是画布,我们需要的东西应该都在这
package org.loon.simple.slg.ai; import java.awt.Canvas; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Random; /** * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:ceponline@yahoo.com.cn * @version 0.1 */ public class GameCanvas extends Canvas implements Runnable, KeyListener { /** * */ private static final long serialVersionUID = 1L; // 地图 private Map map = null; // 菜单 private Menu menu = null; // 背景窗体 private Image screen; // 地图图片 private Image mapImage; private Graphics2D graphics; private String state; private int lastX; private int lastY; private int curX; private int curY; private int turn = 1; private int actionUnit = -1; private int moveCount = 0; private int[][] moveList; private int[][] movingList; private int[][] attackList; private int maxX; private int maxY; private List unitList = Collections.synchronizedList(new ArrayList(10)); // 战斗个体图 private Image[] unitImages = Utility.getSplitImages("image/unit.png", tile, tile); private Image[] iconImages = Utility.getSplitImages("image/icon.png", tile, tile); private Image[] listImages = Utility.getSplitImages("image/list.png", tile, tile); private Thread gameLoop; private int eventCode = -1; final static int tile = 32; public GameCanvas() { actionUnit = -1; state = "战斗开始"; turn = 1; this.setBackground(Color.BLACK); this.map = new Map("map.txt", tile); // 地图 this.mapImage = this.map.getMapImage(); this.maxX = map.getMaxX(); this.maxY = map.getMaxY(); this.moveList = new int[maxX][maxY]; this.movingList = new int[maxX][maxY]; this.attackList = new int[maxX][maxY]; int width = maxX * tile; int height = maxY * tile; // 菜单 this.menu = new Menu(maxX - 1); // 创建角色:name=空罐少女,team=0(我军),imageindex=3,x=7,y=1,以下雷同 createRole("空罐少女", 0, 0, 3, 7, 1); createRole("猫猫1", 0, 1, 6, 1, 2); createRole("猫猫2", 0, 0, 3, 2, 6); // 创建角色:name=躲猫兵团1,team=1(敌军),imageindex=6,x=4,y=5,以下雷同 createRole("躲猫兵团1", 1, 2, 4, 4, 5); createRole("躲猫兵团2", 1, 2, 4, 8, 5); createRole("躲猫兵团3", 1, 2, 4, 5, 7); createRole("躲猫兵团4", 1, 2, 4, 7, 2); this.screen = Utility.createImage(width, height, true); this.graphics = (Graphics2D) screen.getGraphics(); // 初始化 this.initRange(); // 绘制图像 this.drawBattle(); this.setPreferredSize(new Dimension(width - 2, height - 2)); this.setFocusable(true); this.addKeyListener(this); // 开始构建游戏 this.mainLoop(); } public void mainLoop() { gameLoop = new Thread(this); gameLoop.start(); } public void run() { for (;;) { long start = System.currentTimeMillis(); long end = System.currentTimeMillis(); long time = end - start; long sleepTime = 20L - time; if (sleepTime < 0L) { sleepTime = 0L; } this.eventClick(); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { } } } /** * 事件触发 * */ public synchronized void eventClick() { switch (eventCode) { // 按下Enter,开始触发游戏事件 case KeyEvent.VK_ENTER: int index = 0; // 当游戏状态为[状态显示]下 if (state.equalsIgnoreCase("状态显示")) { // 光标指向我方未行动角色 index = getRoleIdx(0, curX, curY); if ((index > -1) && (getRole(index).action == 0)) { state = "角色移动"; actionUnit = getRoleIdx(0, curX, curY); // 绘制移动范围 setMoveRange(); movingList[curX][curY] = moveCount; drawBattle(); // 光标指向敌方未行动角色 } else if (getRoleIdx(1, curX, curY) > -1) { state = "移动范围"; actionUnit = getRoleIdx(1, curX, curY); setMoveRange(); drawBattle(); // 查看角色情报 } else { state = "情报查看"; openMenu(0); drawBattle(); } } // 选择移动 else if (state.equalsIgnoreCase("角色移动")) { // 无法移动的区域 if (moveList[curX][curY] < 0) { return; } // 监测移动地点 if ((getRoleIdx(0, curX, curY) == -1) || (moveList[curX][curY] == 0)) { lastX = getRole(actionUnit).x; lastY = getRole(actionUnit).y; moveRole(); state = "行动菜单"; // 绘制攻击范围 setAttackRange(true); // 判定菜单项 if (isAttackCheck()) { openMenu(2); } else { openMenu(1); } drawBattle(); } } // 当角色移动后 else if (state.equalsIgnoreCase("行动菜单")) { if (menu.getMenuItem(menu.cur).equalsIgnoreCase("攻击")) { state = "进行攻击"; closeMenu(); drawBattle(); } else if (menu.getMenuItem(menu.cur).equalsIgnoreCase("待机")) { state = "状态显示"; closeMenu(); getRole(actionUnit).action = 1; actionUnit = -1; initRange(); drawBattle(); } } // 攻击时 else if (state.equalsIgnoreCase("进行攻击")) { // 无法攻击 if (attackList[curX][curY] < 2) { return; } // 当指定地点敌方存在时 if ((index = getRoleIdx(1, curX, curY)) > -1) { // 删除List中敌方角色(此处可设定减血规范) unitList.remove(index); state = "状态显示"; // 改变行动状态 getRole(actionUnit).action = 1; actionUnit = -1; initRange(); drawBattle(); } } // 查看角色移动范围 else if (state.equalsIgnoreCase("移动范围")) { state = "状态显示"; Role role = getRole(actionUnit); curX = role.x; curY = role.y; actionUnit = -1; initRange(); drawBattle(); } // 查看角色情报 else if (state.equalsIgnoreCase("情报查看")) { // 本回合战斗结束 if (menu.getMenuItem(menu.cur).equalsIgnoreCase("结束")) { closeMenu(); curX = 0; curY = 0; setBeforeAction(); state = "战斗结束"; drawBattle(); } } // 我军开始行动 else if (state.equalsIgnoreCase("战斗开始")) { state = "状态显示"; drawBattle(); } // 敌军开始行动 else if (state.equalsIgnoreCase("战斗结束")) { state = "敌方行动"; enemyAction(); setBeforeAction(); turn = turn + 1; state = "战斗开始"; drawBattle(); } break; // 按下ESC,取消已做选择 case KeyEvent.VK_ESCAPE: if (state.equalsIgnoreCase("角色移动")) // 移动 { state = "状态显示"; Role role = (Role) unitList.get(actionUnit); curX = role.x; curY = role.y; actionUnit = -1; initRange(); drawBattle(); } else if (state.equalsIgnoreCase("行动菜单")) // 移动后 { state = "角色移动"; closeMenu(); setAttackRange(false); // 不显示攻击范围 Role role = (Role) unitList.get(actionUnit); role.x = lastX; role.y = lastY; drawBattle(); } else if (state.equalsIgnoreCase("进行攻击")) // 攻击状态 { state = "行动菜单"; Role role = (Role) unitList.get(actionUnit); curX = role.x; curY = role.y; openMenu(menu.menuType); drawBattle(); } else if (state.equalsIgnoreCase("移动范围")) { // 移动范围 state = "状态显示"; Role role = (Role) unitList.get(actionUnit); curX = role.x; curY = role.y; actionUnit = -1; initRange(); drawBattle(); } else if (state.equalsIgnoreCase("情报查看")) // 角色情报 { state = "状态显示"; closeMenu(); drawBattle(); } else if (state.equalsIgnoreCase("战斗开始")) // 我军行动 { state = "状态显示"; drawBattle(); } else if (state.equalsIgnoreCase("战斗结束")) // 敌军行动 { state = "敌方行动"; enemyAction(); setBeforeAction(); turn = turn + 1; state = "战斗开始"; drawBattle(); } break; } if (eventCode > -1) { eventCode = -1; } } /** * 初始化各项范围参数 * */ public synchronized void initRange() { for (int y = 0; y <= maxY - 1; y++) { for (int x = 0; x <= maxX - 1; x++) { moveCount = 0; moveList[x][y] = -1; movingList[x][y] = -1; attackList[x][y] = 0; } } } /** * 获得移动到指定地点所需步数 * * @param x * @param y * @return */ public synchronized int getMoveCount(int x, int y) { if ((x < 0) || (x > maxX - 1) || (y < 0) || (y > maxY - 1)) { // 无法移动返回-1 return -1; } return moveList[x][y]; } /** * 设定移动步数 * * @param x * @param y * @param count */ public synchronized void setMoveCount(int x, int y, int count) { Role role = getRole(actionUnit); // 当为我军时 if (role.team == 0) { if (getRoleIdx(1, x, y) > -1) { return; } } else { if (getRoleIdx(0, x, y) > -1) { return; } } int cost = map.getMapCost(x, y); // 指定位置无法进入 if (cost < 0) { return; } count = count + cost; // 移动步数超过移动能力 if (count > role.move) { return; } // 获得移动所需步数 if ((moveList[x][y] == -1) || (count < moveList[x][y])) { moveList[x][y] = count; } } /** * 设定攻击范围 * * @param isAttack */ public synchronized void setAttackRange(final boolean isAttack) { try { int x, y, point; if (isAttack == true) { point = 2; } else { point = 1; } Role role = getRole(actionUnit); x = role.x; y = role.y; // 判定攻击点 if (x > 0) { attackList[x - 1][y] = point; } if (y > 0) { attackList[x][y - 1] = point; } if (x < maxX - 1) { attackList[x + 1][y] = point; } if (y < maxY - 1) { attackList[x][y + 1] = point; } } catch (Exception e) { } } /** * 判断是否能做出攻击 * * @return */ public synchronized boolean isAttackCheck() { for (int i = 0; i < unitList.size(); i++) { Role role = getRole(i); if (role.team != 1) { continue; } if (attackList[role.x][role.y] == 2) { return true; } } return false; } /** * 设定菜单 * * @param menuType */ public synchronized void openMenu(int menuType) { menu.visible = true; menu.setMenuType(menuType); menu.cur = 0; } /** * 关闭菜单 * */ public synchronized void closeMenu() { menu.visible = false; } /** * 设定所有角色参与行动 * */ public synchronized void setBeforeAction() { for (Iterator it = unitList.iterator(); it.hasNext();) { Role role = (Role) it.next(); role.setAction(0); } } /** * 返回指定索引下角色 * * @param index * @return */ public synchronized Role getRole(final int index) { if (unitList != null && index > -1) { return (Role) unitList.get(index); } return null; } /** * 设定移动路线 * */ public synchronized void setMoveCourse() { if (moveList[curX][curY] == -1) { return; } if (movingList[curX][curY] == moveCount) { return; } // 选择可行的最短路径 if ((movingList[redressX(curX - 1)][curY] != moveCount) && (movingList[curX][redressY(curY - 1)] != moveCount) && (movingList[redressX(curX + 1)][curY] != moveCount) && (movingList[curX][redressY(curY + 1)] != moveCount) || (moveCount + map.getMapCost(curX, curY) > getRole(actionUnit).move)) { for (int j = 0; j <= maxY - 1; j++) { for (int i = 0; i <= maxX - 1; i++) { movingList[i][j] = -1; } } int x = curX; int y = curY; moveCount = moveList[curX][curY]; movingList[x][y] = moveCount; // 获得移动路径 for (int i = moveCount; i > 0; i--) { switch (setMoveCouse(x, y)) { case 0: x = x - 1; break; case 1: y = y - 1; break; case 2: x = x + 1; break; case 3: y = y + 1; break; case 4: break; } } moveCount = moveList[curX][curY]; movingList[x][y] = 0; return; } // 获得矫正的移动步数 moveCount = moveCount + map.getMapCost(curX, curY); if (movingList[curX][curY] > -1) { moveCount = movingList[curX][curY]; for (int j = 0; j <= maxY - 1; j++) { for (int i = 0; i <= maxX - 1; i++) { if (movingList[i][j] > movingList[curX][curY]) { movingList[i][j] = -1; } } } } movingList[curX][curY] = moveCount; } /** * 设定最短移动路径 * * @param x * @param y * @return */ public synchronized int setMoveCouse(int x, int y) { // 判定左方最短路径 if ((x > 0) && (moveList[x - 1][y] > -1) && (moveList[x - 1][y] < moveList[x][y]) && (moveList[x - 1][y] == moveCount - map.getMapCost(x, y))) { moveCount = moveCount - map.getMapCost(x, y); movingList[x - 1][y] = moveCount; return 0; } // 判定上方最短路径 if ((y > 0) && (moveList[x][y - 1] > -1) && (moveList[x][y - 1] < moveList[x][y]) && (moveList[x][y - 1] == moveCount - map.getMapCost(x, y))) { moveCount = moveCount - map.getMapCost(x, y); movingList[x][y - 1] = moveCount; return 1; } // 判定右方最短路径 if ((x < maxX - 1) && (moveList[x + 1][y] > -1) && (moveList[x + 1][y] < moveList[x][y]) && (moveList[x + 1][y] == moveCount - map.getMapCost(x, y))) { moveCount = moveCount - map.getMapCost(x, y); movingList[x + 1][y] = moveCount; return 2; } // 判定下方最短路径 if ((y < maxY - 1) && (moveList[x][y + 1] > -1) && (moveList[x][y + 1] < moveList[x][y]) && (moveList[x][y + 1] == moveCount - map.getMapCost(x, y))) { moveCount = moveCount - map.getMapCost(x, y); movingList[x][y + 1] = moveCount; return 3; } return 4; } /** * 移动角色 * */ public synchronized void moveRole() { state = "开始移动"; int x = lastX; int y = lastY; int direction; // 移动方向判定 for (int i = 0; i <= moveCount; i++) { direction = 4; if ((x > 0) && (moveList[x - 1][y] > -1) && (movingList[x - 1][y] - map.getMapCost(x - 1, y) == movingList[x][y])) direction = 0; // 左 if ((y > 0) && (moveList[x][y - 1] > -1) && (movingList[x][y - 1] - map.getMapCost(x, y - 1) == movingList[x][y])) direction = 1; // 上 if ((x < maxX - 1) && (moveList[x + 1][y] > -1) && (movingList[x + 1][y] - map.getMapCost(x + 1, y) == movingList[x][y])) direction = 2; // 右 if ((y < maxY - 1) && (moveList[x][y + 1] > -1) && (movingList[x][y + 1] - map.getMapCost(x, y + 1) == movingList[x][y])) direction = 3; // 下 switch (direction) { case 0: x = x - 1; break; case 1: y = y - 1; break; case 2: x = x + 1; break; case 3: y = y + 1; break; case 4: break; } Role role = getRole(actionUnit); role.setX(x); role.setY(y); drawBattle(); Utility.wait(10); } getRole(actionUnit).x = curX; getRole(actionUnit).y = curY; Utility.wait(10); } /** * 设定移动范围 */ public synchronized void setMoveRange() { Role role = getRole(actionUnit); int x = role.x; int y = role.y; int area = role.move; // 有效范围 moveList[x][y] = 0; // 设定现在为移动0步 for (int count = 0; count <= area - 1; count++) { for (int j = redressY(y - area); j < redressY(y + area); j++) { for (int i = redressX(x - (area - Math.abs(y - j))); i <= redressX(x + (area - Math.abs(y - j))); i++) { // 如果能够移动指定步数 if ((getMoveCount(i - 1, j) == count) || (getMoveCount(i, j - 1) == count) || (getMoveCount(i + 1, j) == count) || (getMoveCount(i, j + 1) == count)) { setMoveCount(i, j, count); } } } } area = area + 1; // 射程 for (int j = redressY(y - area); j <= redressY(y + area); j++) { for (int i = redressX(x - (area - Math.abs(y - j))); i <= redressX(x + (area - Math.abs(y - j))); i++) { // 远程攻击 if ((getMoveCount(i - 1, j) > -1) || (getMoveCount(i, j - 1) > -1) || (getMoveCount(i + 1, j) > -1) || (getMoveCount(i, j + 1) > -1)) { attackList[i][j] = 1; } } } } /** * 获得指定索引及分组下角色 * * @param team * @param x * @param y * @return */ public synchronized int getRoleIdx(final int team, final int x, final int y) { int index = 0; for (Iterator it = unitList.iterator(); it.hasNext();) { Role role = (Role) it.next(); if (x == role.x && y == role.y && team == role.team) { return index; } index++; } return -1; } /** * 创建角色 * * @param name * @param team * @param imageIndex * @param move * @param x * @param y */ private synchronized void createRole(String name, int team, int imageIndex, int move, int x, int y) { unitList.add(new Role(name, team, unitImages[imageIndex], move, x, y)); } /** * 绘制画面 * */ public synchronized void drawBattle() { int count = 0; // 绘制地图 graphics.drawImage(mapImage, 0, 0, null); // 移动范围绘制 if ((state.equalsIgnoreCase("角色移动")) || (state.equalsIgnoreCase("移动范围"))) { for (int j = 0; j <= maxY - 1; j++) { for (int i = 0; i <= maxX - 1; i++) { if (moveList[i][j] > -1) { graphics.drawImage(iconImages[2], i * tile, j * tile, null); } else if (attackList[i][j] > 0) { graphics.drawImage(iconImages[3], i * tile, j * tile, null); } } } } // 角色绘制 for (int index = 0; index < unitList.size(); index++) { Role role = (Role) unitList.get(index); if (index == actionUnit) { // 当前控制角色处理(此示例未加入特殊处理) graphics.drawImage(role.getImage(), role.getX() * tile, role .getY() * tile, null); } else { graphics.drawImage(role.getImage(), role.getX() * tile, role .getY() * tile, null); } // 已行动完毕 if (role.action == 1) { graphics.drawImage(unitImages[3], role.getX() * tile, role .getY() * tile, null); } } // 攻击范围绘制 if (state.equalsIgnoreCase("进行攻击")) { for (int j = 0; j <= maxY - 1; j++) { for (int i = 0; i <= maxX - 1; i++) { int result = attackList[i][j]; if (result == 2) { graphics.drawImage(iconImages[3], i * tile, j * tile, null); } // 标注选中的攻击对象 if (result == 2 && getRoleIdx(1, i, j) > -1 && curX == i && curY == j) { graphics.drawImage(iconImages[4], i * tile, j * tile, null); } } } } // 绘制移动路线 if (state.equalsIgnoreCase("角色移动")) { for (int j = 0; j <= maxY - 1; j++) { for (int i = 0; i <= maxX - 1; i++) { if (movingList[i][j] == -1) { continue; } count = 0; if ((movingList[i][j] == 0) || (movingList[i][j] == moveCount)) { if ((i > 0) && (movingList[i - 1][j] > -1) && ((movingList[i - 1][j] - map.getMapCost(i - 1, j) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i - 1][j]))) { count = 1; } if ((j > 0) && (movingList[i][j - 1] > -1) && ((movingList[i][j - 1] - map.getMapCost(i, j - 1) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i][j - 1]))) { count = 2; } if ((i < maxX-1) && (movingList[i + 1][j] > -1) && ((movingList[i + 1][j] - map.getMapCost(i + 1, j) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i + 1][j]))) { count = 3; } if ((j < maxY-1) && (movingList[i][j + 1] > -1) && ((movingList[i][j + 1] - map.getMapCost(i, j + 1) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i][j + 1]))) { count = 4; } if (movingList[i][j] != 0) { count = count + 4; } } else { count = 6; if ((i > 0) && (movingList[i - 1][j] > -1) && ((movingList[i - 1][j] - map.getMapCost(i - 1, j) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i - 1][j]))) { count = count + 1; } if ((j > 0) && (movingList[i][j - 1] > -1) && ((movingList[i][j - 1] - map.getMapCost(i, j - 1) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i][j - 1]))) { count = count + 2; } if ((i < maxX-1) && (movingList[i + 1][j] > -1) && ((movingList[i + 1][j] - map.getMapCost(i + 1, j) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i + 1][j]))) { count = count + 3; } if ((j < maxY-1) && (movingList[i][j + 1] > -1) && ((movingList[i][j + 1] - map.getMapCost(i, j + 1) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i][j + 1]))) { count = count + 5; } } if (count > 0) { graphics.drawImage(iconImages[count + 4], i * tile, j * tile, null); } } } } // 菜单 if (menu.visible) { Utility.setAlpha(graphics, 0.50f); graphics.drawImage(listImages[0], menu.getLeft(curX) * tile, 0, null); for (int i = 1; i <= menu.width; i++) { graphics.drawImage(listImages[1], (menu.getLeft(curX) + i) * tile, 0, null); } graphics.drawImage(listImages[2], (menu.getLeft(curX) + menu.width + 1) * tile, 0, null); for (int j = 1; j <= menu.height; j++) { graphics.drawImage(listImages[3], menu.getLeft(curX) * tile, j * tile, null); for (int i = 1; i <= menu.width; i++) { graphics.drawImage(listImages[4], (menu.getLeft(curX) + i) * tile, j * tile, null); } graphics.drawImage(listImages[5], (menu.getLeft(curX) + menu.width + 1) * tile, j * tile, null); } graphics.drawImage(listImages[6], menu.getLeft(curX) * tile, (menu.height + 1) * tile, null); for (int i = 1; i <= menu.width; i++) { graphics.drawImage(listImages[7], (menu.getLeft(curX) + i) * tile, (menu.height + 1) * tile, null); } graphics.drawImage(listImages[8], (menu.getLeft(curX) + menu.width + 1) * tile, (menu.height + 1) * tile, null); Utility.setAlpha(graphics, 1.0f); // 写入文字 graphics.drawImage(iconImages[1], (menu.getLeft(curX) + 1) * tile, (menu.cur + 1) * tile, null); for (int j = 1; j <= menu.height; j++) { graphics.setColor(Color.white); Utility.drawDefaultString(menu.getMenuItem(j - 1), graphics, (menu.getLeft(curX) + 2) * tile, ((j * tile)) + 24, 0, 23); } } // 显示状态 if (state.equalsIgnoreCase("状态显示")) { int i = getRoleIdx(0, curX, curY); if (i == -1) { i = getRoleIdx(1, curX, curY); } if (i > -1) { Role role = (Role) unitList.get(i); Utility.setAlpha(graphics, 0.75f); graphics.drawImage(listImages[0], menu.getLeft(curX) * tile, 0, null); graphics.drawImage(listImages[1], (menu.getLeft(curX) + 1) * tile, 0, null); graphics.drawImage(listImages[1], (menu.getLeft(curX) + 2) * tile, 0, null); graphics.drawImage(listImages[2], (menu.getLeft(curX) + 3) * tile, 0, null); graphics.drawImage(listImages[3], (menu.getLeft(curX)) * tile, tile, null); graphics.drawImage(listImages[4], (menu.getLeft(curX) + 1) * tile, tile, null); graphics.drawImage(listImages[4], (menu.getLeft(curX) + 2) * tile, tile, null); graphics.drawImage(listImages[5], (menu.getLeft(curX) + 3) * tile, tile, null); graphics.drawImage(listImages[3], menu.getLeft(curX) * tile, 64, null); graphics.drawImage(listImages[4], (menu.getLeft(curX) + 1) * tile, 64, null); graphics.drawImage(listImages[4], (menu.getLeft(curX) + 2) * tile, 64, null); graphics.drawImage(listImages[5], (menu.getLeft(curX) + 3) * tile, 64, null); graphics.drawImage(listImages[6], (menu.getLeft(curX)) * tile, 96, null); graphics.drawImage(listImages[7], (menu.getLeft(curX) + 1) * tile, 96, null); graphics.drawImage(listImages[7], (menu.getLeft(curX) + 2) * tile, 96, null); graphics.drawImage(listImages[8], (menu.getLeft(curX) + 3) * tile, 96, null); Utility.setAlpha(graphics, 1.0f); // 显示角色数据 graphics.drawImage(role.getImage(), (menu.getLeft(curX) + 1) * tile + 16, tile, null); Utility.drawDefaultString("HP:" + role.getHp(), graphics, (menu .getLeft(curX) + 1) * tile + 12, 75, 1, 12); Utility.drawDefaultString("MV:" + role.getMove(), graphics, (menu.getLeft(curX) + 1) * tile + 12, 88, 1, 12); } } // 战斗回合 if (state.equalsIgnoreCase("战斗开始") || state.equalsIgnoreCase("战斗结束")) { Utility.setAlpha(graphics, 0.5f); graphics.setColor(Color.black); graphics.fillRect(0, 90, 320, 140); graphics.setColor(Color.white); Utility.setAlpha(graphics, 1.0f); Utility.drawDefaultString("第" + turn + "回合", graphics, 120, 160, 0, 25); } // 我方移动 else if (state.equalsIgnoreCase("开始移动")) { // 未添加处理 } else if (state.equalsIgnoreCase("敌方行动")) { for (int i = unitList.size() - 1; i > -1; i--) { Role role = (Role) unitList.get(i); // 敌军,且无法再次移动和攻击 if (role.team == 1 && role.action == 1) { int x = role.x; int y = role.y; int index = 0; // 当敌军移动地点附近才能在我方人物时, 直接删除List中我方角色(实际开发中应加入相应判定) if ((index = getRoleIdx(0, x, y + 1)) > -1 && !role.isAttack()) { unitList.remove(index); } else if ((index = getRoleIdx(0, x, y - 1)) > -1 && !role.isAttack()) { unitList.remove(index); } else if ((index = getRoleIdx(0, x + 1, y)) > -1 && !role.isAttack()) { unitList.remove(index); } else if ((index = getRoleIdx(0, x - 1, y)) > -1 && !role.isAttack()) { unitList.remove(index); } role.setAttack(true); } } } else { // 绘制光标 graphics.drawImage(iconImages[0], curX * tile, curY * tile, null); } // 刷新画面 this.repaint(); } public void paint(Graphics g) { g.drawImage(screen, 0, 0, null); g.dispose(); } public void update(Graphics g) { paint(g); } /** * 矫正x坐标 * * @param x * @return */ public synchronized int redressX(int x) { if (x < 0) x = 0; if (x > maxX - 1) x = maxX - 1; return x; } /** * 矫正y坐标 * * @param y * @return */ public synchronized int redressY(int y) { if (y < 0) y = 0; if (y > maxY - 1) y = maxY - 1; return y; } /** * 敌军行动 * */ public synchronized void enemyAction() { for (int index = 0; index < unitList.size(); index++) { Role role = (Role) unitList.get(index); if (role.team != 1) { continue; } actionUnit = index; setMoveRange(); // 随机选择敌方移动地点 int x = role.move - new Random().nextInt(role.move * 2 + 1); int y = (role.move - Math.abs(x)) - new Random().nextInt((role.move - Math.abs(x)) * 2 + 1); x = redressX(role.x + x); y = redressY(role.y + y); if ((moveList[x][y] > 0) && (getRoleIdx(0, x, y) == -1) && (getRoleIdx(1, x, y) == -1)) { // 记录角色最后的移动位置 lastX = role.x; lastY = role.y; curX = x; curY = y; moveCount = moveList[x][y]; movingList[x][y] = moveCount; for (int i = 0; i < moveCount; i++) { switch (setMoveCouse(x, y)) { case 0: x = x - 1; break; case 1: y = y - 1; break; case 2: x = x + 1; break; case 3: y = y + 1; break; default: break; } } moveCount = moveList[curX][curY]; movingList[x][y] = 0; moveRole(); } state = "敌方行动"; curX = 0; curY = 0; role.setAction(1); role.setAttack(false); actionUnit = -1; initRange(); drawBattle(); Utility.wait(200); } } public void keyReleased(KeyEvent e) { if (state.equalsIgnoreCase("战斗开始")) return; if (state.equalsIgnoreCase("战斗结束")) return; if (state.equalsIgnoreCase("敌方行动")) return; // 菜单可见 if (menu.visible) { switch (e.getKeyCode()) { case KeyEvent.VK_UP: if (menu.cur > 0) { menu.cur = menu.cur - 1; } break; case KeyEvent.VK_DOWN: if (menu.cur < menu.height - 1) { menu.cur = menu.cur + 1; } break; } } // 菜单不可见 else { switch (e.getKeyCode()) { case KeyEvent.VK_LEFT: curX = redressX(curX - 1); break; case KeyEvent.VK_UP: curY = redressY(curY - 1); break; case KeyEvent.VK_RIGHT: curX = redressX(curX + 1); break; case KeyEvent.VK_DOWN: curY = redressY(curY + 1); break; } } if (state.equalsIgnoreCase("角色移动")) { setMoveCourse(); } drawBattle(); } public void keyPressed(KeyEvent e) { int code = e.getKeyCode(); eventCode = code; } public void keyTyped(KeyEvent e) { } }
这个类里面有很多东西,我们从头开始看,
// 地图 this.mapImage = this.map.getMapImage(); this.maxX = map.getMaxX(); this.maxY = map.getMaxY(); this.moveList = new int[maxX][maxY]; this.movingList = new int[maxX][maxY]; this.attackList = new int[maxX][maxY]; int width = maxX * tile; int height = maxY * tile;构造函数里面的地图解析,地图map类
package org.loon.simple.slg.ai; import java.awt.Graphics; import java.awt.Image; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; /** * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:ceponline@yahoo.com.cn * @version 0.1 */ public class Map { private int[][] mapArray = null; private int size = 0; private int maxX = 0; private int maxY = 0; private int tile = 32; private Image[] mapImages; /** * 加载指定地图文件为list * * @param fileName * @return * @throws IOException */ private static List loadList(final String fileName) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader( Utility.getResource(fileName))); List records = new ArrayList(10); String result = null; try { // 分解地图设定点 while ((result = reader.readLine()) != null) { char[] charArray = result.toCharArray(); int size = charArray.length; int[] intArray = new int[size]; for (int i = 0; i < size; i++) { intArray[i] = Character.getNumericValue(charArray[i]); } records.add(intArray); } } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { } } } return records; } /** * 加载地图文件为整型二维数组 * * @param fileName * @return * @throws IOException */ public static int[][] loadArray(final String fileName) throws IOException { // 取得地图二维数组(此时row,col颠倒) List list = loadList(fileName); int row = list.size(); int[][] mapArray = new int[row][]; for (int i = 0; i < row; i++) { mapArray[i] = (int[]) list.get(i); } int col = (((int[]) mapArray[row > 0 ? row - 1 : 0]).length); // 颠倒二维数组row,col int[][] result = new int[col][row]; for (int j = 0; j < col; j++) { for (int i = 0; i < row; i++) { result[i][j] = mapArray[j][i]; } } return result; } /** * 构造地图 * * @param size * @param fileName */ public Map(final String fileName, final int tile) { try { this.mapArray = Map.loadArray(fileName); } catch (IOException e) { throw new RuntimeException(e); } this.size = this.mapArray.length; this.tile = tile; this.maxX = this.size; this.maxY = (((int[]) this.mapArray[this.maxX > 0 ? this.maxX - 1 : 0]).length); this.mapImages = Utility.getSplitImages("image/map.png", tile, tile); } /** * 获得地图图像 * * @return */ public Image getMapImage() { Image image = Utility.createImage(maxX * tile, maxY * tile, true); Graphics graphics = image.getGraphics(); for (int y = 0; y <= maxY - 1; y++) { for (int x = 0; x <= maxX - 1; x++) { int type = getMapType(x, y); graphics.drawImage(mapImages[type], x * tile, y * tile, null); } } graphics.dispose(); return image; } public int[][] getMaps() { return mapArray; } public int getMaxX() { return maxX; } public int getMaxY() { return maxY; } /** * 获得地图指定坐标点对象 * * @param x * @param y * @return */ public int getMapType(int x, int y) { /*if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x > maxX - 1) { x = maxX - 1; } if (y > maxY - 1) { y = maxY - 1; }*/ return mapArray[x][y]; } /** * 返回指定坐标地形 * * @param x * @param y * @return */ public int getMapCost(int x, int y) { int type = getMapType(x, y); switch (type) { case 0: type = 1; // 草 break; case 1: type = 2; // 树 break; case 2: type = 3; // 山地 break; case 3: type = -1; // 湖泽(不能进入) break; } return type; } }map.txt
1122221100 0000012210 1100001100 0001110000 0000111000 0000000000 1100000000 2111102002 2211133202 2222113322这个是地图的图块信息,getmapcost方法中可见0是草,1是树,2是山地,3是湖泽(不可移动),map.txt被map类解析完,由canvas的构造函数初始化调用,
// 创建角色:name=空罐少女,team=0(我军),imageindex=3,x=7,y=1,以下雷同 createRole("空罐少女", 0, 0, 3, 7, 1); createRole("猫猫1", 0, 1, 6, 1, 2); createRole("猫猫2", 0, 0, 3, 2, 6); // 创建角色:name=躲猫兵团1,team=1(敌军),imageindex=6,x=4,y=5,以下雷同 createRole("躲猫兵团1", 1, 2, 4, 4, 5); createRole("躲猫兵团2", 1, 2, 4, 8, 5); createRole("躲猫兵团3", 1, 2, 4, 5, 7); createRole("躲猫兵团4", 1, 2, 4, 7, 2);
/** * 创建角色 * * @param name * @param team * @param imageIndex * @param move * @param x * @param y */ private synchronized void createRole(String name, int team, int imageIndex, int move, int x, int y) { unitList.add(new Role(name, team, unitImages[imageIndex], move, x, y)); }创建人物,我们看到创建人物在unitList中加入了角色的信息,包括名称,阵营,图片等等信息
this.screen = Utility.createImage(width, height, true); this.graphics = (Graphics2D) screen.getGraphics();
绘制screen,我们看下Utility类
package org.loon.simple.slg.ai; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Container; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.MediaTracker; import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.awt.image.ImageProducer; import java.awt.image.MemoryImageSource; import java.awt.image.PixelGrabber; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Map; import java.util.WeakHashMap; public class Utility { final static private Toolkit toolKit = Toolkit.getDefaultToolkit(); final static private MediaTracker mediaTracker = new MediaTracker( new Container()); final static private Map cacheImages = new WeakHashMap(100); final static private ClassLoader classLoader = Thread.currentThread() .getContextClassLoader(); final static String newLine = "\r\n"; final static RenderingHints hints; static { // 设定图像显示状态 hints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); hints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); hints.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); hints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); hints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE); } private Utility() { } /** * 分解整图为图片数组 * * @param fileName * @param row * @param col * @return */ public static Image[] getSplitImages(String fileName, int row, int col) { Image image = Utility.loadImage(fileName); int index = 0; int wlenght = image.getWidth(null) / row; int hlenght = image.getHeight(null) / col; int l = wlenght * hlenght; Image[] abufferedimage = new Image[l]; for (int y = 0; y < hlenght; y++) { for (int x = 0; x < wlenght; x++) { abufferedimage[index] = Utility.createImage(row, col, true); Graphics g = abufferedimage[index].getGraphics(); g.drawImage(image, 0, 0, row, col, (x * row), (y * col), row + (x * row), col + (y * col), null); g.dispose(); // 透明化处理 PixelGrabber pgr = new PixelGrabber(abufferedimage[index], 0, 0, -1, -1, true); try { pgr.grabPixels(); } catch (InterruptedException ex) { ex.getStackTrace(); } int pixels[] = (int[]) pgr.getPixels(); //循环像素 for (int i = 0; i < pixels.length; i++) { //去色255,0,255 LColor color = LColor.getLColor(pixels[i]); if (color.R == 255 && color.G == 0 && color.B == 255) { //透明化 pixels[i] = 0; } } ImageProducer ip = new MemoryImageSource(pgr.getWidth(), pgr .getHeight(), pixels, 0, pgr.getWidth()); abufferedimage[index] = toolKit.createImage(ip); index++; } } return abufferedimage; } public static Image drawClipImage(final Image image, int objectWidth, int objectHeight, int x1, int y1, int x2, int y2) throws Exception { BufferedImage buffer = Utility.createImage(objectWidth, objectHeight, true); Graphics g = buffer.getGraphics(); Graphics2D graphics2D = (Graphics2D) g; graphics2D.drawImage(image, 0, 0, objectWidth, objectHeight, x1, y1, x2, y2, null); graphics2D.dispose(); graphics2D = null; return buffer; } /** * 生成大图的截取图 * * @param source * @param src_x * @param src_y * @param desc_width * @param desc_height * @return */ public static BufferedImage drawClip(String source, int src_x, int src_y, int desc_width, int desc_height) { return Utility.drawClip(Utility.getBufferImage(Utility .loadImage(source)), src_x, src_y, desc_width, desc_height); } public static void drawString(String s, final Graphics2D g, int i, int j, int k) { Graphics2D graphics2D = (Graphics2D) g; graphics2D.setRenderingHints(hints); Font font = graphics2D.getFont(); int size = graphics2D.getFontMetrics(font).stringWidth(s); Utility.setAlpha(g, 0.9f); graphics2D.drawString(s, i + (k - size) / 2, j); Utility.setAlpha(g, 1.0f); } /** * 在graphics上描绘文字 * * @param message * @param fontName * @param g * @param x1 * @param y1 * @param style * @param size */ public static void drawString(String message, String fontName, final Graphics g, int x1, int y1, int style, int size) { Graphics2D graphics2D = (Graphics2D) g; graphics2D.setRenderingHints(hints); graphics2D.setFont(new Font(fontName, style, size)); Utility.setAlpha(g, 0.9f); graphics2D.drawString(message, x1, y1); Utility.setAlpha(g, 1.0f); } /** * 默认的文字输出 * * @param message * @param g * @param x1 * @param y1 * @param font * @param fontSize */ public static void drawDefaultString(String message, final Graphics2D g, int x1, int y1, int font, int fontSize) { g.setRenderingHints(hints); g.setFont(new Font("华文新魏", font, fontSize)); g.drawString(message, x1, y1); } public static BufferedImage getBufferImage(final Image image) { int width = image.getWidth(null); int height = image.getHeight(null); BufferedImage bufferedimage = createImage(width, height, true); Graphics g = bufferedimage.getGraphics(); g.drawImage(image, 0, 0, null); return bufferedimage; } public Image drawClip(final Image image, int objectWidth, int objectHeight, int x1, int y1, int x2, int y2) throws Exception { BufferedImage buffer = Utility.createImage(objectWidth, objectHeight, true); Graphics g = buffer.getGraphics(); Graphics2D graphics2D = (Graphics2D) g; graphics2D.drawImage(image, 0, 0, objectWidth, objectHeight, x1, y1, x2, y2, null); graphics2D.dispose(); graphics2D = null; return buffer; } /** * 生成截取图 * * @param image * @param src_x * @param src_y * @param desc_width * @param desc_height * @return */ public static BufferedImage drawClip(final Image image, int src_x, int src_y, int desc_width, int desc_height) { BufferedImage thumbImage = new BufferedImage(desc_width, desc_height, BufferedImage.TYPE_INT_RGB); Graphics2D graphics2D = thumbImage.createGraphics(); graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); graphics2D.drawImage(image, 0, 0, desc_width, desc_height, src_x, src_y, image.getWidth(null), image.getHeight(null), null); graphics2D.dispose(); return thumbImage; } public final static InputStream getResource(final String fileName) { return new BufferedInputStream(classLoader .getResourceAsStream(fileName)); } /** * 加载file转为Image * * @param inputstream * @return */ final static public Image loadImage(final String fileName) { String keyName = fileName.trim().toLowerCase(); Image cacheImage = (Image) cacheImages.get(keyName); if (cacheImage == null) { InputStream in = new BufferedInputStream(classLoader .getResourceAsStream(fileName)); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { byte[] bytes = new byte[8192]; int read; while ((read = in.read(bytes)) >= 0) { byteArrayOutputStream.write(bytes, 0, read); } byte[] arrayByte = byteArrayOutputStream.toByteArray(); cacheImages.put(keyName, cacheImage = toolKit .createImage(arrayByte)); mediaTracker.addImage(cacheImage, 0); mediaTracker.waitForID(0); waitImage(100, cacheImage); } catch (Exception e) { throw new RuntimeException(fileName + " not found!"); } finally { try { if (byteArrayOutputStream != null) { byteArrayOutputStream.close(); byteArrayOutputStream = null; } if (in != null) { in.close(); } } catch (IOException e) { } } } if (cacheImage == null) { throw new RuntimeException(("File not found. ( " + fileName + " )") .intern()); } return cacheImage; } /** * 延迟加载image,以使其同步。 * * @param delay * @param image */ private final static void waitImage(int delay, Image image) { try { for (int i = 0; i < delay; i++) { if (toolKit.prepareImage(image, -1, -1, null)) { return; } Thread.sleep(delay); } } catch (Exception e) { } } /** * 生成一个BufferImage * * @param i * @param j * @param flag * @return */ final static public BufferedImage createImage(int i, int j, boolean flag) { if (flag) { return new BufferedImage(i, j, 2); } else { return new BufferedImage(i, j, 1); } } /** * 延迟指定毫秒 * * @param ms */ final static public void wait(final int ms) { try { Thread.sleep(ms); } catch (InterruptedException ex) { } } /** * 字体设定 * * @param g * @param size * @param type */ final static public void font(final Graphics2D g, final int size, int type) { if (type == 0) { type = 0; } if (type == 1) { type = 1; } g.setFont(new Font("SansSerif", type, size)); } final static public void font(final Graphics2D g, final String fontName, final int size, int type) { if (type == 0) { type = 0; } if (type == 1) { type = 1; } g.setFont(new Font(fontName, type, size)); } /** * 颜色设定 * * @param gr * @param r * @param g * @param b */ final static public void color(final Graphics2D gr, final int r, final int g, final int b) { gr.setColor(new Color(r, g, b)); } /** * 透明度设定 * * @param g * @param d */ final static public void setAlpha(Graphics g, double d) { AlphaComposite alphacomposite = AlphaComposite .getInstance(3, (float) d); ((Graphics2D) g).setComposite(alphacomposite); } final static public void setAlpha(Graphics2D g2d, double d) { AlphaComposite alphacomposite = AlphaComposite .getInstance(3, (float) d); g2d.setComposite(alphacomposite); } /** * 分解小图 * * @param image * @param objectWidth * @param objectHeight * @param x1 * @param y1 * @param x2 * @param y2 * @return * @throws Exception */ final static private Image getClipImage(final Image image, int objectWidth, int objectHeight, int x1, int y1, int x2, int y2) throws Exception { BufferedImage buffer = createImage(objectWidth, objectHeight, true); Graphics g = buffer.getGraphics(); Graphics2D graphics2D = (Graphics2D) g; graphics2D.drawImage(image, 0, 0, objectWidth, objectHeight, x1, y1, x2, y2, null); graphics2D.dispose(); graphics2D = null; return buffer; } /** * 按横行宽度分解图像 * * @param img * @param width * @return */ final static public Image[] getImageRows(Image img, int width) { int iWidth = img.getWidth(null); int iHeight = img.getHeight(null); int size = iWidth / width; Image[] imgs = new Image[size]; for (int i = 1; i <= size; i++) { try { imgs[i - 1] = transBlackColor(getClipImage(img, width, iHeight, width * (i - 1), 0, width * i, iHeight)); } catch (Exception e) { e.printStackTrace(); } } return imgs; } /** * 将黑色颜色部分透明化 * * @param img * @return */ final static public Image transBlackColor(final Image img) { int width = img.getWidth(null); int height = img.getHeight(null); PixelGrabber pg = new PixelGrabber(img, 0, 0, width, height, true); try { pg.grabPixels(); } catch (InterruptedException e) { e.printStackTrace(); } int pixels[] = (int[]) pg.getPixels(); for (int i = 0; i < pixels.length; i++) { if (pixels[i] <= -11500000) { pixels[i] = 16777215; } } return toolKit.createImage(new MemoryImageSource(width, height, pixels, 0, width)); } /** * 清空image缓存 * */ final static public void destroyImages() { cacheImages.clear(); System.gc(); } }很明显这个类是作为图像处理的,
/** * 初始化各项范围参数 * */ public synchronized void initRange() { for (int y = 0; y <= maxY - 1; y++) { for (int x = 0; x <= maxX - 1; x++) { moveCount = 0; moveList[x][y] = -1; movingList[x][y] = -1; attackList[x][y] = 0; } } }
/** * 绘制画面 * */ public synchronized void drawBattle() { int count = 0; // 绘制地图 graphics.drawImage(mapImage, 0, 0, null); // 移动范围绘制 if ((state.equalsIgnoreCase("角色移动")) || (state.equalsIgnoreCase("移动范围"))) { for (int j = 0; j <= maxY - 1; j++) { for (int i = 0; i <= maxX - 1; i++) { if (moveList[i][j] > -1) { graphics.drawImage(iconImages[2], i * tile, j * tile, null); } else if (attackList[i][j] > 0) { graphics.drawImage(iconImages[3], i * tile, j * tile, null); } } } } // 角色绘制 for (int index = 0; index < unitList.size(); index++) { Role role = (Role) unitList.get(index); if (index == actionUnit) { // 当前控制角色处理(此示例未加入特殊处理) graphics.drawImage(role.getImage(), role.getX() * tile, role .getY() * tile, null); } else { graphics.drawImage(role.getImage(), role.getX() * tile, role .getY() * tile, null); } // 已行动完毕 if (role.action == 1) { graphics.drawImage(unitImages[3], role.getX() * tile, role .getY() * tile, null); } } // 攻击范围绘制 if (state.equalsIgnoreCase("进行攻击")) { for (int j = 0; j <= maxY - 1; j++) { for (int i = 0; i <= maxX - 1; i++) { int result = attackList[i][j]; if (result == 2) { graphics.drawImage(iconImages[3], i * tile, j * tile, null); } // 标注选中的攻击对象 if (result == 2 && getRoleIdx(1, i, j) > -1 && curX == i && curY == j) { graphics.drawImage(iconImages[4], i * tile, j * tile, null); } } } }
寻路
// 绘制移动路线 if (state.equalsIgnoreCase("角色移动")) { for (int j = 0; j <= maxY - 1; j++) { for (int i = 0; i <= maxX - 1; i++) { if (movingList[i][j] == -1) { continue; } count = 0; if ((movingList[i][j] == 0) || (movingList[i][j] == moveCount)) { if ((i > 0) && (movingList[i - 1][j] > -1) && ((movingList[i - 1][j] - map.getMapCost(i - 1, j) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i - 1][j]))) { count = 1; } if ((j > 0) && (movingList[i][j - 1] > -1) && ((movingList[i][j - 1] - map.getMapCost(i, j - 1) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i][j - 1]))) { count = 2; } if ((i < maxX-1) && (movingList[i + 1][j] > -1) && ((movingList[i + 1][j] - map.getMapCost(i + 1, j) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i + 1][j]))) { count = 3; } if ((j < maxY-1) && (movingList[i][j + 1] > -1) && ((movingList[i][j + 1] - map.getMapCost(i, j + 1) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i][j + 1]))) { count = 4; } if (movingList[i][j] != 0) { count = count + 4; } } else { count = 6; if ((i > 0) && (movingList[i - 1][j] > -1) && ((movingList[i - 1][j] - map.getMapCost(i - 1, j) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i - 1][j]))) { count = count + 1; } if ((j > 0) && (movingList[i][j - 1] > -1) && ((movingList[i][j - 1] - map.getMapCost(i, j - 1) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i][j - 1]))) { count = count + 2; } if ((i < maxX-1) && (movingList[i + 1][j] > -1) && ((movingList[i + 1][j] - map.getMapCost(i + 1, j) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i + 1][j]))) { count = count + 3; } if ((j < maxY-1) && (movingList[i][j + 1] > -1) && ((movingList[i][j + 1] - map.getMapCost(i, j + 1) == movingList[i][j]) || (movingList[i][j] - map.getMapCost(i, j) == movingList[i][j + 1]))) { count = count + 5; } } if (count > 0) { graphics.drawImage(iconImages[count + 4], i * tile, j * tile, null); } } } }
可以说每个地方地很详细
// 菜单 if (menu.visible) { Utility.setAlpha(graphics, 0.50f); graphics.drawImage(listImages[0], menu.getLeft(curX) * tile, 0, null); for (int i = 1; i <= menu.width; i++) { graphics.drawImage(listImages[1], (menu.getLeft(curX) + i) * tile, 0, null); } graphics.drawImage(listImages[2], (menu.getLeft(curX) + menu.width + 1) * tile, 0, null); for (int j = 1; j <= menu.height; j++) { graphics.drawImage(listImages[3], menu.getLeft(curX) * tile, j * tile, null); for (int i = 1; i <= menu.width; i++) { graphics.drawImage(listImages[4], (menu.getLeft(curX) + i) * tile, j * tile, null); } graphics.drawImage(listImages[5], (menu.getLeft(curX) + menu.width + 1) * tile, j * tile, null); } graphics.drawImage(listImages[6], menu.getLeft(curX) * tile, (menu.height + 1) * tile, null); for (int i = 1; i <= menu.width; i++) { graphics.drawImage(listImages[7], (menu.getLeft(curX) + i) * tile, (menu.height + 1) * tile, null); } graphics.drawImage(listImages[8], (menu.getLeft(curX) + menu.width + 1) * tile, (menu.height + 1) * tile, null); Utility.setAlpha(graphics, 1.0f); // 写入文字 graphics.drawImage(iconImages[1], (menu.getLeft(curX) + 1) * tile, (menu.cur + 1) * tile, null); for (int j = 1; j <= menu.height; j++) { graphics.setColor(Color.white); Utility.drawDefaultString(menu.getMenuItem(j - 1), graphics, (menu.getLeft(curX) + 2) * tile, ((j * tile)) + 24, 0, 23); } } // 显示状态 if (state.equalsIgnoreCase("状态显示")) { int i = getRoleIdx(0, curX, curY); if (i == -1) { i = getRoleIdx(1, curX, curY); } if (i > -1) { Role role = (Role) unitList.get(i); Utility.setAlpha(graphics, 0.75f); graphics.drawImage(listImages[0], menu.getLeft(curX) * tile, 0, null); graphics.drawImage(listImages[1], (menu.getLeft(curX) + 1) * tile, 0, null); graphics.drawImage(listImages[1], (menu.getLeft(curX) + 2) * tile, 0, null); graphics.drawImage(listImages[2], (menu.getLeft(curX) + 3) * tile, 0, null); graphics.drawImage(listImages[3], (menu.getLeft(curX)) * tile, tile, null); graphics.drawImage(listImages[4], (menu.getLeft(curX) + 1) * tile, tile, null); graphics.drawImage(listImages[4], (menu.getLeft(curX) + 2) * tile, tile, null); graphics.drawImage(listImages[5], (menu.getLeft(curX) + 3) * tile, tile, null); graphics.drawImage(listImages[3], menu.getLeft(curX) * tile, 64, null); graphics.drawImage(listImages[4], (menu.getLeft(curX) + 1) * tile, 64, null); graphics.drawImage(listImages[4], (menu.getLeft(curX) + 2) * tile, 64, null); graphics.drawImage(listImages[5], (menu.getLeft(curX) + 3) * tile, 64, null); graphics.drawImage(listImages[6], (menu.getLeft(curX)) * tile, 96, null); graphics.drawImage(listImages[7], (menu.getLeft(curX) + 1) * tile, 96, null); graphics.drawImage(listImages[7], (menu.getLeft(curX) + 2) * tile, 96, null); graphics.drawImage(listImages[8], (menu.getLeft(curX) + 3) * tile, 96, null); Utility.setAlpha(graphics, 1.0f); // 显示角色数据 graphics.drawImage(role.getImage(), (menu.getLeft(curX) + 1) * tile + 16, tile, null); Utility.drawDefaultString("HP:" + role.getHp(), graphics, (menu .getLeft(curX) + 1) * tile + 12, 75, 1, 12); Utility.drawDefaultString("MV:" + role.getMove(), graphics, (menu.getLeft(curX) + 1) * tile + 12, 88, 1, 12); } } // 战斗回合 if (state.equalsIgnoreCase("战斗开始") || state.equalsIgnoreCase("战斗结束")) { Utility.setAlpha(graphics, 0.5f); graphics.setColor(Color.black); graphics.fillRect(0, 90, 320, 140); graphics.setColor(Color.white); Utility.setAlpha(graphics, 1.0f); Utility.drawDefaultString("第" + turn + "回合", graphics, 120, 160, 0, 25); } // 我方移动 else if (state.equalsIgnoreCase("开始移动")) { // 未添加处理 } else if (state.equalsIgnoreCase("敌方行动")) { for (int i = unitList.size() - 1; i > -1; i--) { Role role = (Role) unitList.get(i); // 敌军,且无法再次移动和攻击 if (role.team == 1 && role.action == 1) { int x = role.x; int y = role.y; int index = 0; // 当敌军移动地点附近才能在我方人物时, 直接删除List中我方角色(实际开发中应加入相应判定) if ((index = getRoleIdx(0, x, y + 1)) > -1 && !role.isAttack()) { unitList.remove(index); } else if ((index = getRoleIdx(0, x, y - 1)) > -1 && !role.isAttack()) { unitList.remove(index); } else if ((index = getRoleIdx(0, x + 1, y)) > -1 && !role.isAttack()) { unitList.remove(index); } else if ((index = getRoleIdx(0, x - 1, y)) > -1 && !role.isAttack()) { unitList.remove(index); } role.setAttack(true); } } } else { // 绘制光标 graphics.drawImage(iconImages[0], curX * tile, curY * tile, null); } // 刷新画面 this.repaint(); }
期间用到的另外3个类
package org.loon.simple.slg.ai; import java.awt.Image; /** * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:ceponline@yahoo.com.cn * @version 0.1 */ public class Role { //名称 String name; //分队(0:我军 1:敌军) int team; //hp int hp; //角色图像 Image image; //移动力 int move; //行动状态(0:未行动 1:已行动) int action; //x坐标 int x; //y坐标 int y; //是否已进行攻击 boolean isAttack = false; /** * 设定角色参数 * * @param name * @param team * @param image * @param move * @param x * @param y */ public Role(String name, int team, Image image, int move, int x, int y) { this.name = name; this.team = team; this.hp = 10; this.image = image; this.move = move; this.x = x; this.y = y; } public int getAction() { return action; } public void setAction(int action) { this.action = action; } public int getHp() { return hp; } public void setHp(int hp) { this.hp = hp; } public Image getImage() { return image; } public void setImage(Image image) { this.image = image; } public int getMove() { return move; } public void setMove(int move) { this.move = move; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getTeam() { return team; } public void setTeam(int team) { this.team = team; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public boolean isAttack() { return isAttack; } public void setAttack(boolean isAttack) { this.isAttack = isAttack; } }
package org.loon.simple.slg.ai; /** * * Copyright 2008 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:ceponline@yahoo.com.cn * @version 0.1 */ public class LColor { public int R = 0; public int G = 0; public int B = 0; private LColor() { } /** * 判定两个lcolor是否相等 * * @param a * @param b * @return */ public static boolean equals(final LColor a, final LColor b) { return (a.R == b.R) && (a.G == b.G) && (a.B == b.B); } /** * 将颜色Pixel数值返回为LColor * * @param c * @return */ public static LColor getLColor(int pixel) { LColor color = new LColor(); color.R = (pixel & 0x00ff0000) >> 16; color.G = (pixel & 0x0000ff00) >> 8; color.B = pixel & 0x000000ff; return color; } /** * 将color返回为像素 * * @param color * @return */ public int getPixel(final LColor color) { return (color.R << 16) | (color.G << 8) | color.B; } public int getPixel() { return (R << 16) | (G << 8) | B; } /** * 注入r,g,b数值 * * @param r * @param g * @param b */ public LColor(final int r, final int g, final int b) { this.R = r; this.G = g; this.B = b; } public static LColor fromArgb(final int r, final int g, final int b) { return new LColor(r, g, b); } }
package org.loon.simple.slg.ai; import java.util.ArrayList; import java.util.List; /** * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:ceponline@yahoo.com.cn * @version 0.1 */ public class Menu { // 是否可见 boolean visible; // 菜单纵幅 int height; // 菜单横幅 int width; // 光标位置 int cur; // 菜单类型 int menuType; // 菜单选项 List menuItem; int size=0; public Menu(int size) { this.menuItem = new ArrayList(10); this.setVisible(false); this.setMenuType(0); this.setCur(0); this.size=size; } public void free() { this.menuItem.clear(); } public int getCur() { return cur; } /** * 设定光标 * @param cur */ public void setCur(int cur) { if (cur < 0) { cur = this.height - 1; } if (cur > this.height - 1) { cur = 0; } this.cur = cur; } /** * 获得指定索引位置菜单 * * @param index * @return */ public String getMenuItem(int index) { return (String) menuItem.get(index); } /** * 获得在地图上相对位置 * * @param size * @param x * @return */ public int getLeft(int x) { int result = -1; // 如果x点位置大于 9 / 2,则在左侧显示菜单 if (x > this.size / 2) { result = 0; } else { // 在右侧显示菜单 result = this.size - width - 1; } return result; } /** * 设定菜单项 * */ public void setMenuItem() { switch (this.menuType) { case 0: this.width = 3; this.height = 1; menuItem.add("结束"); break; case 1: this.width = 3; this.height = 1; menuItem.add("待机"); break; case 2: this.width = 3; this.height = 2; menuItem.add("攻击"); menuItem.add("待机"); break; } } public int getMenuType() { return menuType; } public void setMenuType(int menuType) { this.free(); this.menuType = menuType; this.setMenuItem(); } public boolean isVisible() { return visible; } public void setVisible(boolean visible) { this.visible = visible; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } }代码都在这里了,项目源码在这里(这个项目是cping1982的,不过他只提供了jar文件(源码在jar里)我方便大家直接做成了Eclipse项目,下载)
代码是贴完了,不过一个问题来了,战棋游戏因为玩法的独特性,所以貌似做成网游难度很大,现在放眼网游(手游)市场,类似产品只有《战龙兵团》勉强算,纯的战棋游戏
《三国鼎立》也是刚刚回归国服,归其原因还是因为玩法上面特殊,时间消耗太大,战龙兵团为了规避走格子消耗太多的时间,发明了战役挂机---这个想法不错《我叫Mt》外传也是战役挂机,不过游戏搞得已经不是战棋游戏了,看上去是一款顶视图的《刀塔传奇》,把2d的玩法加了一个z轴,变成了3d玩法而已,战龙兵团怎么还有个pvp模式,可以真正体验战棋的乐趣(虽然一场仗要打10几20个小时,不过随时退出游戏,随时加入游戏都不限制,可以根据自己时间安排休闲),日本去年12月份上线了一款纯战棋手游,国内火焰vs众筹失败,所以近期吃螃蟹的公司可能不会有,毕竟风险很大,不过风险与机遇是并存的,当年火焰纹章的策划案提出的时候,也是被压了2年时间,当时任天堂内部也是很多声音,怀疑这种游戏类型能否被玩家接受,但后来事实证明,火纹被全世界玩家所喜爱(可能说的有点绝对,但火纹的消费群绝不是掌机那小小的一群人),市场其实还是挺大的,或许不久的将来战棋类型网游真的能成功也说不定。
当然策略游戏也可以归为SLG游戏,不过这里不做讨论。
相关文章推荐
- 在cmd中使用VC++ cl.exe时找不到mspdb100.dll的解决办法
- Attribute(两)——定义自己的特色+Asp.net MVC中间filter详细解释
- C++二叉搜索树容器set的调用
- C#名单:一个简单的实现
- C++键树容器map的调用
- C++栈的调用
- Spring学习笔记-springMVC入门Demo
- C++优先队列的调用
- C++基础---位操作符
- C++普通队列容器
- Spring MVC 4 常用注解汇总
- C语言指针的算术运算
- C#制作、打包、签名、发布Activex全过程
- Mac下 Lua 添加库 luafilesystem
- golang byte转string 字节数组转字符串的问题
- Matlab画图加图例
- Matlab多维数组按照第一行从小到大进行列排序
- C++ Windows对象和MFC对象的区别
- Python快速教程
- Python快速教程