今天开始做战斗,回合制战斗代码实现第三篇,特殊的回合制游戏Slg(策略战棋)

喜欢玩火焰纹章吗?【这个是我最喜欢的游戏】fc时期放假的时候,可以一次玩一天的游戏,梦幻模拟战,最早接触的电脑游戏《天使帝国》(我这个人比较奇怪,人家都是先玩红警,我最早接触的游戏除了486麻将,殖民计划,就是天使帝国了),加上光荣公司的3款开天辟地的slg大作,《三国英杰传》,《三国孔明传》,《三国曹操传》,还有台湾汉堂的几款游戏(炎龙骑士团,阿玛迪斯战记等等)加上后期的《风色幻想》,共同支撑起了当年Slg的鼎盛时期,不过在快节奏的今天,战棋游戏的滑落非常明显,虽然《火焰纹章》可以全球发售,在全球范围内都维护了大量粉丝,但最新版《觉醒》全球销量却并不是很尽如人意,为什么呢,并不是游戏的人气下落了,或者玩家少了,而是因为一场战斗花费太多的时间令玩家招架不住了,这个在单机游戏市场如此,在网络游戏市场就更是如此,战棋类网游吃螃蟹的日韩企业不是没有,早在03年就有《佣兵传说》这样的网游问世,国内也有盛大推出的《三国豪侠传》,但无一不是失败了,不过既然战棋有自己独特的魅力,又有固定稳定的玩家群体,那么只要想出解决时间开销问题的解决方法,相信赚钱也不是不可能,我们不讨论如何真把战棋搬到网络上。

我们今天只是聊聊战棋怎么做,当然因为市面上没有相关网游代码,单机代码也是很久以前的,所以大家凑合着看看就行了,等如果那一天战棋类网游真的火了,那么我们在加篇幅讨论。先看看这些曾经失败的作品其实盛大的三国豪侠传做的还挺好玩的,但是说实话,战棋游戏因为一次战斗要耗费太多时间,所以真要让玩家在网络上玩,还真要考虑些新的玩法,佣兵传说就不说了,这个游戏做的有问题,无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游戏,不过这里不做讨论。





  • 14
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值