用AS3.0开发flash版SLG游戏-1

说到经典的战棋游戏,我还是最痴迷于曹操传,以前也曾因为研究曹操传MOD而废寖忘食,也做过一个曹操传的MOD小热一时,

却没想到曹操传MOD已经发展到现在这种地步,无论是画面还是技术都有了大规模的突破

但是,修改永远是修改,总会遇到各种限制,想要突破,当然要自己动手,开发自己的引擎。
但是,在这里,我研究flash版的曹操传,目的并不是想要有任何突破,只是单纯的为了研究一下,熟悉一下用flash完成各种游戏的制作而已。

先看几个预览

预览

预览

预览

下面开始制作过程

首先,先建立一个战场,显示一张地图吧,
导出一张曹操传第一关颖川的地图,把它转化成gif格式,命名为1.gif待用
然后,建立1S.xml,作为S剧本,内容
<?xml version="1.0" encoding="GB2312"?>
<data>
<Map>1</Map>
</data>
里面的1就是地图的代号,对应的地图就是1.gif了
要显示它,就很简单了
建立两个Sprite,
//最底层Sprite
private var _bakSprite:Sprite;
//地图Sprite
private var _mapSprite:Sprite;
将地图建立在底层的Sprite,方便之后操作
_bakSprite.addChild(_mapSprite);

//加载地图
_pic_loader = new Loader();
_pic_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteMap);
var mapName:String = "Images/HM/" + _fightXml.Map + ".gif";
_pic_loader.load(new URLRequest(mapName));

//加载地图完毕
private function onCompleteMap(event:Event):void {
_pic_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompleteMap);
_image = Bitmap(_pic_loader.content);
_mapSprite.addChild(_image);
}
然后,一张地图,就可以显示出来了
当然,光显示出来还不行,因为地图很大,窗口显示不了全部的地图,这样,就要像曹操传中的那样,当鼠标移动到边界的时候,地图就发生移动,看到自己想看的位置
所以,需要加入鼠标移动事件
//鼠标移动事件
this.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);

//鼠标移动事件
private function mouseMoveHandler(event:MouseEvent):void{
var intX:int = event.currentTarget.mouseX;
var intY:int = event.currentTarget.mouseY;
if(intX < 48){
_mapXadd = 48;
}elseif(intX > Sav.gamedata["stageWidth"] - 48){
_mapXadd = -48;
}else{
_mapXadd = 0;
}
if(intY < 48){
_mapYadd = 48;
}elseif(intY > Sav.gamedata["stageHeight"] - 48){
_mapYadd = -48;
}else{
_mapYadd = 0;
}
}
Sav.gamedata["stageWidth"] 是flash窗口的宽度,我把它存在了静态变量里了,方便用的时候取出来
这样,根据鼠标和地图位置,先来确定地图移动的x,y的方向和步长
然后,加入一个贞事件,来控制地图的移动
//贞事件
this.addEventListener(Event.ENTER_FRAME, mapMoveHandler);
//贞事件
private function mapMoveHandler(event:Event):void{
if(_mapMoveCtrl > 5){
//根据地图移动用xy步长移动地图
_bakSprite.x += _mapXadd;
_bakSprite.y += _mapYadd;
_mapMoveCtrl = 0;
}
//控制地图不移出指定范围
if(_bakSprite.x > 0){
_bakSprite.x = 0;
}else if( _bakSprite.x < Sav.gamedata["stageWidth"] - _bakSprite.width){
_bakSprite.x = Sav.gamedata["stageWidth"] - _bakSprite.width;
}
if(_bakSprite.y > 0){
_bakSprite.y = 0;
}else if( _bakSprite.y < Sav.gamedata["stageHeight"] - _bakSprite.height){
_bakSprite.y = Sav.gamedata["stageHeight"] - _bakSprite.height;
}
_mapMoveCtrl ++;
}
_mapMoveCtrl 用来控制地图移动的速度,然后只要控制地图不移出指定的范围就可以了
这样,运行一下,就可以让地图自由的移动位置了

接下来,让地图上显示一个人物
导出曹操传中曹操的三个图片,去除背景,并保存为gif格式,就像下面这样

素材

首先,在1S.xml中加入
<Our>
<List>Caocao</List>
</Our>
建立一个用来显示人物动作的类CharacterMC,
在类里面,读取完图片之后,将其按照规律拆分成数组,和之前我在做flashRPG游戏的时候一样,用的同样的方法,
//Unit_mov图片加载完成
public function onCompleteUnit_mov(event:Event):void {
_image = Bitmap(_loader.content);
//初始化显示数组
_bitShowArr = new Array();
//将位图数据拆分成小块,装入bitmapArr
_bitmapArr=ImageCtrl.divide(_image,1,11);
var newArr:Array;
//得到向上行走数组
newArr = new Array(_bitmapArr[2][0],_bitmapArr[3][0]);
//将向上行走数组加入到显示数组 编号:0
_bitShowArr.push(newArr);
//得到向下行走数组
newArr = new Array(_bitmapArr[0][0],_bitmapArr[1][0]);
//将向下行走数组加入到显示数组 编号:1
_bitShowArr.push(newArr);
//得到向左行走数组
newArr = new Array(_bitmapArr[4][0],_bitmapArr[5][0]);
//将向左行走数组加入到显示数组 编号:2
_bitShowArr.push(newArr);
//得到向右行走数组
newArr = new Array(ImageCtrl.bitHorizontal(_bitmapArr[4][0]),ImageCtrl.bitHorizontal(_bitmapArr[5][0]));
//将向右行走数组加入到显示数组 编号:3
_bitShowArr.push(newArr);

startFrame();
}
然后显示的时候,只需要调用不同的编号,就可以显示不同的动作了
新建一个人物属性类,Character ,存放人物的属性
public class Character {
//人物显示控制类
private var _characterMC:CharacterMC;
//人物移动力
private var _moveLong:int;
//人物编号
private var _charaIndex:int;

然后在战场上,再另建一个Sprite,用来显示人物
//人物Sprite
private var _characterSprite:Sprite;
然后,在读取S剧本完成时,把人物加入
//我军人物添加
_ourArr = new Array();
//根据xml内容,得到我军人物,添加至战场
for each ( var ourment:XML in _fightXml.Our.elements( ) ) {
var ourName:String = ourment.toString();
var ourchara:XML = XML(_pXml[ourName]);
_characterMC = new CharacterMC(int(ourchara.Id));
_character = new Character(_characterMC,int(ourchara.Move),int(ourchara.Id));
_characterSprite.addChild(_characterMC);
_ourArr.push(_character);
}
运行就可以看到曹操出现在战场上了
预览

下面,开始控制曹操移动

首先,先在CS4里,建立一个MC,加入三个按钮,如图
素材

我暂时把地形全都设定成为可移动,且地形全都消耗1,1S.xml中
<DataMap>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
<list>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</list>
</DataMap>

加入鼠标点击事件
//鼠标点击事件
addEventListener(MouseEvent.CLICK,onClick);

//鼠标点击事件
private function onClick(event:Event):void{
var __mouseX:Number = event.currentTarget.mouseX;
var __mouseY:Number = event.currentTarget.mouseY;
var i:int;
if(_clickCtrl == "NULL"){
for(i=0;i<_ourArr.length;i++){
_character = _ourArr[i] as Character;
_characterMC = _character.characterMC;
if(Math.floor(_characterMC.x/48) == Math.floor(__mouseX/48) && Math.floor(_characterMC.y/48) == Math.floor(__mouseY/48)){
_nowChatacter = _character;
setRoad(_nowChatacter);
_clickCtrl = "ROAD_SHOW";
removeEventListener(MouseEvent.CLICK,onClick);
_roadSprite.addEventListener(MouseEvent.CLICK,onClick);
break;
}
}
}else if(_clickCtrl == "ROAD_SHOW"){
_characterMC = _nowChatacter.characterMC;
for(i=0;i<_roadShowArray.length;i++){
_nowPoint = new Point(Math.floor(_characterMC.x/48),Math.floor(_characterMC.y/48));
_nowDirection = _characterMC.getDir();
_toPoint = new Point(Math.floor(__mouseX/48),Math.floor(__mouseY/48));
_roadArray = _roadQuery.path4(_nowPoint,_toPoint,_roadShowArray);
if(_roadArray != null && _roadArray.length > 0){
addEventListener(Event.ENTER_FRAME, onFrame);
_clickCtrl == "MOVE_NOW"
SpriteRemove.removeAllChildren(_roadSprite);
_roadSprite.removeEventListener(MouseEvent.CLICK,onClick);
}
}
}


}
_clickCtrl 用来控制点击鼠标时,战场上的状态,当为NULL的时候,寻找点击的人物,然后开始寻找最大可移动的范围
//循环搜寻可到达的点
public function loopPath(thisPoint:Object):void{
if(thisPoint.moveLong <= 0){
return;
}

if(! thisPoint.isChecked){
_path.push(thisPoint);
thisPoint.isChecked = true;
}
var checkList:Array = [];
//获取周围四个点
if (thisPoint.y>0) {
checkList.push(_map[(thisPoint.y-1)][thisPoint.x]);
}
if (thisPoint.x>0) {
checkList.push(_map[thisPoint.y][(thisPoint.x-1)]);
}
if (thisPoint.x<_w-1) {
checkList.push(_map[thisPoint.y][(thisPoint.x+1)]);
}
if (thisPoint.y<_h-1) {
checkList.push(_map[(thisPoint.y+1)][thisPoint.x]);
}
for(var i=0;i<checkList.length;i++){
if(!checkList[i].isChecked || checkList[i].moveLong < thisPoint.moveLong){
checkList[i].moveLong = thisPoint.moveLong - 1;
loopPath(checkList[i]);
}
}
}
//搜寻最大路径
public function makePath(star:Point, moveLong:int):Array {
_path = [];
var isOver:Boolean = false;
setStart();
_starPoint = _map[star.y][star.x];
_starPoint.moveLong = moveLong;
loopPath(_starPoint);
return _path;
}

预览

最大路径找好后,点击目标点,利用A*算法,走到目标点
_clickCtrl 用来控制点击鼠标时,战场上的状态,当为ROAD_SHOW的时候,查找路径,并走到目标点
A*算法,比较麻烦,就不多解释了,想了解的,可以看源代码
然后,行走完毕后,要显示出选择菜单,
//人物移动事件贞控制
private function onFrame(event:Event):void {
_characterMC = _nowChatacter.characterMC;
if(_roadArray != null && _roadArray.length > 1){
if(_characterMC.x % 48 == 0 && _characterMC.y % 48 == 0){
if(_roadArray[0].x == _roadArray[1].x){
if(_roadArray[0].y > _roadArray[1].y){
_characterMC.setDir(0);
_xadd = 0;
_yadd = -_addLeng;
}else{
_characterMC.setDir(1);
_xadd = 0;
_yadd = _addLeng;
}
}else{
if(_roadArray[0].x > _roadArray[1].x){
_characterMC.setDir(2);
_xadd = -_addLeng;
_yadd = 0;
}else{
_characterMC.setDir(3);
_xadd = _addLeng;
_yadd = 0;
}
}

_roadArray.splice(0,1);

}
_characterMC.x += _xadd;
_characterMC.y += _yadd;

}else if(_characterMC.x % 48 == 0 && _characterMC.y % 48 == 0){
removeEventListener(Event.ENTER_FRAME, onFrame);
_selectBox.visible = true;
_selectBox.x = _characterMC.x + 48;
_selectBox.y = _characterMC.y;
}else{

_characterMC.x += _xadd;
_characterMC.y += _yadd;
}
}
所以在战场初始化的时候,加入菜单按钮等事件

//点击停止事件
_selectBox.btnStop.addEventListener(MouseEvent.CLICK, charaStopHandler);
//点击取消事件
_selectBox.btnCan.addEventListener(MouseEvent.CLICK, charaCanHandler);
//菜单隐藏
_selectBox.visible = false;
效果如下图
预览

接下来,显示一下地形,
准备一个Terrain.xml
<?xml version="1.0" encoding="GB2312"?>
<data>
<Terrain0>
<Name>平原</Name>
<Image></Image>
</Terrain0>
<Terrain1>
<Name>草原</Name>
<Image></Image>
</Terrain1>
<Terrain2>
<Name>树林</Name>
<Image></Image>
</Terrain2>
</data>
暂时添加这三个地形,等有时间了之后,再慢慢加
然后,在CS4里,建立一个MC,如下,用来显示地形

素材

剩下的就简单了,
在战场的鼠标点击事件中,当状态为NULL的时候,
if(_clickCtrl == "NULL"){
var queryPeople:Boolean = false;
//点击我军人物判断
for(i=0;i<_ourArr.length;i++){
_character = _ourArr[i] as Character;
_characterMC = _character.characterMC;
if(Math.floor(_characterMC.x/48) == Math.floor(__mouseX/48) && Math.floor(_characterMC.y/48) == Math.floor(__mouseY/48)){
_nowChatacter = _character;
setRoad(_nowChatacter);
_clickCtrl = "ROAD_SHOW";
removeEventListener(MouseEvent.CLICK,onClick);
_roadSprite.addEventListener(MouseEvent.CLICK,onClick);
queryPeople = true;
break;
}
}
//点击敌军人物判断
for(i=0;i<_enemyArr.length;i++){
//点击敌军人物动作
}
if(!queryPeople){
//点击地图,显示地形
_clickCtrl = "TERRAIN_SHOW";
var mapX:int = Math.floor((__mouseX - _bakSprite.x)/48);
var mapY:int = Math.floor((__mouseY - _bakSprite.y)/48);
var showX:int = Math.floor(__mouseX/48);
var showY:int = Math.floor(__mouseY/48);
var terrainId:int = _mapDate[mapX][mapY];
var terrainName:String = "Terrain" + terrainId;
_terrainBox.x = showX*48 - 48;
_terrainBox.y = showY*48 - 48;
if(_terrainBox.x < 0){
_terrainBox.x = 0;
}else if(_terrainBox.x > Sav.gamedata["stageWidth"] - 144){
_terrainBox.x = Sav.gamedata["stageWidth"] - 144;
}
if(_terrainBox.y < 0){
_terrainBox.y = 0;
}else if(_terrainBox.y > Sav.gamedata["stageHeight"] - 144){
_terrainBox.y = Sav.gamedata["stageHeight"] - 144;
}
_terrainBox.TerrainName.text = _terrain[terrainName].Name;
SpriteRemove.removeAllChildren(_terrainBox.TerrainShow);
_terrainBox.TerrainShow.addChild(ImageCtrl.getImage(_bmapimage,mapX*48,mapY*48,48,48));
removeEventListener(MouseEvent.CLICK,onClick);
_terrainBox.visible = true;
}
}else if(_clickCtrl == "ROAD_SHOW"){
就是说,点击的地方如果没有人,则显示地形框
然后,在鼠标移动的时候,把地形框隐藏掉
//鼠标移动事件
private function mouseMoveHandler(event:MouseEvent):void{
var intX:int = event.currentTarget.mouseX;
var intY:int = event.currentTarget.mouseY;
if(intX < 48){
_mapXadd = 48;
}elseif(intX > Sav.gamedata["stageWidth"] - 48 && intX <= Sav.gamedata["stageWidth"]){
_mapXadd = -48;
}else{
_mapXadd = 0;
}
if(intY < 48){
_mapYadd = 48;
}elseif(intY > Sav.gamedata["stageHeight"] - 48 && intY <= Sav.gamedata["stageHeight"]){
_mapYadd = -48;
}else{
_mapYadd = 0;
}
if(_terrainBox.visible){
_clickCtrl = "NULL";
_terrainBox.visible = false;
addEventListener(MouseEvent.CLICK,onClick);
}
}
看吧,效果如下图

预览

因为地形我全都设定成了0,所以现在点哪里都是平原

剩下的就是把1S.xml的地形好好设定下了

下次,研究在各种地形下行走的范围^0^!

下面,来继续在不同地形下的寻路问题
首先,准备好兵种数据Arms.xml
<?xml version="1.0" encoding="GB2312"?>
<data>
<Arms1>
<Name>英雄</Name>
<Property>
<Attack>A</Attack>
<Spirit>A</Spirit>
<Defense>A</Defense>
<Breakout>A</Breakout>
<Morale>A</Morale>
</Property>
<Terrain>
<Terrain0>1</Terrain0>
<Terrain1>1</Terrain1>
<Terrain2>2</Terrain2>
<Terrain3>100</Terrain3>
<Terrain4>100</Terrain4>
<Terrain5>1</Terrain5>
<Terrain6>1</Terrain6>
<Terrain7>1</Terrain7>
</Terrain>
</Arms1>
</data>
地形数据Terrain.xml
<?xml version="1.0" encoding="GB2312"?>
<data>
<Terrain0>平原</Terrain0>
<Terrain1>草原</Terrain1>
<Terrain2>树林</Terrain2>
<Terrain3>大河</Terrain3>
<Terrain4>栅栏</Terrain4>
<Terrain5>城池</Terrain5>
<Terrain6>村庄</Terrain6>
<Terrain7>帐篷</Terrain7>
</data>
人物属性上当然要对应好兵种
<?xml version="1.0" encoding="GB2312"?>
<data>
<Caocao>
<Id>1</Id>
<Name>曹操</Name>
<Arms>1</Arms>
<Lv>1</Lv>
<Exp>0</Exp>
<HP>100</HP>
<MP>50</MP>
<Move>5</Move>
</Caocao>
</data>
其中,Arms是兵种ID,Move是移动力
最后,设定下战场文件1S.xml
<?xml version="1.0" encoding="GB2312"?>
<data>
<Map>1</Map>
<DataMap>
<list>1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1</list>
<list>3,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1</list>
<list>3,3,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1</list>
<list>3,3,3,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,3,3</list>
<list>3,3,3,3,1,1,1,0,0,0,0,1,1,1,1,1,1,3,3,3</list>
<list>3,3,3,3,3,1,1,0,0,0,0,0,1,1,1,1,1,3,3,3</list>
<list>3,3,3,3,3,4,4,4,4,0,0,4,4,4,4,1,1,3,3,3</list>
<list>3,3,3,3,3,4,6,0,0,0,0,0,0,6,4,1,3,3,3,3</list>
<list>3,3,3,3,3,4,6,0,0,0,0,0,0,6,4,1,3,3,3,3</list>
<list>3,3,3,3,0,4,6,0,0,0,0,0,0,0,4,1,3,3,3,3</list>
<list>3,3,3,0,0,0,0,0,0,4,4,0,0,0,4,3,3,3,3,3</list>
<list>3,3,0,0,0,0,0,0,0,5,7,0,0,0,4,3,3,3,3,3</list>
<list>3,0,0,0,0,4,0,0,0,0,0,0,0,0,4,3,3,3,3,3</list>
<list>0,0,0,0,0,4,6,6,0,0,0,0,0,7,4,0,3,3,3,3</list>
<list>0,0,0,0,0,4,4,4,4,0,0,4,4,4,4,0,1,1,3,3</list>
<list>0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3</list>
<list>1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1</list>
<list>1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1</list>
<list>1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1</list>
<list>1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1</list>
</DataMap>
<Our>
<List x="10" y="5">Caocao</List>
</Our>
<Enemy />
</data>

然后开始利用这些数据,完成寻路
首先在添加战场人物的时候,要把相应的兵种和移动力都得到
//我军人物添加
_ourArr = new Array();
//根据xml内容,得到我军人物,添加至战场
for each ( var ourment:XML in _fightXml.Our.elements( ) ) {
var ourName:String = ourment.toString();
var ourchara:XML = XML(_pXml[ourName]);
_characterMC = new CharacterMC(int(ourchara.Id));
_characterMC.x = int(ourment.@x)*48;
_characterMC.y = int(ourment.@y)*48;
_character = new Character(_characterMC,int(ourchara.Move),int(ourchara.Id),int(ourchara.Arms));
_characterSprite.addChild(_characterMC);
_ourArr.push(_character);
}
Character类中,加入兵种ID属性就可以了

然后,寻路的时候,把当前人物传到makePath方法中

//寻找最大移动范围
private function setRoad(chara:Character){
_roadShowArray = _roadQuery.makePath(chara);

if(_roadShowArray != null && _roadShowArray.length > 0){
var sign:Sign;
for(var i:int = 0;i<_roadShowArray.length;i++){
sign = new Sign();
sign.x = _roadShowArray[i].x * 48;
sign.y = _roadShowArray[i].y * 48;
_roadSprite.addChild(sign);
}
}
}

_roadQuery方法中,移动力和起始坐标都根据当前人物得到
public function makePath(chara:Character):Array {
_chara = chara;
_path = [];
var isOver:Boolean = false;
setStart();
_starPoint = _map[Math.floor(chara.characterMC.y/48)][Math.floor(chara.characterMC.x/48)];
_starPoint.moveLong = chara.moveLong;
loopPath(_starPoint);
return _path;
}
然后,在loopPath方法中,做最后的修改
checkPoint.moveLong = thisPoint.moveLong - 1;是用来计算下一个点的剩余移动力的,
之前,所有点的移动力都是由当前点的移动力-1
把它改为
var cost:int = int(XML(Sav.gamedata["Arms"])["Arms" + _chara.armsIndex]["Terrain"]["Terrain" + _map[checkPoint.y][checkPoint.x].value]);
checkPoint.moveLong = thisPoint.moveLong - cost;
就是减去下一个点的消耗移动力,这个消耗移动力在兵种数据文件中已经设定好了,直接读取就可以了
运行代码,效果如下

预览

下次,该研究一下,加入敌军的人物问题了

其实,加入敌军人物,只需要在1S.xml中加入几个人物就可以了
<Our>
<List x="10" y="4">1</List>
<List x="10" y="5">98</List>
</Our>
<Enemy>
<List x="12" y="5">100</List>
<List x="16" y="5">103</List>
</Enemy>
然后配置好,相应的兵种数据和人物数据,就可以在战场上显示了
剩下的还要改动一下寻路的方法,把战场上有人物的地方,改为消耗移动力100

public function makePath(chara:Character):Array {
_chara = chara;
_path = [];
var isOver:Boolean = false;
setStart();
_enemyCost = new Object();
var i:int = 0;
var objarr:Array;
objarr = _fightMap.enemyArr;
for(i=0;i<objarr.length;i++){
_enemyCost[objarr[i].locationX + "-" +objarr[i].locationY] = 100;
}
objarr = _fightMap.ourArr;
for(i=0;i<objarr.length;i++){
_enemyCost[objarr[i].locationX + "-" +objarr[i].locationY] = 100;
}
_starPoint = _map[Math.floor(chara.character.y/48)][Math.floor(chara.character.x/48)];
_starPoint.moveLong = chara.moveLong;
loopPath(_starPoint);

return _path;
}

public function loopPath(thisPoint:Object):void{
if(thisPoint.moveLong <= 0){
return;
}

if(! thisPoint.isChecked){
_path.push(thisPoint);
thisPoint.isChecked = true;
}
var checkList:Array = [];
//获取周围四个点
if (thisPoint.y>0) {
checkList.push(_map[(thisPoint.y-1)][thisPoint.x]);
}
if (thisPoint.x>0) {
checkList.push(_map[thisPoint.y][(thisPoint.x-1)]);
}
if (thisPoint.x<_w-1) {
checkList.push(_map[thisPoint.y][(thisPoint.x+1)]);
}
if (thisPoint.y<_h-1) {
checkList.push(_map[(thisPoint.y+1)][thisPoint.x]);
}
for(var i=0;i<checkList.length;i++){
var checkPoint:Object = checkList[i];
if(!checkPoint.isChecked || checkPoint.moveLong < thisPoint.moveLong){
var cost:int = int(XML(Sav.gamedata["Arms"])["Arms" + _chara.armsIndex]["Terrain"]["Terrain" + _map[checkPoint.y][checkPoint.x].value]);
cost += _enemyCost[checkPoint.x + "-" + checkPoint.y] == null ? 0:_enemyCost[checkPoint.x + "-" + checkPoint.y];
checkPoint.moveLong = thisPoint.moveLong - cost;
loopPath(checkPoint);
}
}
}
这样战场上有人的地方就移动不过去了

接下来,来给每个人加上攻击范围的光标
准备好攻击范围显示的光标MC

素材

然后,在相应的兵种数据中加上攻击范围的控制
如英雄
<Arms1>
<Name>英雄</Name>
<Property>
<Attack>A</Attack>
<Spirit>A</Spirit>
<Defense>A</Defense>
<Breakout>A</Breakout>
<Morale>A</Morale>
</Property>
<Terrain>
<Terrain0>1</Terrain0>
<Terrain1>1</Terrain1>
<Terrain2>2</Terrain2>
<Terrain3>100</Terrain3>
<Terrain4>100</Terrain4>
<Terrain5>1</Terrain5>
<Terrain6>1</Terrain6>
<Terrain7>1</Terrain7>
</Terrain>
<RangeAttack>
<List>0,-1</List>
<List>0,1</List>
<List>-1,0</List>
<List>1,0</List>
</RangeAttack>
</Arms1>
其中RangeAttack代表以当前人物为坐标的相对攻击范围
然后在战场类中加一个函数
//攻击范围显示
private function setAttRound(armIndex:int):void{
var attRoundArr:Array;
var attRound:AttBox;
for each ( var roundment:XML in _arms["Arms" + armIndex]["RangeAttack"].elements( ) ) {
attRound = new AttBox();
attRoundArr = roundment.toString().split(",");
attRound.x = (int(attRoundArr[0]) + _nowChatacter.locationX )*48;
attRound.y = (int(attRoundArr[1]) + _nowChatacter.locationY) *48;
_roadSprite.addChild(attRound);
}

}
其中AttBox是预先准备好的攻击范围显示的光标MC
然后,在寻找最大行动范围的时候,调用这个函数
就可以显示攻击范围了,效果如图

预览

接下来,研究一下回合控制,和敌军回合的时候,敌军的行动

这次除了添加一些东西外,改动也比较大
具体改了哪里,也忘了做记录了
最后成形的战场类代码如下FightMap .as

package Caocao.Mains{
import Lufy.Images.ImageCtrl;
import Lufy.Sprite.SpriteRemove;
import Caocao.Character.CharacterMC;
import Caocao.Character.Character;
import Caocao.ot.RoadQuery;
import Lufy.Xml.XMLLoader;

import flash.net.URLLoader;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
import flash.net.URLRequest;
import flash.geom.Point;
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.events.KeyboardEvent;
import flash.text.*;

public class FightMap extends Sprite {
//最底层Sprite
private var _bakSprite:Sprite;
//地图Sprite
private var _mapSprite:Sprite;
//人物Sprite
private var _characterSprite:Sprite;
//通路Sprite
private var _roadSprite:Sprite;
//战场Xml
private var _fightXml:XML;
//地形数组
private var _mapData:Array;
//图片载入器
private var _pic_loader:Loader;
//xml载入器
private var _xml_loader:XMLLoader;
//声明Bitmap
private var _image:Bitmap;
//大地图Bitmap
private var _bmapimage:Bitmap;
//人物类
private var _character:Character;
private var _characterMC:CharacterMC;
private var _nowChatacter:Character;
//我军数组
private var _ourArr:Array;
//敌军数组
private var _enemyArr:Array;
//寻路类
private var _roadQuery:RoadQuery;
//储存路径数组
private var _roadArray:Array;
//表示路径数组
private var _roadShowArray:Array;
//人物移动控制
private var _xadd:int = 0;
private var _yadd:int = 0;
//人物移动步长
private var _addLeng:int = 4;
//移动起始坐标
private var _nowPoint:Point;
//移动起始方向
private var _nowDirection:int;
//移动目的地坐标
private var _toPoint:Point;
//点击动作控制
private var _clickCtrl:String = "NULL";
//人物数据
private var _pXml:XML;
//地形数据
private var _terrain:XML;
//兵种数据
private var _arms:XML;
//选择菜单
private var _selectBox:SelectBox;
//地图移动速度控制
private var _mapMoveCtrl:int = 0;
//地图移动用xy步长
private var _mapXadd:int = 0;
private var _mapYadd:int = 0;
//地形框
private var _terrainBox:TerrainShowBox;
//回合控制
private var _roundCtrl:String = "我方回合";
//回合数
private var _roundIndex:int = 1;
//鼠标框
private var _mouseBox:MouseBox;
//敌方行动控制用
private var _enemyActionCtrl:int = 0;
//回合显示信息
private var _roundShow:TextField ;
//回合显示信息控制用
private var _roundShowCtrl:int = 0;
public function FightMap(mapXmlSrc:String,fun:Function,gameMap:GameStart) {
//添加显示Sprite
_bakSprite = new Sprite();
addChild(_bakSprite);
_mapSprite = new Sprite();
_bakSprite.addChild(_mapSprite);
_characterSprite = new Sprite();
_bakSprite.addChild(_characterSprite);
_roadSprite = new Sprite();
_bakSprite.addChild(_roadSprite);

_mouseBox = new MouseBox();
_bakSprite.addChild(_mouseBox);

_selectBox = new SelectBox();
_bakSprite.addChild(_selectBox);

_terrainBox = new TerrainShowBox();
addChild(_terrainBox);

textInit();

//菜单事件
//点击停止事件
_selectBox.btnStop.addEventListener(MouseEvent.CLICK, charaStopHandler);
//点击取消事件
_selectBox.btnCan.addEventListener(MouseEvent.CLICK, charaCanHandler);
//菜单隐藏
_selectBox.visible = false;


//地形显示框隐藏
_terrainBox.visible = false;

//得到所有人物数据
_pXml = Sav.gamedata["people"] as XML;
//得到所有地形数据
_terrain = Sav.gamedata["Terrain"] as XML;
//得到所有兵种数据
_arms = Sav.gamedata["Arms"] as XML;

//鼠标点击事件
_bakSprite.addEventListener(MouseEvent.CLICK,onClick);
//贞事件
this.addEventListener(Event.ENTER_FRAME, mapMoveHandler);

//鼠标移动事件
addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
//鼠标移动事件
_bakSprite.addEventListener(MouseEvent.MOUSE_MOVE, mouseBakMoveHandler);

//载入人物属性Xml
_xml_loader = new XMLLoader();
_xml_loader.onLoadComplete = initStage;
_xml_loader.load(mapXmlSrc, XMLLoader.GB2312);
}
//文本格式
private function textInit():void{

_roundShow = new TextField();
_roundShow.autoSize = TextFieldAutoSize.LEFT;
var formatter:TextFormat = new TextFormat( );
formatter.color = 0xCCCCCC;
formatter.size = 60;
formatter.bold = true;
_roundShow.defaultTextFormat = formatter;
_roundShow.text = "";
addChild(_roundShow);
}
//贞事件
private function mapMoveHandler(event:Event):void{
if(_mapMoveCtrl > 5){
//根据地图移动用xy步长移动地图
_bakSprite.x += _mapXadd;
_bakSprite.y += _mapYadd;
_mapMoveCtrl = 0;
}
//控制地图不移出指定范围
if(_bakSprite.x > 0){
_bakSprite.x = 0;
}else if( _bakSprite.x < Sav.gamedata["stageWidth"] - _bakSprite.width){
_bakSprite.x = Sav.gamedata["stageWidth"] - _bakSprite.width;
}
if(_bakSprite.y > 0){
_bakSprite.y = 0;
}else if( _bakSprite.y < Sav.gamedata["stageHeight"] - _bakSprite.height){
_bakSprite.y = Sav.gamedata["stageHeight"] - _bakSprite.height;
}
if(_roundShowCtrl == 0){
_roundShow.text = "第" + _roundIndex + "回合/n";
_roundShow.x = (Sav.gamedata["stageWidth"] - _roundShow.width)/2;
_roundShow.y = (Sav.gamedata["stageHeight"] - _roundShow.height)/2;
}else if(_roundShowCtrl == 40){
_roundShow.text = "/n" + _roundCtrl;
_roundShow.x = (Sav.gamedata["stageWidth"] - _roundShow.width)/2;
_roundShow.y = (Sav.gamedata["stageHeight"] - _roundShow.height)/2;
}else if(_roundShowCtrl == 80){
_roundShow.text = "";
if(_roundCtrl == "我方回合"){
_bakSprite.addEventListener(MouseEvent.CLICK,onClick);
}elseif(_roundCtrl == "敌方回合"){
addEventListener(Event.ENTER_FRAME, onEnemyFrame);
}
}
_roundShowCtrl++;
_mapMoveCtrl ++;
}
//鼠标移动事件
private function mouseBakMoveHandler(event:MouseEvent):void{
var intX:int = event.currentTarget.mouseX;
var intY:int = event.currentTarget.mouseY;
_mouseBox.x = Math.floor(intX/48)*48;
_mouseBox.y = Math.floor(intY/48)*48;
}
//鼠标移动事件
private function mouseMoveHandler(event:MouseEvent):void{
var intX:int = event.currentTarget.mouseX;
var intY:int = event.currentTarget.mouseY;
if(intX < 48){
_mapXadd = 48;
}elseif(intX > Sav.gamedata["stageWidth"] - 48 && intX <= Sav.gamedata["stageWidth"]){
_mapXadd = -48;
}else{
_mapXadd = 0;
}
if(intY < 48){
_mapYadd = 48;
}elseif(intY > Sav.gamedata["stageHeight"] - 48 && intY <= Sav.gamedata["stageHeight"]){
_mapYadd = -48;
}else{
_mapYadd = 0;
}
if(_terrainBox.visible){
_clickCtrl = "NULL";
_terrainBox.visible = false;
_bakSprite.addEventListener(MouseEvent.CLICK,onClick);
}
if(_clickCtrl == "ENEMY_ROUND_SHOW"){
_clickCtrl = "NULL";
SpriteRemove.removeAllChildren(_roadSprite);
_bakSprite.addEventListener(MouseEvent.CLICK,onClick);
}
}

//用来重新载入点击事件
private function onClickFrame(event:Event):void {
removeEventListener(Event.ENTER_FRAME, onClickFrame);
var ctrl:Boolean = false;
var i:int;
for(i = 0;i<_ourArr.length;i++){
if(!_ourArr[i].actionCtrl){
ctrl = true;
break;
}
}
if(!ctrl){
_roundCtrl = "敌方回合";
for(i=0;i<_enemyArr.length;i++){
_enemyArr[i].actionCtrl = false;
}
_enemyActionCtrl = 0;
//addEventListener(Event.ENTER_FRAME, onEnemyFrame);
_roundShowCtrl = 40;
}else{
_bakSprite.addEventListener(MouseEvent.CLICK,onClick);
}
}

//控制敌军行动事件
private function onEnemyFrame(event:Event):void {
var i:int;
var toDistance:int;
var checkDistance:int;
if(_clickCtrl == "NULL"){
_nowChatacter = null;
//寻找未行动人员
for(i=0;i<_enemyArr.length;i++){
if(!_enemyArr[i].actionCtrl){
_nowChatacter = _enemyArr[i];
break;
}
}
//如果全部行动完毕,则进入我军回合
if(_nowChatacter == null){
_roundCtrl = "我方回合";
for(i=0;i<_ourArr.length;i++){
_ourArr[i].actionCtrl = false;
}
removeEventListener(Event.ENTER_FRAME, onEnemyFrame);
_roundIndex ++;
_roundShowCtrl = 0;
return;
}
if(_enemyActionCtrl == 0){
//得到为行动人员,开始寻路显示
_clickCtrl = "ROAD_SHOW";
setRoad(_nowChatacter);
}
}
if(_clickCtrl == "ROAD_SHOW" && _enemyActionCtrl == 10){
//开始行动
_toPoint = new Point(_roadShowArray[0].x,_roadShowArray[0].y);
i = Math.random() * _ourArr.length;
_character = _ourArr[i];
toDistance = Math.abs(_character.locationX - _toPoint.x) + Math.abs(_character.locationY - _toPoint.y) ;
for(i=1;i<_roadShowArray.length;i++){
checkDistance = Math.abs(_character.locationX - _roadShowArray[i].x) + Math.abs(_character.locationY - _roadShowArray[i].y) ;
if(checkDistance < toDistance){
toDistance = checkDistance;
_toPoint.x = _roadShowArray[i].x;
_toPoint.y = _roadShowArray[i].y;
}
}
_nowPoint = new Point( _nowChatacter.locationX, _nowChatacter.locationY);
_nowDirection = _characterMC.getDir();
charaToMove();
}
_enemyActionCtrl ++;

}
//点击停止事件
private function charaStopHandler(event:MouseEvent):void{
_clickCtrl = "NULL";
_nowChatacter.actionCtrl = true;
_selectBox.visible = false;
addEventListener(Event.ENTER_FRAME, onClickFrame);
}
//点击取消事件
private function charaCanHandler(event:MouseEvent):void{
_clickCtrl = "NULL";
_selectBox.visible = false;
_characterMC = _nowChatacter.character;
_characterMC.x = _nowPoint.x * 48;
_characterMC.y = _nowPoint.y * 48;
_characterMC.setDir(_nowDirection);
addEventListener(Event.ENTER_FRAME, onClickFrame);
}

//寻找最大移动范围
private function setRoad(chara:Character){
_roadShowArray = _roadQuery.makePath(chara);

if(_roadShowArray != null && _roadShowArray.length > 0){
var sign:Sign;
for(var i:int = 0;i<_roadShowArray.length;i++){
sign = new Sign();
sign.x = _roadShowArray[i].x * 48;
sign.y = _roadShowArray[i].y * 48;
_roadSprite.addChild(sign);
}
setAttRound(_pXml["peo" + _nowChatacter.charaIndex].Arms);
}
}
//攻击范围显示
private function setAttRound(armIndex:int):void{
var attRoundArr:Array;
var attRound:AttBox;
for each ( var roundment:XML in _arms["Arms" + armIndex]["RangeAttack"].elements( ) ) {
attRound = new AttBox();
attRoundArr = roundment.toString().split(",");
attRound.x = (int(attRoundArr[0]) + _nowChatacter.locationX )*48;
attRound.y = (int(attRoundArr[1]) + _nowChatacter.locationY) *48;
_roadSprite.addChild(attRound);
}

}
//鼠标点击事件
private function onClick(event:Event):void{
var __mouseX:Number = event.currentTarget.mouseX;
var __mouseY:Number = event.currentTarget.mouseY;
var i:int;
if(_clickCtrl == "NULL"){
var queryPeople:Boolean = false;
//点击我军人物判断
for(i=0;i<_ourArr.length;i++){
_character = _ourArr[i] as Character;
_characterMC = _character.character;
if(Math.floor(_characterMC.x/48) == Math.floor(__mouseX/48) && Math.floor(_characterMC.y/48) == Math.floor(__mouseY/48)){
_nowChatacter = _character;
setRoad(_nowChatacter);
_clickCtrl = "ROAD_SHOW";
_bakSprite.removeEventListener(MouseEvent.CLICK,onClick);
_roadSprite.addEventListener(MouseEvent.CLICK,onClick);
queryPeople = true;
break;
}
}
//点击敌军人物判断
for(i=0;i<_enemyArr.length && !queryPeople;i++){
_character = _enemyArr[i] as Character;
_characterMC = _character.character;
if(Math.floor(_characterMC.x/48) == Math.floor(__mouseX/48) && Math.floor(_characterMC.y/48) == Math.floor(__mouseY/48)){
_nowChatacter = _character;
setRoad(_nowChatacter);
_clickCtrl = "ENEMY_ROUND_SHOW";
_bakSprite.removeEventListener(MouseEvent.CLICK,onClick);
queryPeople = true;
break;
}
}
if(!queryPeople){
//点击地图,显示地形
_clickCtrl = "TERRAIN_SHOW";
var mapX:int = Math.floor(__mouseX/48);
var mapY:int = Math.floor(__mouseY/48);
var terrainId:int = _mapData[mapY][mapX];
var terrainName:String = "Terrain" + terrainId;
_terrainBox.x = mapX *48 - 48 + _bakSprite.x;
_terrainBox.y = mapY*48 - 48 + _bakSprite.y;
if(_terrainBox.x < 0){
_terrainBox.x = 0;
}else if(_terrainBox.x > Sav.gamedata["stageWidth"] - 144){
_terrainBox.x = Sav.gamedata["stageWidth"] - 144;
}
if(_terrainBox.y < 0){
_terrainBox.y = 0;
}else if(_terrainBox.y > Sav.gamedata["stageHeight"] - 144){
_terrainBox.y = Sav.gamedata["stageHeight"] - 144;
}
_terrainBox.TerrainName.text = _terrain[terrainName];
SpriteRemove.removeAllChildren(_terrainBox.TerrainShow);
_terrainBox.TerrainShow.addChild(ImageCtrl.getImage(_bmapimage,mapX*48,mapY*48,48,48));
_bakSprite.removeEventListener(MouseEvent.CLICK,onClick);
_terrainBox.visible = true;
}
}else if(_clickCtrl == "ROAD_SHOW"){
_characterMC = _nowChatacter.character;
for(i=0;i<_roadShowArray.length;i++){
_nowPoint = new Point(_nowChatacter.locationX,_nowChatacter.locationY);
_nowDirection = _characterMC.getDir();
_toPoint = new Point(Math.floor(__mouseX/48),Math.floor(__mouseY/48));
charaToMove();
}
}


}
//当前人物开始移动
private function charaToMove():void{
_roadArray = _roadQuery.path4(_nowPoint,_toPoint,_roadShowArray);
if(_roadArray != null && _roadArray.length > 0){
addEventListener(Event.ENTER_FRAME, onFrame);
_clickCtrl == "MOVE_NOW"
SpriteRemove.removeAllChildren(_roadSprite);
if(_roundCtrl == "我方回合"){
_roadSprite.removeEventListener(MouseEvent.CLICK,onClick);
}
}
}
//人物移动事件贞控制
private function onFrame(event:Event):void {
_characterMC = _nowChatacter.character;
if(_roadArray != null && _roadArray.length > 1){
if(_characterMC.x % 48 == 0 && _characterMC.y % 48 == 0){
if(_roadArray[0].x == _roadArray[1].x){
if(_roadArray[0].y > _roadArray[1].y){
_characterMC.setDir(0);
_xadd = 0;
_yadd = -_addLeng;
}else{
_characterMC.setDir(1);
_xadd = 0;
_yadd = _addLeng;
}
}else{
if(_roadArray[0].x > _roadArray[1].x){
_characterMC.setDir(2);
_xadd = -_addLeng;
_yadd = 0;
}else{
_characterMC.setDir(3);
_xadd = _addLeng;
_yadd = 0;
}
}

_roadArray.splice(0,1);

}
_characterMC.x += _xadd;
_characterMC.y += _yadd;

}else if(_characterMC.x % 48 == 0 && _characterMC.y % 48 == 0){
removeEventListener(Event.ENTER_FRAME, onFrame);
if(_roundCtrl == "我方回合"){
_selectBox.visible = true;
_selectBox.x = _characterMC.x + 48;
_selectBox.y = _characterMC.y;
}else if(_roundCtrl == "敌方回合"){
_nowChatacter.actionCtrl = true;
_enemyActionCtrl = 0;
_clickCtrl = "NULL";
addEventListener(Event.ENTER_FRAME, onEnemyFrame);
}
}else{

_characterMC.x += _xadd;
_characterMC.y += _yadd;
}
}

//得到战场xml信息
private function initStage(xml:XML):void{
_fightXml = xml;
_mapData= new Array();
//根据xml内容,得到地形数组
for each ( var datement:XML in _fightXml.DataMap.elements( ) ) {
var dates:Array = ("" + datement).split( ",");
_mapData.push(dates);
}
_roadQuery = new RoadQuery(this);

//我军人物添加
_ourArr = new Array();
//根据xml内容,得到我军人物,添加至战场
for each ( var ourment:XML in _fightXml.Our.elements( ) ) {
var ourId:int = int(ourment);
var ourchara:XML = XML(_pXml["peo" + ourId]);
_characterMC = new CharacterMC(ourId);
_characterMC.x = int(ourment.@x)*48;
_characterMC.y = int(ourment.@y)*48;
_character = new Character(_characterMC,int(ourchara.Move),int(ourchara.sImage),int(ourchara.Arms));
_characterSprite.addChild(_characterMC);
_ourArr.push(_character);
}
//敌军人物添加
_enemyArr = new Array();
//根据xml内容,得到敌军人物,添加至战场
for each ( var enemyment:XML in _fightXml.Enemy.elements( ) ) {
var enemyId:int = int(enemyment);
var enemychara:XML = XML(_pXml["peo" + enemyId]);
_characterMC = new CharacterMC(enemyId);
_characterMC.x = int(enemyment.@x)*48;
_characterMC.y = int(enemyment.@y)*48;
_character = new Character(_characterMC,int(enemychara.Move),int(enemychara.sImage),int(enemychara.Arms));
_characterSprite.addChild(_characterMC);
_enemyArr.push(_character);
}
//加载地图
_pic_loader = new Loader();
_pic_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteMap);
var mapName:String = "Images/HM/" + _fightXml.Map + ".gif";
_pic_loader.load(new URLRequest(mapName));
}
//加载地图完毕
private function onCompleteMap(event:Event):void {
_pic_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompleteMap);
_bmapimage = Bitmap(_pic_loader.content);
_mapSprite.addChild(_bmapimage);

}
public function get map():Array{
return _mapData;
}
public function get roundCtrl():String{
return _roundCtrl;
}
public function get enemyArr():Array{
return _enemyArr;
}
public function get ourArr():Array{
return _ourArr;
}

}
}

效果如下图
预览

预览

预览

暂时,敌军只会跟随我军某个人物移动,等下面再慢慢研究敌方的AI
下次,在战场上显示人物的攻击防御等属性:)

要显示人物属性了,把相应的人物数据和兵种数据改好,如下<?xml version="1.0" encoding="GB2312"?>
<data>
<peo1>
<Name>曹操</Name>
<Arms>1</Arms>
<Lv>1</Lv>
<Exp>0</Exp>
<HP>124</HP>
<MP>85</MP>
<Move>5</Move>
<Face>1</Face>
<sImage>1</sImage>
<Force>80</Force>
<Intelligence>96</Intelligence>
<Command>98</Command>
<Agile>83</Agile>
<Luck>88</Luck>
<Attack>82</Attack>
<Spirit>92</Spirit>
<Defense>80</Defense>
<Breakout>85</Breakout>
<Morale>80</Morale>
<Introduction></Introduction>
</peo1>
......
<?xml version="1.0" encoding="GB2312"?>
<data>
<Arms1>
<Name>英雄</Name>
<Property>
<Attack>A</Attack>
<Spirit>A</Spirit>
<Defense>A</Defense>
<Breakout>A</Breakout>
<Morale>A</Morale>
</Property>
<Weapon>剑</Weapon>
<Equipment>铠甲</Equipment>
<Terrain>
<Terrain0>1</Terrain0>
<Terrain1>1</Terrain1>
<Terrain2>2</Terrain2>
<Terrain3>100</Terrain3>
<Terrain4>100</Terrain4>
<Terrain5>1</Terrain5>
<Terrain6>1</Terrain6>
<Terrain7>1</Terrain7>
</Terrain>
<RangeAttack>
<List>0,-1</List>
<List>0,1</List>
<List>-1,0</List>
<List>1,0</List>
</RangeAttack>
<Introduction></Introduction>
</Arms1>
......
在data.xml中设定升级所需EXP和能力上限值
<?xml version="1.0" encoding="GB2312"?>
<data>
<varlable>255</varlable>
<MaxExp>100</MaxExp>
<MaxAbility>1000</MaxAbility>
</data>
然后,就像.net编辑From一样,开始准备所需要的MC
素材

素材

在读取完data.xml时,把需要的升级所需EXP和能力上限值保存,方便随时取用
Sav.gamedata["MaxAbility"] = xml.MaxAbility;
Sav.gamedata["MaxExp"] = xml.MaxExp;
战场上,把整个战场向下移动48个像素,用来仿照曹操传放置按钮,
在曹操传中,左击鼠标用来察看人物属性,但是flash中是没有办法弄成这样的,至少现在不能,因为flash左击鼠标,会弹出flash菜单
所以,我在最上面的菜单上,放置了两个按钮,用来察看我军和敌军属性,按钮用了普通的士兵S形象,点击我军或者敌军的S形象按钮就能察看我军和敌军的属性了
//查看武将-我军按钮
_ourShow = new PeopleShow();
_ourShow.x = 500;
addChild(_ourShow);
_ourShow.addEventListener(MouseEvent.CLICK, ourShowHandler);
//查看武将-敌军按钮
_enemyShow = new PeopleShowEnemy();
_enemyShow.x = 548;
addChild(_enemyShow);
_enemyShow.addEventListener(MouseEvent.CLICK, enemyShowHandler);

然后添加现实HP,MP和人物属性的MC
_hpmp = new HPMP();
_bakSprite.addChild(_hpmp);
_hpmp.visible = false;
这个HPMP,是用来显示当前的HP和MP的MC,就是上面一开始准备的第一个图
//查看武将MC
_peopleShow = new CharacterProperty();
_peopleShow.x = (Sav.gamedata["stageWidth"] - _peopleShow.width)/2;
_peopleShow.y = (Sav.gamedata["stageHeight"] - _peopleShow.height)/2;
this.addChild(_peopleShow);
_peopleShow.btnGenerals.visible = false;
_peopleShow.visible = false;
这个CharacterProperty就是准备好的显示人物属性的MC,就是上面的第二个图


当鼠标移动到我军或敌军身上时,就显示其HP和MP

//鼠标移动事件
private function mouseBakMoveHandler(event:MouseEvent):void{
var intX:int = event.currentTarget.mouseX;
var intY:int = event.currentTarget.mouseY;
_mouseBox.x = Math.floor(intX/48)*48;
_mouseBox.y = Math.floor(intY/48)*48;
var queryPeople:Boolean = false;
var i:int;
for(i=0;i<_ourArr.length;i++){
_character = _ourArr[i] as Character;
if(_character.x == _mouseBox.x && _character.y == _mouseBox.y){
_nowChatacter = _character;
queryPeople = true;
break;
}
}

for(i=0;i<_enemyArr.length && !queryPeople;i++){
_character = _enemyArr[i] as Character;
if(_character.x == _mouseBox.x && _character.y == _mouseBox.y){
_nowChatacter = _character;
queryPeople = true;
break;
}
}
if(!queryPeople){
_hpmp.visible = false;
}else{
_hpmp.visible = true;
_hpmp.x = _mouseBox.x - 102;
_hpmp.y = _mouseBox.y - 48;
if(_hpmp.x < 0){
_hpmp.x = 0;
}
if(_hpmp.y < 0){
_hpmp.y = 0;
}
_hpmp.txtHP.text = _nowChatacter.nowHP + "/" + _nowChatacter.HP;
_hpmp.spHP.width = 100 * (_nowChatacter.nowHP/_nowChatacter.HP);
_hpmp.txtMP.text = _nowChatacter.nowMP + "/" + _nowChatacter.MP;
_hpmp.spMP.width = 100 * (_nowChatacter.nowMP/_nowChatacter.MP);
}
}

添加好点击事件,显示人物属性时,实现相应的切换

_peopleShow.visible = false;
//添加各个按钮点击事件
_peopleShow.btnGenerals.addEventListener(MouseEvent.CLICK, onClickGenerals);
_peopleShow.btnForce.addEventListener(MouseEvent.CLICK, onClickForce);
_peopleShow.btnAbility.addEventListener(MouseEvent.CLICK, onClickAbility);
_peopleShow.btnEquipment.addEventListener(MouseEvent.CLICK, onClickEquipment);
_peopleShow.btnTactics.addEventListener(MouseEvent.CLICK, onClickTactics);
_peopleShow.btnClose.addEventListener(MouseEvent.CLICK, onClickClose);
_peopleShow.btnLast.addEventListener(MouseEvent.CLICK, onClickLast);
_peopleShow.btnNext.addEventListener(MouseEvent.CLICK, onClickNext);


//察看武将-按钮全部显示
private function _peopleBtnToTrue(){
_peopleShow.btnGenerals.visible = true;
_peopleShow.btnForce.visible = true;
_peopleShow.btnAbility.visible = true;
_peopleShow.btnEquipment.visible = true;
_peopleShow.btnTactics.visible = true;

}
//察看武将-点击上一武将
private function onClickLast(event:MouseEvent):void{
peopleShowFromIndex(-1);
}
//察看武将-点击下一武将
private function onClickNext(event:MouseEvent):void{
peopleShowFromIndex(1);
}
//察看武将-点击关闭
private function onClickClose(event:MouseEvent):void{
if(_peopleShow.btnGenerals.visible){
_peopleShow.gotoAndStop(1);
}
_peopleShow.visible = false;
}
//察看武将-点击武将列传
private function onClickGenerals(event:MouseEvent):void{
_peopleShow.gotoAndStop(1);
_peopleBtnToTrue();
_peopleShow.btnGenerals.visible = false;
setGenerals();
}
//察看武将-点击部队属性
private function onClickForce(event:MouseEvent):void{
_peopleShow.gotoAndStop(2);
_peopleBtnToTrue();
_peopleShow.btnForce.visible = false;
setForce();
}
//察看武将-点击能力
private function onClickAbility(event:MouseEvent):void{
_peopleShow.gotoAndStop(3);
_peopleBtnToTrue();
_peopleShow.btnAbility.visible = false;
setAbility();
}
//察看武将-点击装备
private function onClickEquipment(event:MouseEvent):void{
_peopleShow.gotoAndStop(4);
_peopleBtnToTrue();
_peopleShow.btnEquipment.visible = false;
setEquipment();
}
//察看武将-点击策略
private function onClickTactics(event:MouseEvent):void{
_peopleShow.gotoAndStop(5);
_peopleBtnToTrue();
_peopleShow.btnTactics.visible = false;
setTactics();
}


//察看我军
private function ourShowHandler(event:MouseEvent):void{
_peopleShowIndex= 0;
_peopleShowCtrl = "Our";
peopleShowFromIndex(0);
}
//察看敌军
private function enemyShowHandler(event:MouseEvent):void{
_peopleShowIndex = 0;
_peopleShowCtrl = "Enemy";
peopleShowFromIndex(0);
}
//根据人物序号显示人物属性
private function peopleShowFromIndex(addIndex:int):void{
_peopleShowIndex += addIndex;
if(_peopleShowCtrl == "Our"){
if(_peopleShowIndex < 0){
_peopleShowIndex = _ourArr.length - 1;
}else if(_peopleShowIndex >= _ourArr.length){
_peopleShowIndex = 0;
}
_nowChatacter = _ourArr[_peopleShowIndex] as Character;
_peopleShow.txtForceShow.text = "我军";
}else if(_peopleShowCtrl == "Enemy"){
if(_peopleShowIndex < 0){
_peopleShowIndex = _enemyArr.length - 1;
}else if(_peopleShowIndex >= _enemyArr.length){
_peopleShowIndex = 0;
}
_nowChatacter = _enemyArr[_peopleShowIndex] as Character;
_peopleShow.txtForceShow.text = "敌军";
}
_peopleShow.txtName.text = _pXml["peo" + _nowChatacter.charaIndex].Name.toString();
_peopleShow.txtArms.text = _pXml["peo" + _nowChatacter.charaIndex].Arms.toString();
_peopleShow.txtLv.text = _pXml["peo" + _nowChatacter.charaIndex].Lv.toString();
_peopleShow.txtExp.text = _pXml["peo" + _nowChatacter.charaIndex].Exp + "/" + Sav.gamedata["MaxExp"];
_peopleShow.spExp.width = 50 * (int(_pXml["peo" + _nowChatacter.charaIndex].Exp)/int(Sav.gamedata["MaxExp"]));
_peopleShow.txtHP.text = _nowChatacter.nowHP + "/" + _nowChatacter.HP;
_peopleShow.spHP.width = 100 * (_nowChatacter.nowHP/_nowChatacter.HP);
_peopleShow.txtMP.text = _nowChatacter.nowMP + "/" + _nowChatacter.MP;
_peopleShow.spMP.width = 100 * (_nowChatacter.nowMP/_nowChatacter.MP);
_peopleShow.txtStatus.text = _nowChatacter.getfStatus();
for(var i:int = 0;i<_nowChatacter.statusArr.length;i++){
_peopleShow.txtStatus.appendText(_nowChatacter.statusArr[0] + "");
}

//加载人物头像
var faceStr:String = "Images/Face/" + _pXml["peo" + _nowChatacter.charaIndex].Face.toString().split(",")[0] + ".gif";
_pic_loader = new Loader();
_pic_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteFace);
_pic_loader.load(new URLRequest(faceStr));
if(!_peopleShow.btnGenerals.visible){
setGenerals();
}else if(!_peopleShow.btnForce.visible){
setForce();
}else if(!_peopleShow.btnAbility.visible){
setAbility();
}else if(!_peopleShow.btnEquipment.visible){
setEquipment();
}else if(!_peopleShow.btnTactics.visible){
setTactics();
}
}
//加载人物头像完毕
private function onCompleteFace(event:Event):void {
_pic_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompleteFace);
_image = Bitmap(_pic_loader.content);
SpriteRemove.removeAllChildren(_peopleShow.faceImage);
_peopleShow.faceImage.addChild(_image);
_peopleShow.visible = true;
}
//察看武将-显示武将列传
private function setGenerals():void{
_peopleShow.txtForce.text = _pXml["peo" + _nowChatacter.charaIndex].Force.toString();
_peopleShow.txtIntelligence.text = _pXml["peo" + _nowChatacter.charaIndex].Intelligence.toString();
_peopleShow.txtCommand.text = _pXml["peo" + _nowChatacter.charaIndex].Command.toString();
_peopleShow.txtAgile.text = _pXml["peo" + _nowChatacter.charaIndex].Agile.toString();
_peopleShow.txtLuck.text = _pXml["peo" + _nowChatacter.charaIndex].Luck.toString();
_peopleShow.txtIntroduction.text = _pXml["peo" + _nowChatacter.charaIndex].Introduction.toString();
}
//察看武将-显示部队属性
private function setForce():void{
_peopleShow.txtAttack.text = _arms["Arms" + _nowChatacter.armsIndex].Property.Attack.toString();
_peopleShow.txtSpirit.text = _arms["Arms" + _nowChatacter.armsIndex].Property.Spirit.toString();
_peopleShow.txtDefense.text = _arms["Arms" + _nowChatacter.armsIndex].Property.Defense.toString();
_peopleShow.txtBreakout.text = _arms["Arms" + _nowChatacter.armsIndex].Property.Breakout.toString();
_peopleShow.txtMorale.text = _arms["Arms" + _nowChatacter.armsIndex].Property.Morale.toString();
_peopleShow.txtArmsPro.text = _arms["Arms" + _nowChatacter.armsIndex].Introduction.toString();
_peopleShow.txtArms2.text = _pXml["peo" + _nowChatacter.charaIndex].Arms.toString();
_peopleShow.txtWeapon.text = _arms["Arms" + _nowChatacter.armsIndex].Weapon.toString();
_peopleShow.txtEquipment.text = _arms["Arms" + _nowChatacter.armsIndex].Equipment.toString();
SpriteRemove.removeAllChildren(_peopleShow.armsImage);
_peopleShow.armsImage.addChild(new Bitmap(_nowChatacter.character.getBitmapData()));
}
//察看武将-显示能力
private function setAbility():void{
_peopleShow.txtAttack1.text = _pXml["peo" + _nowChatacter.charaIndex].Attack.toString();
_peopleShow.txtSpirit1.text = _pXml["peo" + _nowChatacter.charaIndex].Spirit.toString();
_peopleShow.txtDefense1.text = _pXml["peo" + _nowChatacter.charaIndex].Defense.toString();
_peopleShow.txtBreakout1.text = _pXml["peo" + _nowChatacter.charaIndex].Breakout.toString();
_peopleShow.txtMorale1.text = _pXml["peo" + _nowChatacter.charaIndex].Morale.toString();
_peopleShow.spAttack1.width = 100 * int(_pXml["peo" + _nowChatacter.charaIndex].Attack) / int(Sav.gamedata["MaxAbility"]);
_peopleShow.spSpirit1.width = 100 * int(_pXml["peo" + _nowChatacter.charaIndex].Spirit) / int(Sav.gamedata["MaxAbility"]);
_peopleShow.spDefense1.width = 100 * int(_pXml["peo" + _nowChatacter.charaIndex].Defense) / int(Sav.gamedata["MaxAbility"]);
_peopleShow.spBreakout1.width = 100 * int(_pXml["peo" + _nowChatacter.charaIndex].Breakout) / int(Sav.gamedata["MaxAbility"]);
_peopleShow.spMorale1.width = 100 * int(_pXml["peo" + _nowChatacter.charaIndex].Morale) / int(Sav.gamedata["MaxAbility"]);
}
//察看武将-显示装备
private function setEquipment():void{}
//察看武将-显示策略
private function setTactics():void{}

就是这样了,然后,运行一下flash,可以看到下面的图
预览

预览

该研究攻击了,这个比较复杂,先来看,我军方面的攻击
当然,首先要把攻击动作等补全
CharacterMC中,把攻击图片和被攻击图片等全部载入
//Unit_mov图片加载完成
public function onCompleteUnit_mov(event:Event):void {
_image = Bitmap(_loader.content);
//初始化显示数组
_bitShowArr = new Array();
//将位图数据拆分成小块,装入bitmapArr
_bitmapArr=ImageCtrl.divide(_image,1,11);
var newArr:Array;
//得到向上行走数组
newArr = new Array(_bitmapArr[2][0],_bitmapArr[3][0]);
//将向上行走数组加入到显示数组 编号:0
_bitShowArr.push(newArr);
//得到向下行走数组
newArr = new Array(_bitmapArr[0][0],_bitmapArr[1][0]);
//将向下行走数组加入到显示数组 编号:1
_bitShowArr.push(newArr);
//得到向左行走数组
newArr = new Array(_bitmapArr[4][0],_bitmapArr[5][0]);
//将向左行走数组加入到显示数组 编号:2
_bitShowArr.push(newArr);
//得到向右行走数组
newArr = new Array(ImageCtrl.bitHorizontal(_bitmapArr[4][0]),ImageCtrl.bitHorizontal(_bitmapArr[5][0]));
//将向右行走数组加入到显示数组 编号:3
_bitShowArr.push(newArr);
//得到向上站立数组
newArr = new Array(_bitmapArr[7][0]);
//将向上站立数组加入到显示数组 编号:4
_bitShowArr.push(newArr);
//得到向下站立数组
newArr = new Array(_bitmapArr[6][0]);
//将向下站立数组加入到显示数组 编号:5
_bitShowArr.push(newArr);
//得到向左站立数组
newArr = new Array(_bitmapArr[8][0]);
//将向左站立数组加入到显示数组 编号:6
_bitShowArr.push(newArr);
//得到向右站立数组
newArr = new Array(ImageCtrl.bitHorizontal(_bitmapArr[8][0]));
//将向右站立数组加入到显示数组 编号:7
_bitShowArr.push(newArr);
//得到喘气数组
newArr = new Array(_bitmapArr[9][0],_bitmapArr[10][0]);
//将喘气数组加入到显示数组 编号:8
_bitShowArr.push(newArr);

//Unit_atk图片加载;
_loader = new Loader();
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteUnit_atk);
var atkName:String = "Images/Unit_atk/" + _imageIndex + ".gif";
_loader.load(new URLRequest(atkName));
}
//Unit_atk图片加载完成
public function onCompleteUnit_atk(event:Event):void {
_image = Bitmap(_loader.content);
//将位图数据拆分成小块,装入bitmapArr
_bitmapArr=ImageCtrl.divide(_image,1,12);
var newArr:Array;
//得到向上攻击数组
newArr = new Array(_bitmapArr[4][0],_bitmapArr[5][0],_bitmapArr[6][0],_bitmapArr[7][0]);
//将向上攻击数组加入到显示数组 编号:9
_bitShowArr.push(newArr);
//得到向下攻击数组
newArr = new Array(_bitmapArr[0][0],_bitmapArr[1][0],_bitmapArr[2][0],_bitmapArr[3][0]);
//将向下攻击数组加入到显示数组 编号:10
_bitShowArr.push(newArr);
//得到向左攻击数组
newArr = new Array(_bitmapArr[8][0],_bitmapArr[9][0],_bitmapArr[10][0],_bitmapArr[11][0]);
//将向左攻击数组加入到显示数组 编号:11
_bitShowArr.push(newArr);
//得到向右攻击数组
newArr = new Array(ImageCtrl.bitHorizontal(_bitmapArr[8][0]),ImageCtrl.bitHorizontal(_bitmapArr[9][0]),ImageCtrl.bitHorizontal(_bitmapArr[10][0]),ImageCtrl.bitHorizontal(_bitmapArr[11][0]));
//将向右攻击数组加入到显示数组 编号:12
_bitShowArr.push(newArr);

//Unit_spc图片加载;
_loader = new Loader();
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteUnit_spc);
var spcName:String = "Images/Unit_spc/" + _imageIndex + ".gif";
_loader.load(new URLRequest(spcName));
}
//Unit_spc图片加载完成
public function onCompleteUnit_spc(event:Event):void {
_image = Bitmap(_loader.content);
//将位图数据拆分成小块,装入bitmapArr
_bitmapArr=ImageCtrl.divide(_image,1,5);
var newArr:Array;
//得到向上挡格数组
newArr = new Array(_bitmapArr[1][0]);
//将向上挡格数组加入到显示数组 编号:13
_bitShowArr.push(newArr);
//得到向下挡格数组
newArr = new Array(_bitmapArr[0][0]);
//将向下挡格数组加入到显示数组 编号:14
_bitShowArr.push(newArr);
//得到向左挡格数组
newArr = new Array(_bitmapArr[2][0]);
//将向左挡格数组加入到显示数组 编号:15
_bitShowArr.push(newArr);
//得到向右挡格数组
newArr = new Array(ImageCtrl.bitHorizontal(_bitmapArr[2][0]));
//将向右挡格数组加入到显示数组 编号:16
_bitShowArr.push(newArr);
//得到受攻击数组
newArr = new Array(_bitmapArr[3][0]);
//将受攻击数组加入到显示数组 编号:17
_bitShowArr.push(newArr);
//得到升级数组
newArr = new Array(_bitmapArr[4][0]);
//将升级数组加入到显示数组 编号:18
_bitShowArr.push(newArr);

startFrame();
}

CharacterIndex中,把相应的动作代号补全,以方便使用
package Caocao.Character {
public class CharacterIndex {
public static const UP:int = 0;
public static const DOWN:int = 1;
public static const LEFT:int = 2;
public static const RIGHT:int = 3;
public static const UP_STOP:int = 4;
public static const DOWN_STOP:int = 5;
public static const LEFT_STOP:int = 6;
public static const RIGHT_STOP:int = 7;
public static const PANT:int = 8;
public static const ATTACK_UP:int = 9;
public static const ATTACK_DWON:int = 10;
public static const ATTACK_LEFT:int = 11;
public static const ATTACK_RIGHT:int = 12;
public static const WARD_UP:int = 13;
public static const WARD_DWON:int = 14;
public static const WARD_LEFT:int = 15;
public static const WARD_RIGHT:int = 16;
public static const TAKE_A_BEAT:int = 17;
public static const UPGRADE:int = 18;
public function CharacterIndex() { }
}
}
然后,继续在人物动作类CharacterMC中加入一个被攻击人员和一个可以随时改变值的自定义函数
//对手
public var _rival:Character;
private var _rivalMC:CharacterMC;
//执行函数
public var _fun:Function;

然后,在战场类FightMap中把战斗按钮上加上点击事件
//点击攻击事件
_selectBox.btnAttAck.addEventListener(MouseEvent.CLICK, charaAttHandler);
//点击攻击事件
private function charaAttHandler(event:MouseEvent):void{
_clickCtrl = "ATTACK";
_selectBox.visible = false;
_roadSprite.addEventListener(MouseEvent.CLICK,onClick);
setAttRound2(_pXml["peo" + _nowChatacter.charaIndex].Arms);
}
这里的setAttRound2,用红色半透明MC来显示攻击范围
//攻击范围显示
private function setAttRound2(armIndex:int):void{
var attRoundArr:Array;
var attRound:AttShow;
for each ( var roundment:XML in _arms["Arms" + armIndex]["RangeAttack"].elements( ) ) {
attRound = new AttShow();
attRoundArr = roundment.toString().split(",");
attRound.x = (int(attRoundArr[0]) + _nowChatacter.locationX )*48;
attRound.y = (int(attRoundArr[1]) + _nowChatacter.locationY) *48;
_roadSprite.addChild(attRound);
}

}
这时候,点击状态已经改变为"ATTACK"
在点击事件中,加上攻击事件
......
else if(_clickCtrl == "ATTACK"){
//寻找攻击目标
for(i=0;i<_enemyArr.length && !queryPeople;i++){
_character = _enemyArr[i] as Character;
_characterMC = _character.character;
if(Math.floor(_characterMC.x/48) == Math.floor(__mouseX/48) && Math.floor(_characterMC.y/48) == Math.floor(__mouseY/48)){

SpriteRemove.removeAllChildren(_roadSprite);
_nowChatacter.character._rival = _character;
_nowChatacter.character._fun = function(){
_clickCtrl = "NULL";
_nowChatacter.actionCtrl = true;
addEventListener(Event.ENTER_FRAME, onClickFrame);
}
_nowChatacter.attack();

break;
}

}
}
这里的_fun很重要,用来处理攻击完之后的事件代码
当然,给函数赋了值就要有执行的地方,
下面修改人物动作类CharacterMC的动态显示贞事件
//动态显示
public function onFrame(event:Event):void {
var dir:int = _showIndex;
_peopleBitmap.bitmapData = _bitShowArr[dir][_pointer];
_count += _speed;
_pointer += int(_count) ;
_count=_count%1;
//当人物攻击时,在攻击的第三个动作,被攻击人物显示被攻击动作
if((dir == CharacterIndex.ATTACK_UP || dir == CharacterIndex.ATTACK_DWON ||
dir == CharacterIndex.ATTACK_LEFT || dir == CharacterIndex.ATTACK_RIGHT ) && _pointer == 2){
//得到被攻击人物动作显示类
_rivalMC = _rival.character;
//根据攻击人物方向,设定攻击和被攻击完毕之后的人物方向
if(_rivalMC.x - this.x > 0){
this._direct = CharacterIndex.RIGHT;
_rivalMC._direct = CharacterIndex.LEFT;
}else if(_rivalMC.x - this.x < 0){
this._direct = CharacterIndex.LEFT;
_rivalMC._direct = CharacterIndex.RIGHT;
}else if(_rivalMC.y - this.y > 0){
this._direct = CharacterIndex.DOWN;
_rivalMC._direct = CharacterIndex.UP;
}else if(_rivalMC.y - this.y < 0){
this._direct = CharacterIndex.UP;
_rivalMC._direct = CharacterIndex.DOWN;
}
_rivalMC.setDir(CharacterIndex.TAKE_A_BEAT);
}
if(_pointer >= _bitShowArr[dir].length){
//人物动作不是移动动作的时候,动作结束后,根据动作前的方向,显示移动动作
switch(dir){
case CharacterIndex.TAKE_A_BEAT:
_showIndex = _direct;
break;
case CharacterIndex.ATTACK_UP:
_showIndex = _direct;
_fun();
case CharacterIndex.ATTACK_DWON:
_showIndex = _direct;
_fun();
case CharacterIndex.ATTACK_LEFT:
_showIndex = _direct;
_fun();
case CharacterIndex.ATTACK_RIGHT:
_showIndex = _direct;
_fun();
break;
}

_pointer = 0;
_count = 0;
}
}
之后,在动作类中,加入两个函数,用来控制人物行动前和行动后的亮度,就像曹操传里的行动完之后,人物会变暗
//转为静态
public function stand():void{
switch(_showIndex){
case CharacterIndex.UP:
setDir(CharacterIndex.UP_STOP);
break;
case CharacterIndex.DOWN:
setDir(CharacterIndex.DOWN_STOP);
break;
case CharacterIndex.LEFT:
setDir(CharacterIndex.LEFT_STOP);
break;
case CharacterIndex.RIGHT:
setDir(CharacterIndex.RIGHT_STOP);
break;
}
this.transform.colorTransform = _standColor;
}
//转为动态
public function run():void{
switch(_showIndex){
case CharacterIndex.UP_STOP:
setDir(CharacterIndex.UP);
break;
case CharacterIndex.DOWN_STOP:
setDir(CharacterIndex.DOWN);
break;
case CharacterIndex.LEFT_STOP:
setDir(CharacterIndex.LEFT);
break;
case CharacterIndex.RIGHT_STOP:
setDir(CharacterIndex.RIGHT);
break;
}
this.transform.colorTransform = _runColor;
}
主要是这些修改,其他的都是些小改动

目前,只写了我军的攻击,而且只是攻击动作,敌人也不掉血,不过加个掉血并不难,
难的是敌军的攻击,现在敌军回合,敌军依然只会跟随我军某一个人物移动,等研究完敌军攻击之后,把代码放出来,

好了,现在先看一下效果吧
预览

预览

下次,研究一下敌人的攻击

到了复杂的地方了,敌军的AI问题了

曹操传中敌军的行动方针有很多种,敌军根据相应的行动方针进行不同的行为
所以,我们首先在人物类中,加上行动方针一项
//行动方针
private var _mission:String;
默认是"DEFAULT",现在不研究太复杂,目前只考虑这一个行动方针
并且,默认下就选择攻击
敌人选择攻击目标的时候,会优先选择一击可以杀死的人物,
这里就要在选择攻击目标之前,先来判断一下攻击的这个人能否被杀死
那么,就要有物理攻击计算
那就利用曹操传中的物理攻击公式在战场类中写一个方法
/*物理攻击的伤害值计算
X代表攻击方的攻击力,Y代表被攻击方的防御力,Lv表示攻击方的等级。R表示伤害值
首先会根据地形修正攻击和防御力为X',Y'
if (x'>y')
r=Lv+25+(X'-Y')/2;
else
r=Lv+25-(Y'-X')/2
然后再根据兵种相克和宝物进行修正
*/
public function getAttHurt(attChara:Character,hertChara:Character):int{
var r:int;
//得到攻击方的攻击力和等级
var attLv:int = int(_pXml["peo" + attChara.charaIndex].Lv);
var attAttack:int = int(_pXml["peo" + attChara.charaIndex].Attack);
//得到防御方的防御力
var hertDefense:int = int(_pXml["peo" + hertChara.charaIndex].Defense);
//计算攻击方所在地形
var attTerrain:String = "Terrain" + _mapData[attChara.locationY][attChara.locationX];
//计算防御方所在地形
var hertTerrain:String = "Terrain" + _mapData[hertChara.locationY][hertChara.locationX];
//根据地形修正攻击和防御力
var attAttackAddition:int = Math.floor((int(_arms["Arms" + attChara.armsIndex].Terrain[attTerrain].@Addition)/100) * attAttack);
var hertDefenseAddition:int = Math.floor((int(_arms["Arms" + hertChara.armsIndex].Terrain[hertTerrain].@Addition)/100) * hertDefense);
//物理攻击的伤害值计算
if(attAttackAddition > hertDefenseAddition){
r = attLv + 25 + (attAttackAddition - hertDefenseAddition)/2;
}else{
r = attLv + 25 + (hertDefenseAddition - attAttackAddition)/2;
}
return r;
}
好了,有了伤害计算了,在攻击的时候,先寻找到所有可以攻击到的位置,
//计算所有攻击范围
private function getAttRange(chara:Character):Object{
var attArr:Array = new Array();
var attRoundArr:Array;
var i:int;
var j:int;
var objAll:Object = new Object();
var objCheck:Object = new Object();
var obj:Object = new Object();
var attRound:Array = new Array();
//兵种攻击范围
for each ( var roundment:XML in _arms["Arms" + chara.armsIndex]["RangeAttack"].elements( ) ) {
attRoundArr = roundment.toString().split(",");
attRound.push(new Point(int(attRoundArr[0]), int(attRoundArr[1])));
}
//根据移动范围来计算所有攻击范围
for(i=0;i<_roadShowArray.length;i++){
for(j=0;j<attRound.length;j++){
obj = new Object();
obj.x = _roadShowArray[i].x + attRound[j].x;
obj.y = _roadShowArray[i].y + attRound[j].y;
if(objAll[obj.x + "," + obj.y] == null){
obj.nodeparent = _roadShowArray[i];
objAll[obj.x + "," + obj.y] = obj;
attArr.push(obj);
}
}
}
objAll.attArr = attArr;
return objAll;
}
这里,添加了一个obj.nodeparent,用来确定攻击的时候所移动的位置

好了,现在就简单了,因为可以利用上面的两个方法轻松找到攻击目标了
//计算攻击目标
public function getAttTarget(chara:Character,peoArr:Array):Object{
var i:int;
var objResult:Object;
var obj:Object;
//计算所有攻击范围
var objAll:Object = getAttRange(chara);
var attArr:Array = new Array();
var intHert:int;
for(i=0;i<peoArr.length;i++){
var checkChara:Character = peoArr[i];
obj = objAll[checkChara.locationX + "," + checkChara.locationY];
if(obj != null){
intHert = getAttHurt(chara,checkChara);
obj.chara = checkChara;
//判断是否有一击可以杀死的人,有的话直接确立目标
if(intHert >= checkChara.nowHP){
return obj;
}
attArr.push(obj);
}
}
//没有一击可以杀死的人的时候,如果有可以攻击到的人,则随即抽取可以攻击到的人,确立目标
if(attArr.length > 0 ){
i = Math.random() * attArr.length;
return attArr[i];
}
//没有可以攻击到的人,没有找到目标
return null;
}
然后,在敌军寻路完成后,就可以判断下行动方针,当然这里的行动方针只有一个,哈哈
if(_nowChatacter.mission == "DEFAULT"){
//查找攻击目标
var obj:Object = getAttTarget(_nowChatacter,_ourArr);
if(obj != null){
_nowChatacter.character._rival = obj.chara;
_toPoint = new Point(obj.nodeparent.x,obj.nodeparent.y);
}else{
//开始行动
_toPoint = new Point(_roadShowArray[0].x,_roadShowArray[0].y);
i = Math.random() * _ourArr.length;
_character = _ourArr[i];
toDistance = Math.abs(_character.locationX - _toPoint.x) + Math.abs(_character.locationY - _toPoint.y) ;
for(i=1;i<_roadShowArray.length;i++){
checkDistance = Math.abs(_character.locationX - _roadShowArray[i].x) + Math.abs(_character.locationY - _roadShowArray[i].y) ;
if(checkDistance < toDistance){
toDistance = checkDistance;
_toPoint.x = _roadShowArray[i].x;
_toPoint.y = _roadShowArray[i].y;
}
}
_nowChatacter.character._rival = null;
}
_nowPoint = new Point( _nowChatacter.locationX, _nowChatacter.locationY);
_characterMC = _nowChatacter.character;
_nowDirection = _characterMC.getDir();
charaToMove();
}

看,obj.nodeparent.x,obj.nodeparent.y就是之前确定好的移动位置

然后,在敌军武将移动完毕时,判断一下是不是有攻击目标
没有的话,结束行动,有的话,进入攻击状态
if(_nowChatacter.rival == null){
_nowChatacter.actionCtrl = true;
_enemyActionCtrl = 0;
_clickCtrl = "NULL";
}else{
_clickCtrl = "ATTACK";
}
addEventListener(Event.ENTER_FRAME, onEnemyFrame);
然后,在控制敌军行动事件中,加上攻击代码,和我军攻击的时候是一样的,不同的是,攻击完毕的时候,所调用的方法不一样,我方攻击的时候,需要调用鼠标点击事件,这次需要调用控制敌军行动事了
if(_clickCtrl == "ATTACK"){
removeEventListener(Event.ENTER_FRAME, onEnemyFrame);
_nowChatacter.character._fun = function(){
_clickCtrl = "NULL";
_nowChatacter.actionCtrl = true;
_enemyActionCtrl = 0;
addEventListener(Event.ENTER_FRAME, onEnemyFrame);
}
_nowChatacter.attack();
}

好了,运行下程序,可以看到敌军也会进行攻击了
当然攻击是不掉血的,嘿嘿

敌军步兵的攻击
预览

预览

下次,该研究掉血和掉血的时候显示一下了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值