说到九宫格战斗,就不能不提一款游戏《神仙道》,在神仙道之前,九宫格战斗的模式就在几款游戏里面有应用,但神仙道是真真正正把这种战斗模式发扬光大的里程碑,当时无论口碑,还是市场占有率都可以说是空前的,这款游戏我玩到150级,可以说是投入精力比较大的一款游戏,在游戏里面也交了很多朋友,虽然最近这种游戏模式因为一些原因走下坡路(现阶段刀塔传奇这种模式的游戏很吃香),不过既然说回合制游戏,那么就还是讨论一下。
| 一、 | 战斗系统概述 | |||||
| 1 | 此战斗系统适用于PVE(玩家与怪物战斗)和PVP(玩家与玩家战斗) | |||||
| 2 | 游戏为横版,攻守双方分部屏幕左右两边 | |||||
| 3 | 战场上攻防双方各有一个3*3的9宫格方阵 | |||||
| 4 | 回合制战斗,按双方各自的出手顺序 | |||||
| 二、 | 战斗内容 | ||||||
| 2.1 | 战斗单位 | ||||||
| 2.1.1 | 战场上的一方最多只能有五个战斗单位,战斗单位包括主角和伙伴(这个在后期改为有一个伙伴作为后备,当前排角色死亡后来填补空缺【不过反响并不好】) | ||||||
| 2.1.2 | 每场战斗可以派遣数个伙伴随主角一起参与,最高参与人数与奇术系统相关 | ||||||
| 2.2 | 战斗触发 | ||||||
| 2.2.1 | 战斗触发入口 | 多人副本入口、开启活动副本入口 | |||||
| 2.2.2 | 触碰明雷怪 | 在单人副本中行走进入明雷怪触发战斗范围后,切换至战斗画面 | |||||
| 2.3 | 战斗规则 | ||||||
| 2.3.1 | 回合制 | 每场战斗20回合,如果回合满则自动结束战斗 | |||||
| 2.3.2 | 攻击顺序 | ||||||
| A. | 按照双方先攻值判断队伍出手先后顺序 | ||||||
| B. | 按本方出手顺序依次筛选出第N个出手的战斗单位 | ||||||
| C. | 死亡的战斗单位不参与筛选,如果本方第N个出手的战斗单位死亡,则本轮次轮空 | ||||||
| 2.4 | 战场形势 | ||||||
| 2.4.1 | 战场位置 | 战场上攻防双方各有一个3*3的9宫格方阵,根据阵型不同,玩家可以布置 | |||||
| 2.4.2 | 战斗位置编号 | 为9宫格每个格子进行编号,阵型系统根据编号,给予上场的单位出手顺序 | |||||
| 2.5 | 战斗带入属性 | ||||||
| 2.5.1 | 玩家等级 | 1-100(这里用100是因为100级之前神仙道的概率公式直接使用百分数,110之后更新,概率由百分数改为概率等级,参考魔兽世界600等级==1%) | |||||
| 2.5.2 | 职业 | 剑灵、飞羽、将星、武圣、方士、术士 | |||||
| 2.5.3 | HP | 每个战斗单位的总血量值 | |||||
| 2.5.4 | 普通攻击力/法术攻击力 | 物理职业读取普通攻击力值,法师职业读取法术攻击力值 | |||||
| 2.5.5 | 普通防御力/法术防御力 | 物理职业读取普通防御力值,法师职业读取法术防御力值 | |||||
| 2.5.6 | 绝技攻击力 | 士气达到100时,释放绝技时读取的绝技攻击力值 | |||||
| 2.5.7 | 绝技防御力 | 受到绝技伤害时,读取的绝技防御力值 | |||||
| 2.5.8 | 命中概率、闪避概率 | (出手战斗单位命中概率-防御方闪避)是一个在[0,1]区间的概率值(110之后改为概率等级),决定是否成功命中对方或被对方躲避掉此次伤害 | |||||
| 2.5.9 | 暴击概率 | 成功触发暴击事件的概率(110之后改为概率等级) | |||||
| 2.5.10 | 减少对方暴击 | 减少对方触发暴击事件的概率(110之后改为概率等级) | |||||
| 2.5.11 | 必杀 | 增加触发暴击事件后产生的伤害值(110之后改为概率等级) | |||||
| 2.5.12 | 格挡概率 | 成功触发格挡事件的概率(110之后改为概率等级) | |||||
| 2.5.13 | 减少对方格挡 | 减少对方触发格挡事件的概率(110之后改为概率等级) | |||||
| 2.5.14 | 士气值 | 士气值累积达到100时,触发绝技(110之后改为概率等级) | |||||
| 2.6 | 攻击事件 | |||||||
| 2.6.1 | 普通攻击 | 物理攻击型战斗单位在士气未达到100时的攻击方式 | ||||||
| 2.6.2 | 法术攻击 | 法术攻击型战斗单位在士气未达到100时的攻击方式 | ||||||
| 2.6.3 | 绝技攻击 | 战斗单位的士气值达到100时的攻击方式 | ||||||
| 2.6.4 | 血量减少 | 攻击放成功给予目标战斗单位伤害后,目标战斗单位血量减少 | ||||||
| 2.6.5 | 暴击 | 按暴击概率是否成功触发暴击事件,若成功触发则产生(1+0.5+必杀值)*E的伤害,失败则伤害值仍为E(E为按攻防公式产生的非绝技伤害值) | ||||||
| 2.6.6 | 命中 | 出手战斗单位成功对目标战斗单位造成单次伤害 | ||||||
| 2.6.7 | 闪避 | 目标战斗单位成功躲避出手战斗单位造成的单次伤害 | ||||||
| 2.6.8 | 格挡 | 按概率成功触发格挡事件后,受到的伤害值减半,状态维持1回合 | ||||||
| 2.6.9 | 反击 | 被近战单体攻击并触发格挡之后,触发反击对对方造成数值为E的伤害 | ||||||
| 2.6.10 | 士气 | |||||||
| A. | 获得:初始值及获得士气值见下表(身上有特殊BUFF时也会获得士气值) | |||||||
| 职业 | 初始默认值 | 物理攻击 | 被物理攻击 | 法术攻击 | 被法术攻击 | 绝技攻击 | 被绝技攻击 | BUFF增加 |
| 剑灵 | 50 | 25 | 25 | 25 | 25 | 0 | 0 | 参见BUFF表 |
| 武圣 | 50 | 25 | 25 | 25 | 25 | 0 | 0 | 参见BUFF表 |
| 飞羽 | 50 | 25 | 25 | 25 | 25 | 0 | 0 | 参见BUFF表 |
| 将星 | 50 | 25 | 25 | 25 | 25 | 0 | 0 | 参见BUFF表 |
| 方士 | 50 | 25 | 25 | 25 | 25 | 0 | 0 | 参见BUFF表 |
| 术士 | 50 | 25 | 25 | 25 | 25 | 0 | 0 | 参见BUFF表 |
| B. | 消耗 | |||||||
| 每次士气值达到或超过100触发绝技后,士气值减少至0 | ||||||||
| 受到减少士气值的技能攻击,士气值减少 | ||||||||
| 2.7 | 战斗结果 | |||||||
| 2.7.1 | 一方的所有战斗单位的血量和为0,战斗结束。战斗单位血量和大于0的一方获胜 | |||||||
| 2.7.2 | 每场战斗只有20回合,如果20回合后双方没有分出胜负,则防守方(战斗画面右方)胜利 | |||||||
| 2.8 | 战斗奖励 | |||||||
| 2.8.1 | 战斗之后根据配置文件处理战斗获得 | |||||||
| 2.8.2 | 战斗中死亡的战斗单位也可以获得经验奖励。经验奖励只与战斗结果有关,即战斗胜利, | |||||||
| 胜利方的所有参战的战斗单位都可以获得经验奖励,战斗胜利,所有战斗单位没有经验 | ||||||||
| 奖励 | ||||||||
| 2.9 | 战斗结束后的血量补充 | |||||||
| 2.9.1 | 战斗单位升级 血量自动补满 | |||||||
| 2.9.2 | 战斗单位未升级 | |||||||
| A. | 主角身上有血池buff | |||||||
| a. | 血池足够 | 所有参战的战斗单位血量补满(补给血量值为A),血池血量减少A | ||||||
| b. | 血池不足 | 按照战斗单位的出手顺序为战斗单位依次补给血量 | ||||||
| 实例: | ||||||||
| 战斗单位 | 出手顺序 | 总HP | 当前HP | 血池血量 | 需要的补给 | 实际的补给 | ||
| A | 1 | 4000 | 1000 |
|
3000 | 3000 | ||
| B | 2 | 4000 | 2000 | 18462 | 2000 | 2000 | ||
| C | 3 | 4000 | 1000 | 3000 | 3000 | |||
| D | 4 | 4000 | 1500 | 2500 | 2500 | |||
| c. | 特殊情况: | |||||||
| D当前HP为0,在恢复C血时已经消耗掉血池的全部存余血量,默认为D增加1点HP | ||||||||
| B. | 主角身上无血池buff | |||||||
| 战斗单位血量为0,自动为其增加1点血量 | ||||||||
| 战斗单位剩余血量不为0,不增加血量 | ||||||||
| 三、 | 战斗表现形式 | ||||||
| 3.1 | 状态说明 | ||||||
| 状态 | 说明 | ||||||
| 普通近程攻击 | 出手战斗单位从原地消失→播放向目标战斗单位前进的动作→播放出手战斗单位的攻击动作以及目标战斗单位被攻击的动作→目标战斗单位损失血量→出手战斗单位消失→播放出手战斗单位退回原地的动作→出手战斗单位出现在原位 | ||||||
| 普通远程攻击 | 播放出手战斗单位的攻击动作及特效→播放目标战斗单位的被攻击动作及特效→目标战斗单位损失血量 | ||||||
| 普通法术攻击 | 播放出手战斗单位的攻击动作及特效→播放目标战斗单位的被攻击动作及特效→目标战斗单位损失血量 | ||||||
| 绝技攻击 | 播放出手战斗单位的攻击动作及特效→播放目标战斗单位的被攻击动作及特效→目标战斗单位损失血量 | ||||||
| 闪避 | 播放出手战斗单位的攻击动作及特效→播放目标战斗单位的被攻击动作及特效,同时在目标战斗单位出现“闪避”字样 | ||||||
| 暴击 | 播放出手战斗单位的攻击动作及特效,同时在出手战斗单位出现“暴击”字样→播放目标战斗单位的被攻击动作及特效→目标战斗单位损失血量 | ||||||
| 格挡 | 播放出手战斗单位的攻击动作及特效→播放目标战斗单位的被攻击动作及特效,同时在目标战斗单位出现“格挡”字样→目标战斗单位损失血量 | ||||||
| 损失血量 | 目标战斗单位显示减少的血量数值 | ||||||
| 反击 | 目标战斗单位在格挡状态下,在目标战斗单位处出现“反击”字样→目标战斗单位从原地消失→播放向原出手战斗单位前进的动作→播放目标战斗单位的攻击动作以及出手战斗单位被攻击的动作→原出手战斗单位损失血量→目标战斗单位消失→播放目标战斗单位退回原地的动作→目标战斗单位出现在原位 | ||||||
| 四、 | 流程图 |
4.1战斗回合流程
4.2战斗轮次流程
4.3战斗行动准备流程
4.4战斗进行阶段流程
4.5战斗结束阶段流程
4.6buffer流程
4.7选择攻击方式流程
4.8战斗单位死亡流程
4.9战斗替补单位流程
| 命中、暴击、必杀、格挡计算流程 |
好了,战斗系统就这些,好家伙,真佩服策划的工作能力(上面这些是某公司山寨神仙道
时候的策划文档摘抄,这里感谢原作者)
好了,我们的文档这样就完成了,也就是说我们的战斗系统要做到上面文档要求的效果,那会是什么样的呢?这里感谢as3页游方面的专家leo老兄提供战斗系统源码,因为这里代码有现成的,我们只是做代码分析,因为这个战斗系统代码不是我写的这里就不公开散布了,所以需要源码的小伙伴可以私信给我
。我们这里只做分析。
我们先看看配置文件,战斗的battle数据文件(本来应该是服务器即使生成)
接着看下文档类
package leo
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.profiler.showRedrawRegions;
import leo.controller.util.LayerUtil;
import leo.proxy.GameConst;
import leo.proxy.transmission.LoaderUtil;
import leo.view.ui.BtnBattle;
import leo.view.ui.BtnBattleTips;
import leo.view.ui.UIBattleList;
[SWF(width="1250",height="650",frameRate="24",backgroundColor="0")]
public class BattlePlayer extends Sprite
{
private var curView :*;
private var battleLayer :Sprite;
private var popLayer :Sprite;
private var btnBattle :BtnBattle;
private var btnBattleTips :BtnBattleTips;
public function BattlePlayer()
{
init();
}
private function init():void
{
LoaderUtil.I.loadConfig();
this.battleLayer = new Sprite();
this.popLayer = new Sprite();
this.addChild(battleLayer);
this.addChild(popLayer);
LayerUtil.I.layerDict[GameConst.BATTLE_LAYER] = this.battleLayer;
LayerUtil.I.layerDict[GameConst.POP_LAYER] = this.popLayer;
GameConst.main = this;
}
/*
public function rhand():void
{
btnBattle = new BtnBattle();
this.addChild(btnBattle);
btnBattleTips = new BtnBattleTips();
btnBattleTips.x = btnBattle.x + btnBattle.width - 20;
btnBattleTips.y = btnBattle.y + btnBattle.height - 20;
btnBattleTips.mouseChildren = btnBattleTips.mouseEnabled = false;
this.addChild(btnBattleTips);
btnBattle.addEventListener(MouseEvent.MOUSE_UP,mouseHandler);
}
*/
public function setStage(view :*):void
{
if(this.curView && this.battleLayer && this.battleLayer.contains(this.curView))
{
this.curView.destroy;
this.battleLayer.removeChild(this.curView);
}
battleLayer.addChild(view);
}
public function show():void
{
//btnBattle.visible = true;
//btnBattle.mouseChildren = btnBattle.mouseEnabled = true;
//btnBattleTips.play();
}
public function hide():void
{
//btnBattle.visible = false;
//btnBattle.mouseChildren = btnBattle.mouseEnabled = false;
//btnBattleTips.stop();
}
public function mouseHandler():void
//private function mouseHandler(e :MouseEvent):void
{
trace("load");
var view :UIBattleList = new UIBattleList(null);
setStage(view);
//hide();
}
}
}
init方法中有LoaderUtil.I.loadConfig();我们看下LoaderUtil这个静态类
package leo.proxy.transmission
{
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.utils.Dictionary;
import flash.utils.getDefinitionByName;
import leo.proxy.GameConst;
import leo.proxy.battles.action.Action_AddObject;
import leo.proxy.battles.action.Action_Attack;
import leo.proxy.battles.action.IBattleAction;
import leo.proxy.battles.vo.BattleVO;
import leo.proxy.vo.BaseUI;
import leo.proxy.vo.RoleAssetsVO;
/
* 加载工具
* @author leo
*
*/
public class LoaderUtil
{
private static var _I :LoaderUtil = null;
/
* 加载器缓存
*/
public var loaderDict :Dictionary = new Dictionary();
/
* 所有加载过的UI的VO
*/
public var fileList :Dictionary = new Dictionary();
/
* 缓存的战斗VO表
*/
public var battleVOList :Dictionary = new Dictionary();
/
* 缓存战斗地图
*/
public var battleMapDict :Dictionary = new Dictionary();
/
* 总加载数
*/
private var sum :int;
/
* 当前已加载数
*/
private var index :int;
/
* 加载列表成功函数
*/
private var rhand :Function;
/
* 加载列表失败函数
*/
private var fhand :Function;
/
* 加载UI成功函数
*/
private var uiRhand :Function;
/
* 加载UI失败函数
*/
private var uiFhand :Function;
public function LoaderUtil(prv :PrivateClass)
{
}
/
* 加载UI列表
* @param list 完整路径列表
* @param rhand
* @param fhand
*
*/
public function loadList(list :Array,rhand :Function = null,fhand :Function = null):void
{
if(!list || list.length == 0)
{
return;
}
this.rhand = rhand;
this.fhand = fhand;
this.sum = 0;
this.sum = list.length;
for(var i :int = 0; i < list.length; i++)
{
var url :String = list[i] as String;
var loader :CustomLoader = new CustomLoader();
loader.id = url;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,completeHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
var loaderContext :LoaderContext = new LoaderContext(false,ApplicationDomain.currentDomain);
loader.load(new URLRequest(url),loaderContext);
this.loaderDict[loader.id] = loader;
}
}
/
* 加载UI列表成功
* @param e
*
*/
private function completeHandler(e :Event):void
{
this.index++;
var loader :CustomLoader = (e.target as LoaderInfo).loader as CustomLoader;
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,completeHandler);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,errorHandler);
if(this.loaderDict[loader.id])
{
loader.unload();
delete this.loaderDict[loader.id];
loader = null;
}
if(this.index == this.sum)
{
if(this.rhand != null)
{
rhand();
rhand = null;
fhand = null;
}
}
}
/
* 加载UI列表失败
* @param e
*
*/
private function errorHandler(e :IOErrorEvent):void
{
if(this.fhand != null)
{
fhand();
rhand = null;
fhand = null;
}
var loader :CustomLoader = (e.target as LoaderInfo).loader as CustomLoader;
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,completeHandler);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,errorHandler);
trace("加载组ui出错");
}
/
* 加载单个UI
* @param vo
* @param rhand
* @param fhand
*
*/
public function loadUI(vo :BaseUI,rhand :Function,fhand :Function = null):void
{
if(!vo)
{
return;
}
this.uiRhand = rhand;
this.uiFhand = fhand;
var url :String = vo.swfPath;
var loader :CustomLoader = new CustomLoader();
loader.id = url;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,uiComplete);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,uiError);
var loaderContext :LoaderContext = new LoaderContext(false,ApplicationDomain.currentDomain);
loader.load(new URLRequest(url),loaderContext);
this.loaderDict[loader.id] = loader;
this.fileList[vo.swfPath] = vo;
}
/
* 加载单个UI成功
* @param e
*
*/
private function uiComplete(e :Event):void
{
var loader :CustomLoader = (e.target as LoaderInfo).loader as CustomLoader;
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,completeHandler);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,errorHandler);
if(this.fileList[loader.id])
{
var vo :BaseUI = this.fileList[loader.id] as BaseUI;
vo.isComplete = true;
vo.isLoading = false;
}
if(this.loaderDict[loader.id])
{
loader.unload();
delete this.loaderDict[loader.id];
loader = null;
}
if(this.uiRhand != null)
{
this.uiRhand();
this.uiRhand = null;
uiFhand = null;
}
}
/
* 加载单个UI失败
* @param e
*
*/
private function uiError(e :IOErrorEvent):void
{
var loader :CustomLoader = (e.target as LoaderInfo).loader as CustomLoader;
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,completeHandler);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,errorHandler);
if(this.uiFhand != null)
{
uiFhand();
this.uiRhand = null;
uiFhand = null;
}
trace("加载单个ui出错");
}
/
* 加载config.xml
*
*/
public function loadConfig():void
{
var str :String = GameConst.CONFIG_XML;
var loader :URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE,configComplete);
loader.addEventListener(IOErrorEvent.IO_ERROR,configError);
loader.load(new URLRequest(str));
}
/
* 加载config.xml成功
* @param e
*
*/
private function configComplete(e :Event):void
{
var xml :XML = new XML(((e.target) as URLLoader).data);
GameConst.uiDir = xml.uiDir;
GameConst.itemDir = xml.itemDir;
GameConst.roleDir = xml.roleDir;
GameConst.mapDir = xml.mapDir;
GameConst.battleXML = xml.battleXML;
var str :String = xml.ui;
var ary :Array = str.split(",");
while(ary.length > 0)
{
var url :String = GameConst.uiDir + ary.pop() + ".swf";
GameConst.uiList.push(url);
}
((e.target) as URLLoader).removeEventListener(Event.COMPLETE,configComplete);
((e.target) as URLLoader).removeEventListener(IOErrorEvent.IO_ERROR,configError);
loadBattleData();
}
/
* 加载config.xml失败
* @param e
*
*/
private function configError(e :IOErrorEvent):void
{
((e.target) as URLLoader).removeEventListener(Event.COMPLETE,configComplete);
((e.target) as URLLoader).removeEventListener(IOErrorEvent.IO_ERROR,configError);
trace("加载config出错");
}
/
* 加载战斗XML
*
*/
private function loadBattleData():void
{
var loader :URLLoader = new URLLoader();
var url :String = GameConst.battleXML;
loader.addEventListener(Event.COMPLETE,battleXMLComplete);
loader.addEventListener(IOErrorEvent.IO_ERROR,battleXMLError);
loader.load(new URLRequest(url));
}
/
* 加载战斗XML成功
* @param e
*
*/
private function battleXMLComplete(e :Event):void
{
var loader :URLLoader = e.target as URLLoader;
var xml :XML = new XML(loader.data);
for each(var battleXML :XML in xml.battle)
{
var battleVO :BattleVO = new BattleVO();
battleVO.battleInfoVO.parse(battleXML,battleVO);
for each(var actionXML :XML in battleXML.item)
{
var actionName :String= actionXML.@actionName;
//注意一定要导入要实例化的类才能getDefinitionByName,要不然会报错
importClass();
var path :String = GameConst.PACKAGE_ACTION;
var actionCls:Class = getDefinitionByName(path + actionName) as Class;
var action:IBattleAction = new actionCls() as IBattleAction;
action.parse(actionXML,battleVO);
battleVO.actions.push(action);
}
this.battleVOList[battleVO.battleInfoVO.id] = battleVO;
}
loader.removeEventListener(Event.COMPLETE,battleXMLComplete);
loader.removeEventListener(IOErrorEvent.IO_ERROR,battleXMLError);
loader = null;
//loadList(GameConst.uiList, GameConst.main.rhand);
loadList(GameConst.uiList,GameConst.main.mouseHandler);
}
/
* 加载战斗XML失败
* @param e
*
*/
private function battleXMLError(e :IOErrorEvent):void
{
var loader :URLLoader = e.target as URLLoader;
loader.removeEventListener(Event.COMPLETE,battleXMLComplete);
loader.removeEventListener(IOErrorEvent.IO_ERROR,battleXMLError);
trace("加载战斗XML出错");
}
public function checkIsLoad(swfPath :String):Boolean
{
var vo :BaseUI = this.fileList[swfPath] as BaseUI;
if(vo && (vo.isLoading || vo.isComplete))
{
return true;
}
return false;
}
private function importClass():void
{
var cls1 :Action_AddObject;
var cls2 :Action_Attack;
}
public static function get I():LoaderUtil
{
if(_I == null)
{
_I = new LoaderUtil(new PrivateClass());
}
return _I;
}
}
}
class PrivateClass{}
public function loadConfig():void{}方法里面有这样一句var str :String = GameConst.CONFIG_XML;而得到xml的外部链接
package leo.proxy
{
import flash.filters.GlowFilter;
import leo.BattlePlayer;
/
* 游戏常用的常量
* @author leo
*
*/
public class GameConst
{
public static var main :BattlePlayer = null;
public static const CONFIG_XML :String = "leo/assets/data/config.xml";
// public static const CONFIG_XML :String = "http://www.longsihao.com/games/BattlePlayer/assets/data/netConfig.xml";
public static var itemDir :String;
public static var uiDir :String;
public static var roleDir :String;
public static var mapDir :String;
public static var battleXML :String;
public static var uiList :Array = [];
public static var smallLoading :String = "smallLoading";
public static const POP_LAYER :String = "pop_layer";
public static const BATTLE_LAYER :String = "battle_layer";
public static const PACKAGE_ACTION :String = "leo.proxy.battles.action.";
public static const ROLE_ACTION_ARY :Array = ["attack","be_hit","fighting_idle"];
public static const SPEED :int = 3;
public static const MOUSE_ON :Array = [new GlowFilter(0xffff00,1,2,2,2,2)];
public static const SKILL_NAME :Array = ["天魔杀星","冰凌剑空","灵木刺阵","十方剑气","天魔斩","八方棍法","雷动八方","琥珀冲杀","毒龙蚀天","地狱之火","葬林狂舞"];
public function GameConst()
{
}
}
}
private function configComplete(e :Event):void{}方法中的
然后private function loadBattleData():void{}加载这战斗xml,我们可以看到trace(“actionName=” + actionName);得到的xml文件数据

方法最后loadList(GameConst.uiList,GameConst.main.mouseHandler);加载进入游戏的控制列表
回到文档类中的public function mouseHandler():void{}方法中var view :UIBattleList = new UIBattleList(null);setStage(view);调用battleLayer.addChild(view);
将view加载到舞台上面,UIBattleList中的baseUI = new BaseUI(“BattleList”,”BattleList”);来加载battlelist.swf文件文件截图
override protected function swfLoadComplete():void{}中的this.itemList = new Vector.
();
package leo.proxy.vo
{
import leo.proxy.GameConst;
/
* 加载UIVO基类
* @author Leo
*
*/
public class BaseUI
{
public var fileName :String;
public var linkName :String;
public var isLoading :Boolean = true;
public var isComplete :Boolean = false;
public function BaseUI(fileName :String , linkName :String)
{
this.fileName = fileName;
this.linkName = linkName;
}
public function get swfPath():String
{
return GameConst.uiDir + this.fileName + ".swf";
}
public function complete():void
{
this.isComplete = true;
this.isLoading = false;
}
}
}
package leo.view.ui
{
import flash.display.SimpleButton;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.utils.Dictionary;
import leo.controller.util.UIUtil;
import leo.proxy.GameConst;
import leo.proxy.battles.vo.BattleVO;
import leo.proxy.transmission.LoaderUtil;
import leo.proxy.vo.BaseUI;
/
* 战斗列表UI
* @author Leo
*
*/
public class UIBattleList extends UILoadingBase
{
public static var I :UIBattleList;
public var btnClose :SimpleButton;
public var itemList :Vector.
; public var btnLeft :SimpleButton; public var btnRight :SimpleButton; public var txtPage :TextField; public function UIBattleList(baseUI:BaseUI) { if(!baseUI) { baseUI = new BaseUI("BattleList","BattleList"); } super(baseUI); } override protected function swfLoadComplete():void { super.swfLoadComplete(); if(!content) { return; } this.itemList = new Vector.
(); binding(content,itemList,UIBattleListItem); btnClose = content.btnClose; this.btnLeft = content.btnLeft; this.btnRight = content.btnRight; this.txtPage = content.txtPage; data = []; var list :Dictionary = LoaderUtil.I.battleVOList; for (var key :* in list) { var vo :BattleVO = list[key] as BattleVO; if(vo) { data.push(vo); } } var index :int = 0; for each(var item :UIBattleListItem in itemList) { if(data[index]) { item.data = data[index]; }else { item.data = null; } index++; } addEventListener(MouseEvent.MOUSE_UP,mouseHandler); I = this; } private function mouseHandler(e :MouseEvent):void { trace("btn_close========"); switch(e.target) { case this.btnClose: trace("btn_close"); destroy(); break; case this.btnLeft: trace("left"); break; case this.btnRight: trace("right"); break; } } override public function destroy():void { super.destroy(); removeEventListener(MouseEvent.MOUSE_UP,mouseHandler); unBinding(itemList); if(this.parent) { this.parent.removeChild(this); } I = null; if(GameConst.main) { GameConst.main.show(); } } } }
binding(content,itemList,UIBattleListItem);绑定了数据和战斗播放按钮,super.swfLoadComplete();调用了父类的方法中的content = BitmapUtil.I.getMCByName(baseUI.linkName);
package leo.view.ui
{
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.SimpleButton;
import flash.events.MouseEvent;
import flash.filters.GlowFilter;
import flash.text.TextField;
import flash.utils.ByteArray;
import leo.controller.util.LayerUtil;
import leo.proxy.GameConst;
import leo.proxy.battles.vo.BattleVO;
import leo.proxy.vo.BaseUI;
/
* 战役列表子项
* @author Leo
*
*/
public class UIBattleListItem extends SimpleButton
{
public var txtBattleName :TextField;
public var txtBattleContent :TextField;
public var txtBattleAward :TextField;
public var mcContent :MovieClip;
public var btnShow :SimpleButton;
private var mc :MovieClip;
private var _data :BattleVO;
public function UIBattleListItem(mc :* = null)
{
if(mc)
{
this.mc = mc;
this.txtBattleAward = mc.txtBattleAward;
this.txtBattleContent = mc.txtBattleContent;
this.txtBattleName = mc.txtBattleName;
this.mcContent = mc.mcContent;
this.btnShow = mc.btnShow;
mc.addEventListener(MouseEvent.MOUSE_OVER,mouseHandler);
mc.addEventListener(MouseEvent.MOUSE_OUT,mouseHandler);
mc.addEventListener(MouseEvent.MOUSE_UP,mouseHandler);
}
super();
}
private function mouseHandler(e :MouseEvent):void
{
switch(e.type)
{
case MouseEvent.MOUSE_OVER:
if(this.mcContent)
{
this.mcContent.filters = GameConst.MOUSE_ON;
}
break;
case MouseEvent.MOUSE_OUT:
if(this.mcContent)
{
this.mcContent.filters = null;
}
break;
case MouseEvent.MOUSE_UP:
switch(e.currentTarget)
{
case this.mc:
case this.btnShow:
show();
}
break;
}
}
private function show():void
{
if(UIBattleList.I)
{
UIBattleList.I.destroy();
}
trace("开始播放战役");
if(data)
{
var view :UIBattleView = new UIBattleView(data);
LayerUtil.I.layerDict[UIBattleView.NAME] = view;
GameConst.main.setStage(view);
}
if(GameConst.main)
{
GameConst.main.hide();
}
}
public function get data():BattleVO
{
return _data;
}
public function set data(vo:BattleVO):void
{
_data = vo;
if(vo == null)
{
this.mc.visible = false;
return;
}
this.txtBattleName.text = vo.battleInfoVO.name;
this.txtBattleContent.htmlText = "经验: " + "" + vo.battleInfoVO.exp + "" + " " +
"金币: " + "" + vo.battleInfoVO.gold + "" + " " +
"物品: " + "" + vo.battleInfoVO.itemID + "";
}
public function destroy():void
{
mc.addEventListener(MouseEvent.MOUSE_OVER,mouseHandler);
mc.addEventListener(MouseEvent.MOUSE_OUT,mouseHandler);
mc.addEventListener(MouseEvent.MOUSE_UP,mouseHandler);
mc = null;
txtBattleName = null;
txtBattleContent = null;
txtBattleAward = null;
mcContent = null;
btnShow = null;
}
}
}
mc.addEventListener(MouseEvent.MOUSE_OVER,mouseHandler);
mc.addEventListener(MouseEvent.MOUSE_OUT,mouseHandler);
mc.addEventListener(MouseEvent.MOUSE_UP,mouseHandler);
鼠标按下时show方法

package leo.view.ui
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.utils.Timer;
import ghostcat.manager.SoundManager;
import leo.controller.util.BitmapUtil;
import leo.controller.util.LayerUtil;
import leo.controller.util.PlayerUtil;
import leo.controller.util.RoleManage;
import leo.proxy.GameConst;
import leo.proxy.battles.action.BaseBattleAction;
import leo.proxy.battles.action.IBattleAction;
import leo.proxy.battles.vo.BattleVO;
import leo.proxy.transmission.LoaderUtil;
import leo.proxy.vo.BaseUI;
import leo.proxy.vo.RoleAssetsVO;
import leo.view.role.MapObject;
/
* 战斗视图层
* @author Leo
*
*/
public class UIBattleView extends Sprite
{
public static const NAME :String = "UIBattleView";
public var battleMap :UIBattleMap;
public var battlePlace :UIBattlePlace;
public var battleRoleLayer :UIBattleRoleLayer;
public var btnStartBattle :SimpleButton;
public var btnExitBattle :SimpleButton;
public var battleVO :BattleVO;
private var timer :Timer;
public function UIBattleView(battleVO :BattleVO)
{
this.battleVO = battleVO;
super();
if(!this.battleVO)
{
return;
}
if(stage)
{
init();
}else
{
addEventListener(Event.ADDED_TO_STAGE,init);
}
}
private function init(e :* = null):void
{
removeEventListener(Event.ADDED_TO_STAGE,init);
this.battleMap = new UIBattleMap(this.battleVO.battleInfoVO.battleMapID);
this.addChild(this.battleMap);
this.battlePlace = new UIBattlePlace();
this.addChild(this.battlePlace);
this.battleRoleLayer = new UIBattleRoleLayer(this.battleVO,battlePlace);
this.addChild(this.battleRoleLayer);
this.btnExitBattle = BitmapUtil.I.getBtnByName("BtnExitBattle");
if(this.btnExitBattle)
{
this.addChild(this.btnExitBattle);
this.btnExitBattle.x = stage.stageWidth - 150;
this.btnExitBattle.y = stage.stageHeight - 70;
}
this.btnStartBattle = BitmapUtil.I.getBtnByName("BtnStartBattle");
if(this.btnStartBattle)
{
this.addChild(this.btnStartBattle);
this.btnStartBattle.x = stage.stageWidth - 250;
this.btnStartBattle.y = stage.stageHeight - 70;
}
this.timer = new Timer(30);
this.timer.addEventListener(TimerEvent.TIMER,timerHandler);
this.timer.start();
addEventListener(MouseEvent.MOUSE_UP,clickHandler);
//播放战斗音乐
PlayerUtil.I.playBattleMusic();
}
private function clickHandler(e :MouseEvent):void
{
switch(e.target)
{
case this.btnExitBattle:
trace("退出战斗");
destroy();
break;
case this.btnStartBattle:
trace("开始战斗");
startBattle();
this.btnStartBattle.visible = false;
break;
}
}
/
* timer更新显示对象
* @param e
*
*/
private function timerHandler(e :TimerEvent):void
{
var list :Vector.
= RoleManage.I.roleList; if(!list || list.length == 0) { return; } for each(var mapObj :MapObject in list) { mapObj.update(); } PlayerUtil.I.update(); } / * 开始战役 */ private function startBattle():void { PlayerUtil.I.playBattle(this.battleVO.actions); } / * 销毁 * */ public function destroy():void { removeEventListener(MouseEvent.MOUSE_UP,clickHandler); this.timer.stop(); this.timer.removeEventListener(TimerEvent.TIMER,timerHandler); this.timer = null; RoleManage.I.destroyRoleObj(); PlayerUtil.I.resetAction(); delete LayerUtil.I.layerDict[UIBattleView.NAME]; if(this.parent) { this.parent.removeChild(this); } if(GameConst.main) { GameConst.main.show(); } PlayerUtil.I.stopBattleMusic(); } } }
private function startBattle():void{}方法中PlayerUtil.I.playBattle(this.battleVO.actions);
package leo.controller.util
{
import flash.geom.Point;
import ghostcat.manager.SoundManager;
import leo.proxy.battles.action.BaseBattleAction;
import leo.proxy.battles.vo.AddObjectVO;
import leo.view.role.MapObject;
import leo.view.ui.UIBattleResult;
import leo.view.ui.UIBattleView;
/
* 播放器工具
* @author Leo
*
*/
public class PlayerUtil
{
private static var _I :PlayerUtil = null;
/
* 开始播放
*/
private var start :Boolean = false;
/
* 当前正在播放的动作
*/
private var curAction :BaseBattleAction;
/
* 当前播放的序列
*/
private var curIndex :int;
/
* 需要播放的列表
*/
private var actionList :Array;
public function PlayerUtil(prv :PrivateClass)
{
}
/
* 开始播放战斗
* @param actionList
*
*/
public function playBattle(actionList :Array):void
{
if(!actionList || actionList.length == 0)
{
return;
}
this.actionList = actionList;
this.curIndex = 0;
this.start = true;
curAction = actionList[curIndex];
curAction.exec();
}
/
* 更新播放序列
*
*/
public function update ():void
{
if(!start || !this.actionList || this.actionList.length == 0)
{
return;
}
if(curAction.allActionFinish)
{
this.curIndex++;
if(this.curIndex > this.actionList.length - 1)
{
//播放完成,战斗结束
this.start = false;
resetAction();
winOrlose();
return;
}
this.curAction = this.actionList[this.curIndex];
this.curAction.exec();
}
}
/
* 获取近身攻击后人物返回的点
* @param fireObj
* @return
*
*/
public function getGoBackPoint(fireObj :MapObject):Point
{
var battleView :UIBattleView = LayerUtil.I.layerDict[UIBattleView.NAME] as UIBattleView;
var home :Boolean = fireObj.addObjVO.roleType == AddObjectVO.TYPE_HERO ? true : false;
var p :Point = battleView.battlePlace.getPlacePosition(fireObj.addObjVO.place,home);
return p;
}
/
* 停止战斗音乐
*/
public function stopBattleMusic():void
{
//停止战斗音乐
SoundManager.instance.stop("BattleMusic");
}
/
* 播放战斗音乐
*/
public function playBattleMusic():void
{
//停止战斗音乐
SoundManager.instance.play("BattleMusic",-1);
}
/
* 播放受伤音乐
*/
public function playHurtMusic():void
{
SoundManager.instance.play("HurtMusic");
}
/
* 播放技能效果音乐
*/
public function playSkillMusic():void
{
SoundManager.instance.play("SkillMusic");
}
/
* 重置战斗命令
*
*/
public function resetAction():void
{
for each(var baseBattleAction :BaseBattleAction in this.actionList)
{
if(baseBattleAction.allActionFinish)
{
baseBattleAction.allActionFinish = false;
}
if(baseBattleAction.queue)
{
baseBattleAction.queue.halt();
}
}
}
private function winOrlose():void
{
var roleList :Vector.
= RoleManage.I.roleList; var result :Boolean = false; for each(var mapObj :MapObject in roleList) { if(mapObj && mapObj.isAlive) { if(mapObj.addObjVO.roleType == AddObjectVO.TYPE_HERO) { result = true; break; } } } var uiBattleView :UIBattleView = LayerUtil.I.getLayer(UIBattleView.NAME) as UIBattleView; if(uiBattleView) { if(result) //战斗胜利 { uiBattleView.battleRoleLayer.addChild(new UIBattleResult(true)); }else // 战斗失败 { uiBattleView.battleRoleLayer.addChild(new UIBattleResult(false)); } }else { trace("PlayerUtil 战斗UI查找出错"); } } public static function get I():PlayerUtil { if(_I == null) { _I = new PlayerUtil(new PrivateClass()); } return _I; } } } class PrivateClass{}
private function winOrlose():void{}来获得战斗结果,最后交由
var uiBattleView :UIBattleView = LayerUtil.I.getLayer(UIBattleView.NAME) as UIBattleView;
if(uiBattleView)
{
if(result) //战斗胜利
{
uiBattleView.battleRoleLayer.addChild(new UIBattleResult(true));
}else // 战斗失败
{
uiBattleView.battleRoleLayer.addChild(new UIBattleResult(false));
}
}else
{
trace("PlayerUtil 战斗UI查找出错");
}
上面只是走了一遍基本流程,整个战斗系统相对庞大(这里就不都贴出来了,不是我的作品,开源别人的东西不道德),需要源码的小伙伴私信给我就好。我们看下战斗效果。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/228812.html原文链接:https://javaforall.net
