mirror镜像模块,主要学习AI逻辑
目录
什么是镜像?
机器人,模拟玩家。随机的名字,拥有主副侠客,侠客都是从表里配死的,境界、星级、属性。
镜像,拥有玩家性质的生物角色,可以从机器人身上拷贝生物性质,也可以直接从玩家身上拷贝生物性质。
类继承关系
1.类图
2.所有状态机抽象类AbstractAIState
/**
* 状态机抽象类
*
* @author wangguohao
* @time 2017年7月6日 - 下午5:00:08
*/
public abstract class AbstractAIState<E extends AbstractCharacter>
{
/**
* 当前状态可转换的状态
*
*/
protected EnumSet<StateEnum> transitionState = EnumSet.noneOf(StateEnum.class);
/**
* 判断是否可以进入此状态
* @param e
* @return
*/
public boolean canEnter(E e)
{
return true;
}
/**
* 进入当前状态要做的事
* @param e
* @return
*/
public abstract boolean enter(E e);
/**
* 判断是否可以退出此状态
* @param e
* @return
*/
public boolean canExit(E e)
{
return true;
}
/**
* 退出当前状态要做的事
* @param e
* @return
*/
public abstract boolean exit(E e);
...
}
所有状态机的抽象父类,
镜像、npc、傀儡…状态机的实现都是继承自AbstractAIState。
AbstractAIState
传入对象必须是继承AbstractCharacter,拥有生物类属性的对象。
抽象一些方法,判断是否可以进入此状态、进入当前状态要做的事…, 子类各自覆写实现。
3.镜像抽象类AbstractMirrorAIState
/**
* 镜像基础AI状态类
*/
public abstract class AbstractMirrorAIState extends AbstractAIState<Mirror>
{
/**
* 检查目标是否继续有效
* @param mirror
* @return true=有效 false=失效
*/
protected boolean checkTarget(Mirror mirror)
{
...
}
}
传入的对象是Mirror
将检查目标是否继续有效提到公共层
4.镜像AI状态类
/**
* 镜像AI状态机 - Idle状态
* <pre>
* 可转换状态 : Battle状态 、 Persuit状态
* 状态机逻辑 : 1.如果镜像死亡或者不能攻击,将一直留在Idle状态
* 2.判断敌人的状态,如果死亡则一直停留在Idle状态
* 3.选择一个可释放技能,如果是刚开始需要顺序释放镜像的防守技能,放完一遍防守技能随机使用技能
* 4.根据随机的技能,判断和敌人的距离,不够则追击(转换到 Persuit状态),距离够则使用技能攻击( Battle状态)
* </pre>
*/
public class MirrorIdleState extends AbstractMirrorAIState
空闲状态机,Idle状态
/**
* 镜像追击状态
*/
public class MirrorPursuitState extends AbstractMirrorAIState
镜像追击状态
/**
* 镜像AI状态 - 战斗状态
* <p>
* 主要负责释放技能,释放完技能就转换成Idle状态,释放技的过程中仍然在该状态
* </p>
*/
public class MirrorBattleState extends AbstractMirrorAIState
战斗状态
/**
* 特殊控制状态
*/
public class MirrorSpecialControlState extends AbstractMirrorAIState
特殊控制状态
5.状态机管理类BaseAIFsmManager
/**
* 状态机管理类
*/
public class BaseAIFsmManager<T extends AbstractCharacter>
{
/**
* 当前状态
*/
AbstractAIState<T> curState;
/**
* 转换状态 ( 当前帧不会转换,下一帧才转换)
*
* @param stateEnum
*/
public boolean transtTo(StateEnum stateEnum)
{
...
}
/**
* Tick
*/
public void tick(int interval)
{
if (curState == null)
{
return;
}
curState.tick(owner, interval);
}
}
主要的成员属性和方法,缓存了一个当前状态,转换状态,tick
例如:MirrorAiModule模块缓存了一个BaseAIFsmManager状态机管理类,
BaseAIFsmManager缓存当前状态,根据当前状态进行tick。
AI流程
1.调用mirror.init();
BPCopySceneFightArenaGame:
@Override
public void onActorEnter(Actor actor)
{
...
...
//初始化镜像数据
Mirror mirror = new Mirror(mirrorData);
mirror.init();
//添加镜像到场景
addBPObject(mirror);
...
...
}
比武小游戏场景,玩家添加进场景是。
同时,mirror.init()将镜像初始化,addBPObject添加到场景。
2.镜像AI模块初始化
MirrorAiModule:
@Override
public void init()
{
//顺序释放技能队列 (第一个侠客先按配招放一遍技能,然后随机放;第二个侠客直接随机放)
sequenceSkillQueue = new BPIntArrayDeque();
//初始化状态机管理类
aiFsmManager = new BaseAIFsmManager<>(getMirror());
//初始化状态机为空闲状态机,并添加状态机列表
List<AbstractAIState<Mirror>> states = new ArrayList<>();
states.add(MirrorIdleState.getInstance());
states.add(MirrorBattleState.getInstance());
states.add(MirrorPursuitState.getInstance());
states.add(MirrorSpecialControlState.getInstance());
aiFsmManager.init(StateEnum.IDLE, states);
//初始化强控制参数
aiSpecialControlParam = AISpeicalcontrolParamFactory.create();
aiSpecialControlParam.init();
//是否释放完了顺序技能 默认为true
this.hasSequenceSkillDone = true;
//上次普攻是否是子技能(非蓄力技能)
lastNormalSkillIsSequence = false;
//上次的技能序号
lastSkillIndex = 0;
}
顺序释放技能队列 (第一个侠客先按配招放一遍技能,然后随机放;第二个侠客直接随机放)
初始化状态机管理类
初始化状态机为空闲状态机,并添加状态机列表
初始化强控制参数,是否释放完了顺序技能,上次普攻是否是子技能(非蓄力技能),上次的技能序号
3.激活镜像AI
AbstractBPCopySceneFightArena:
/**
* 状态进入 : 战斗
*/
@Override
protected void onEnterStateFight()
{
//是否打镜像
if (isMirrorFight)
{
Mirror mirror = getMirror();
if (mirror != null)
{
// 设置敌人objectId(镜像的敌人一定是挑战者)
mirror.getMirrorAiModule().setEnemyObjectId(this.getChallengerObjectId());
// 激活镜像的AI
mirror.getMirrorAiModule().activeAI();
}
}
}
设置敌人objectId(镜像的敌人一定是挑战者)
激活镜像的AI,镜像AI逻辑开始tick
4.开始tick
MirrorAiModule:
@Override
public void tick(int interval)
{
if (!active)
{
return;
}
tickRemain -= interval;
if (tickRemain > 0)
{
return;
}
//tick间隔时间
tickRemain = TICK_INTERVAL;
// 状态机管理类tick
aiFsmManager.tick(totalInterval);
}
减少tick频率,
执行aiFsmManager.tick(totalInterval);
5.镜像上来状态的idle状态,idle状态的tick
MirrorIdleState:
@Override
public void tickImpl(Mirror mirror, int interval)
{
...
...
// 判断敌人是否存在
MirrorAiModule mirrorAiModule = mirror.getMirrorAiModule();
//敌人的ObjectID
int enemyObjectId = mirrorAiModule.getEnemyObjectId();
AbstractCharacter targetObject = mirror.getCharacter(enemyObjectId);
}