您的位置:首页 > 编程语言

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

2015-08-16 08:16 661 查看
喜欢玩火焰纹章吗?【这个是我最喜欢的游戏】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游戏,不过这里不做讨论。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: