【ARPG/MOBA类游戏游戏系列】技能系统设计

    其实技能系统有很多种设计方式,暂且列出一种以前项目的设计。
    目标:
    1.使用尽可能少的类,实现游戏里所有种类的技能。

    2.满足打击感的可调节性、可配置性。 
    3.能基本满足绝大部分角色扮演类游戏(比如ARPG、卡牌、Moba、ACT等),更换项目只需要对代码做微调。 ACT类,连击技能需要在技能类调用之前做计数,剩余的代码一样。

    需求分析:
        根据上面的目标,我们把攻击分为几个模块  

       1.目标选择   2.攻击准备  3. 开始攻击  4.受击特效与动作  5.伤害结算、飙血浮动条、血条减少。  6.技能打断

       注意。技能打断,可配置该技能在XXX秒--XXX秒之间可被打断。

       就不详细解释了,具体实现看代码,有注释。



   [mw_shl_code=applescript,true]public abstract class SkillBase 
{
    //技能状态
    public SkillState State { get; protected set; }
    public int SkillID { get { return dataVo == null ? 0 : dataVo.ID; } }
    public SkillDataVo dataVo { get; protected set; }

    //特效
    protected GameObject effect;
    protected bool ifInitEffect = false; //是否已经播放了特效
    protected float effectBeginTime;
    protected float effectTime = 5f;     //特效时长

    //伤害
    protected bool damaged = false;     //是否已经计算了伤害


    //动画
    protected float curAnimalLength;//当前动画时长
    protected string animalName;
    protected float CurCd;
    protected SpriteController owner;
    protected float timer;

    //回收动作
    protected bool IfUseActionReturn;
    protected float ActionReturnTime;


    //攻击目标、角度范围、距离
    protected bool InForward(Transform trans, float _angle, float _dis)
    {
        if (null == trans)
        {
            return false;
        }



        // 获得从当前Obj到目标Obj的方向,然后求和当前Obj的朝向夹角。
        Vector2 tarPos = new Vector2(trans.position.x, trans.position.z);
        Vector2 myPos = new Vector2(owner.transform.position.x, owner.transform.position.z);
        Vector2 mydir = new Vector2(owner.transform.forward.x, owner.transform.forward.z);
        Vector2 dir = tarPos - myPos;
        float angle = Vector2.Angle(mydir.normalized, dir.normalized);


if (angle < _angle / 2f)
        {

            float toPosDis = Vector2.Distance(tarPos, myPos);
            if (toPosDis <= _dis)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        return false;
    }


    public SkillBase(SpriteController obj, int skillID)
    {
        State = SkillState.None;
        this.owner = obj;
        this.CurCd = 0f;

        dataVo = ConfigDataManager.GetSkillDataByID(skillID);
        if (owner.ActionMng != null && owner.ActionMng.TryGetAnimationLength(dataVo.actionName, out curAnimalLength))
        {
            //curAnimalLength -= 0f;
        }
        else
            curAnimalLength = 1f;

        if (dataVo.BufferID.Length > 0)
        {
            dataVo.bufferEntity = new BufferDataVo[dataVo.BufferID.Length];
            for (int i = 0; i < dataVo.bufferEntity.Length; i++)
            {
                dataVo.bufferEntity = ConfigDataManager.GetConfigBufferData(dataVo.BufferID);
            }
        }
        animalName = dataVo.actionName;

        //加载特效
        GameObject effectPre = LoadCache.LoadEffect(dataVo.effectName);
        if (effectPre != null)
        {
            effect = GameObject.Instantiate(effectPre) as GameObject;
            effect.SetActive(false);
        }

    }

    //  Interrupts
    virtual public void SetInterrupts() { State = SkillState.Interrupts; }


    virtual public void ProcessBuffer(int index) {  }


    virtual public bool IsCanInterrupts() 
    {
        if (State == SkillState.None)
            return true;

        if (dataVo.minInterrupt != -1 && timer <= dataVo.minInterrupt)
            return true;

        if (dataVo.maxInterrupt != -1 && timer >= dataVo.maxInterrupt)
            return true;

        return false;
    }

    virtual public void Execute()  
    {
        switch (State)
        {
            case SkillState.Start:
                break;
            case SkillState.Execution:
                break;
            case SkillState.Interrupts:
                break;
            case SkillState.Finish:
                break;
        }
    
    }

    virtual public void Begin()
    {
        State = SkillState.Start;
    }

    //这是一个模
    virtual public void DoUpdate() 
    {
        if (State == SkillState.None)
        {
            return;
        }

      //  if (owner.mAIState == AIState.Dead)
         //   return;

        Execute();
        CalcCd();
    }


    public bool IsCanUse()
    {
        return State == SkillState.None;
    }

    //CD计时
    public void CalcCd()
    {
        CurCd += RealTime.deltaTime;
        if ( CurCd >= dataVo.CD)
        {
            CurCd = 0f;
        }
    }


}[/mw_shl_code]



我们编写了一个超类,规定了技能的实现过程和方式、以及保存了技能的公有信息。
然后我们实现一个子类,能涵盖绝大部分的技能。

[mw_shl_code=applescript,true]public class Skill_Default : SkillBase 
{

    private bool isMove;

    SkillEzMoveData moveData;

    Vector3 moveDir;

    public Skill_Default(SpriteController obj, int skillID)
        : base(obj, skillID)
    {
    }

    //遍历场景所有怪物
    void ForALLEnmy()
    {
        Dictionary<long, SpriteController> dic = BattlerDataManager.Instance.DicMonsters;
        //List<long> tmpList = new List<long>();
        foreach (SpriteController controller in dic.Values)
        {
            if (controller.mAIState == AIState.Dead)

                continue;

            //技能的伤害判断和处理
            bool inforward = InForward(controller.transform, dataVo.attackFanAngle, dataVo.attackFanRange);
            if (inforward)
            {
                int damageValue = dataVo.harm;
                owner.AttackTo(controller, damageValue);
Util.CallMethod("FightingPanel", "UpdateHeroHpMp", BattlerDataManager.Instance.SelfPlayer.SpiritVO.CurHp, BattlerDataManager.Instance.SelfPlayer.SpiritVO.CurMp);   //刷新角色血条

                //            if (BattlerDataManager.Instance.SelfPlayer.mAIState  == AIState.Dead)
                //            {
                //                //玩家死亡
                //
                //            }
                if (BattlerDataManager.Instance.SelfPlayer.SpiritVO.CurHp <= 0)
                {
                    //玩家死亡
                    // Util.CallMethod("FightingPanel", "Lose");
                }
            }
        }
    }



    public override void Execute()
    {

        switch (State)
        {
            case SkillState.Start:
                moveDir = owner.MoveToPostion; 
                timer = 0f;
                effectBeginTime = 0;
                owner.MoveMng.StopMove();
                isMove = false;
               // IfUseActionReturn = false;
                damaged = false;
                ifInitEffect = false;
                //执行
                owner.mAIState = AIState.Attack;
                owner.ActionMng.PlayAnimation(animalName);
                State = SkillState.Execution;

                Debug.Log("skill ID "+dataVo.ID);

                break;
            case SkillState.Interrupts:
                {
                    Debug.Log("被打断");
                    State = SkillState.None;
                }
                break;
            case SkillState.Execution:
                {
                    timer += Time.deltaTime;

                    //触发伤害
                    if (!damaged && timer > dataVo.damageTime)
                    {
                        damaged = true;
                        //伤害结算
                        ForALLEnmy();
                    }

                    //触发特效
                    if (!ifInitEffect && timer > dataVo.fxStartTime)
                    {
                        if (effect != null)
                        {
                            effect.transform.position = owner.transform.position + new Vector3(0, 0.5f, 0)+owner.transform.forward*2;
                            effect.transform.rotation = owner.transform.rotation;
                            effect.SetActive(false);
                            effect.SetActive(true);
                        }

                        ifInitEffect = true;
                    }

                    //动画播放结束,并且触发了特效,触发了伤害
                    if (timer >= curAnimalLength && damaged && ifInitEffect)
                    {
                        State = SkillState.Finish;
                    }
                    
                }
            break;

            case SkillState.Finish:
                {
                    Debug.Log("Finish");
  if (effect != null)
   effect.SetActive(false);
                    owner.mAIState = AIState.Idle;
                    State = SkillState.None;

                }
                break;
        }

    }
}
[/mw_shl_code]

有注释的情况下,应该不难看懂,抛砖引玉。

转载于:https://www.cnblogs.com/sundayofit/p/7995474.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值