设计模式实战学习笔记(二):模板、有限状态机FSM、角色管理系统

(六)模板模式

模板方法模式:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤,是一种基于继承的代码复用技术。

相关链接:https://blog.csdn.net/lovelion/article/details/8299794

模板模式代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TemplateMethodDemo:MonoBehaviour
{
    void Start()
    {
        IPeople nor = new NorthPeople();
        nor.Eat();
    }
}

public abstract class IPeople
{
    public void Eat()
    {
        OrderFoods();
        EatSomething();
        PayBill();
    }

    public void OrderFoods() {
        Debug.Log("—点单");
    }

    public abstract void EatSomething();

    public void PayBill()
    {
        Debug.Log("—买单");
    }
}

public class NorthPeople : IPeople
{
    public override void EatSomething()
    {
        Debug.Log("我在吃面条");
    }
}

public class SouthPeople : IPeople
{
    public override void EatSomething()
    {
        Debug.Log("我在吃米饭");
    }
}

对武器的开火方法进行改写:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class IWeapon
{
    protected int mAtk;//最大攻击力
    protected float mAtkRange;//最大攻击范围
    protected int mAtkPlusValue;//暴击

    protected GameObject mGameObject;//武器模型
    protected ICharacter mOwner;//武器持有者
    protected ParticleSystem mParticle;//武器特效
    protected LineRenderer mLineRender;//武器射线
    protected Light mLight;
    protected AudioSource mAudioSource; //音效

    protected float mEffectDisplayTime;//特效显示时间

    public void Fire(Vector3 targetPos)
    {
        //显示枪口特效
        GunShootEffect();

        //显示子弹轨迹特效
        GunBulletEffect(targetPos);

        //设置特效显示时间
        SetDisplayEffectTime();

        //播放声音
        PlayAudioSources();
    }

    public void Update()
    {
        if (mEffectDisplayTime > 0)
        {
            mEffectDisplayTime -= Time.deltaTime;
            if (mEffectDisplayTime <= 0)
            {
                DisableEffect();
            }
        }
    }

    protected abstract void SetDisplayEffectTime();

    protected virtual void GunShootEffect()
    {
        DoGunShootEffect();
    }

    protected void DoGunShootEffect()
    {
        mParticle.Stop();
        mParticle.Play();
        mLight.enabled = true;
    }

    protected abstract void GunBulletEffect(Vector3 targetPos);
    protected void DoGunBulletEffect(Vector3 targetPos, float Width)
    {
        mLineRender.enabled = true;
        mLineRender.startWidth = Width;
        mLineRender.endWidth = Width;
        mLineRender.SetPosition(0, mGameObject.transform.position);
        mLineRender.SetPosition(1, targetPos);
    }

    protected abstract void PlayAudioSources();
    protected void DoPlayAudioSources(string str)
    {
        string clipName = str;
        AudioClip clip = null; //TODO 后面会对资源加载进行管理,先不做改动
        mAudioSource.clip = clip;
        mAudioSource.Play();
    }
    //结束特效显示
    private void DisableEffect()
    {
        mLight.enabled = false;
        mLineRender.enabled = false;
    }
}

其子类重写方法,如:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WeaponGun: IWeapon
{
    protected override void GunBulletEffect(Vector3 targetPos)
    {
        DoGunBulletEffect(targetPos,0.1f);
    }

    protected override void PlayAudioSources()
    {
        DoPlayAudioSources("GunShot"); 
    }

    protected override void SetDisplayEffectTime()
    {
        mEffectDisplayTime = 0.2f;
    }
}

(七)有限状态机FSM:

相关链接http://wiki.unity3d.com/index.php/Finite_State_Machine

开发战士状态的抽象接口 ISoldierState

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum SoldierTransition
{
    NullTransition,
    SeeEnemy,
    CanAttack,
    NoEnemy,
}

public enum SoldierStateID
{
    NullState,
    Idle,
    Chase,
    Attack
}

public abstract class ISoldierState
{
    protected Dictionary mapDict = new Dictionary();

    protected ICharacter mCharacter; //属于哪个角色

    protected SoldierFSMSystem mSoldierFSMSystem;

    protected SoldierStateID mSoldierStateID;
    public SoldierStateID stateID { get { return stateID; } }

    public ISoldierState(SoldierFSMSystem fsm, ICharacter c)
    {
        this.mSoldierFSMSystem = fsm;
        mCharacter = c;
    }

    public void AddTransition(SoldierTransition tran, SoldierStateID id)
    {
        if (tran == SoldierTransition.NullTransition)
        {
            Debug.Log("SoldierState Error : tran不能为空"); return;
        }
        if (id == SoldierStateID.NullState)
        {
            Debug.Log("SoldierState Error : id不能为空"); return;
        }
        if (mapDict.ContainsKey(tran))
        {
            Debug.Log("SoldierState Error :"+tran+"已经添加过了"); return;
        }
        mapDict.Add(tran, id);
    }

    public void DelectTransition(SoldierTransition tran, SoldierStateID id)
    {
        if (tran == SoldierTransition.NullTransition)
        {
            Debug.Log("SoldierState Error : tran不能为空"); return;
        }
        if (mapDict.ContainsKey(tran))
        {
            mapDict.Remove(tran);
            return;
        }
        Debug.Log("SoldierState Error : id was not on the state's transition list");
    }

    public SoldierStateID GetPutoutStateID(SoldierTransition tran)
    {
        if (mapDict.ContainsKey(tran))
        {
            return mapDict[tran];
        }
        return SoldierStateID.NullState;
    }

    public virtual void DoBeforeEntering() { }
    public virtual void DoBeforeLeaving() { }
    /// 
    /// 控制行为
    /// 
    public abstract void Act(List targets);
    /// 
    /// 此方法决定状态是否应该转换到其列表中的另一个状态
    /// 
    /// 要跟随/攻击的目标
    public abstract void Reason(List targets); 
}

开发状态管理类 SoldierFSMSystem

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SoldierFSMSystem
{
    private List stateList = new List();
    private ISoldierState mCurrentState;
    public ISoldierState CurrentState { get { return mCurrentState; } }

    public void AddState(ISoldierState state)
    {
        if (state == null)
        {
            Debug.Log("要添加的状态为空");
            return;
        }
        if (stateList.Count == 0)
        {
            stateList.Add(state);
            mCurrentState = state;
            return;
        }
        foreach (ISoldierState s in stateList)
        {
            if (s.stateID == state.stateID)
            {
                Debug.Log("存在相同的ID");
                return;
            }
        }
        stateList.Add(state);
    }

    public void DelectState(SoldierStateID stateID)
    {
        if (stateID == SoldierStateID.NullState)
        {
            Debug.Log("要删除的ID状态为空_"+stateID);
        }
        foreach (ISoldierState state in stateList)
        {
            if (state.stateID == stateID)
            {
                stateList.Remove(state);return;
            }
        }
        Debug.Log("要删除的ID状态不在集合中_" + stateID);
    }

    public void PerformTransiton(SoldierTransition trans)
    {
        if (trans == SoldierTransition.NullTransition)
        {
            Debug.LogWarning("要执行的转换条件为空:" + trans); return;
        }
        SoldierStateID currentID = CurrentState.GetPutoutStateID(trans);
        if (currentID == SoldierStateID.NullState)
        {
            Debug.LogWarning("在转换条件[" + trans+"]下没有对应的状态"); return;
        }
        foreach (ISoldierState state in stateList)
        {
            if (state.stateID == currentID)
            {
                mCurrentState.DoBeforeLeaving();
                mCurrentState = state;
                mCurrentState.DoBeforeEntering();
            }
        }
    }
}

战士状态图:

 

设计模式实战学习笔记(二):模板、有限状态机FSM、角色管理系统_第1张图片

开发战士的Idle状态:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SoldierIdleState : ISoldierState
{
    public SoldierIdleState(SoldierFSMSystem fsm, ICharacter c) :base(fsm,c) { mSoldierStateID = SoldierStateID.Idle; }

    public override void Act(List targets)
    {
        mCharacter.SetAnimation("stand");
    }

    public override void Reason(List targets)
    {
        if (targets != null && targets.Count > 0)
        {
            mSoldierFSMSystem.PerformTransiton(SoldierTransition.SeeEnemy);
        }
    }
}

在ICharacter类中添加方法:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public abstract class ICharacter
{
    protected GameObject mGameObject;//游戏角色
    protected NavMeshAgent mNavMeshAgent;
    protected AudioSource mAudioSource;
    protected ICharacterAttr mCharacterAttri;//角色属性
    protected Animation mAnimation;//角色动画
    protected IWeapon mWeapon;
    public IWeapon Weapon { set { mWeapon = value; } }

    public float mAtkRange { get { return mWeapon.AtkRange; } } //武器的攻击距离

    public void Attack(ICharacter targetPos)
    {

        //TODO
        mWeapon.Fire(targetPos.GetPosition);
    }

    /// 
    /// 得到角色位置
    /// 
    /// 
    public Vector3 GetPosition
    {
        get
        {
            if (mGameObject == null)
            {
                Debug.LogWarning("mGameObject为空");
                return Vector3.zero;
            }
            return mGameObject.transform.position;
        }
    }
    /// 
    /// 设置角色动画
    /// 
    /// 
    public void SetAnimation(string animName)
    {
        mAnimation.CrossFade(animName);
    }
    /// 
    /// 追击状态下,移动至目标
    /// 
    /// 
    public void MoveToTarget(Vector3 target)
    {
        mNavMeshAgent.SetDestination(target);
    }

}

开发战士的Chase状态:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SoldierChaseState : ISoldierState
{
    public SoldierChaseState(SoldierFSMSystem fsm, ICharacter c) : base(fsm, c) { mSoldierStateID = SoldierStateID.Chase; }

    public override void Act(List targets)
    {
        if (targets.Count > 0 && targets != null)
        {
            mCharacter.MoveToTarget(targets[0].GetPosition);
        }
    }

    public override void Reason(List targets)
    {
        //没有敌人时,转换为NoEnemy状态
        if (targets.Count == 0 || targets == null)
        {
            mSoldierFSMSystem.PerformTransiton(SoldierTransition.NoEnemy); return;
        }
        //当角色和敌人距离小于攻击武器范围时,转换为攻击状态
        if (targets.Count > 0 && targets != null)
        {
            float dist = Vector3.Distance(targets[0].GetPosition, mCharacter.GetPosition);
            if (dist <= mCharacter.mAtkRange)
            {
                mSoldierFSMSystem.PerformTransiton(SoldierTransition.CanAttack);
            }
        }

    }
}

开发战士的Attack状态:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SoldierAttackState : ISoldierState
{
    public SoldierAttackState(SoldierFSMSystem fsm, ICharacter c) : base(fsm, c)
    {
        mSoldierStateID = SoldierStateID.Attack;
        mAttackIntervalTimer = mAttackIntervalTime;
    }

    private float mAttackIntervalTime = 1;//攻击间隔为一秒
    private float mAttackIntervalTimer = 1;//攻击间隔计时器

    public override void Act(List targets)
    {
        if (targets.Count == 0 || targets == null) return;
        if (targets != null && targets.Count > 0)
        {
            mAttackIntervalTimer += Time.deltaTime;
            if (mAttackIntervalTimer >= mAttackIntervalTime)
            {
                mCharacter.Attack(targets[0]);
                mAttackIntervalTimer = 0;
            }
        }
    }

    public override void Reason(List targets)
    {
        if (targets == null || targets.Count == 0)
        {
            mSoldierFSMSystem.PerformTransiton(SoldierTransition.NoEnemy); return;
        }
        //有敌人时,检测距离,距离小于攻击范围时转换为追击状态
        if (targets != null && targets.Count > 0)
        {
            float dist = Vector3.Distance(targets[0].GetPosition, mCharacter.GetPosition);
            if (dist > mCharacter.mAtkRange)
            {
                mSoldierFSMSystem.PerformTransiton(SoldierTransition.SeeEnemy); return;
            }
        }
    }
}

构建战士的有限状态机ISoldier

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ISoldier : ICharacter {

    protected SoldierFSMSystem mSoldierFSMSystem;

    public ISoldier():base()
    {
        MakeFSM();
    }
   
    public override void UpdateFSMAI(List targets)
    {
        mSoldierFSMSystem.CurrentState.Act(targets);
        mSoldierFSMSystem.CurrentState.Reason(targets);
    }

    public void MakeFSM()
    {
        SoldierAttackState attackState = new SoldierAttackState(mSoldierFSMSystem,this);
        attackState.AddTransition(SoldierTransition.NoEnemy,SoldierStateID.Idle);
        attackState.AddTransition(SoldierTransition.SeeEnemy, SoldierStateID.Chase);

        SoldierIdleState idleState = new SoldierIdleState(mSoldierFSMSystem, this);
        idleState .AddTransition(SoldierTransition.SeeEnemy, SoldierStateID.Chase);

        SoldierChaseState chaseState = new SoldierChaseState(mSoldierFSMSystem, this);
        chaseState .AddTransition(SoldierTransition.CanAttack, SoldierStateID.Attack);
        chaseState .AddTransition(SoldierTransition.NoEnemy, SoldierStateID.Idle);

        mSoldierFSMSystem = new SoldierFSMSystem();

        mSoldierFSMSystem.AddState(idleState);
        mSoldierFSMSystem.AddState(attackState);
        mSoldierFSMSystem.AddState(chaseState);
    }

}

 

UML图解

设计模式实战学习笔记(二):模板、有限状态机FSM、角色管理系统_第2张图片

设计敌人的有限状态机

类似于战士的状态机。

开发敌人状态的抽象接口 IEnemyState

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum EnemyTransition
{
    CanAttack,
    LostSoldier,
    NullTransition,
}

public enum EnemyStateID
{
    NullStateID,
    Chase,
    Attack,
}

public abstract class IEnemyState
{
    private Dictionary EnemyStateDict = new Dictionary();

    protected ICharacter mCharacter;
    protected EnemyFSMSystem mEnemyFSMSystem;
    protected EnemyStateID mEnemyStateID;
    public EnemyStateID EnemyStateID { get { return mEnemyStateID; } }

    public IEnemyState(EnemyFSMSystem fsm, ICharacter c)
    {
        this.mEnemyFSMSystem = fsm;
        mCharacter = c;
    }

    public void AddTransiton(EnemyTransition trans, EnemyStateID id)
    {
        if (trans == EnemyTransition.NullTransition)
        {
            Debug.Log("EnemyState Error : tran不能为空"); return;
        }
        if (id == EnemyStateID.NullStateID)
        {
            Debug.Log("EnemyState Error : id不能为空"); return;
        }
        if (EnemyStateDict.ContainsKey(trans))
        {
            Debug.Log("EnemyState Error :" + trans + "已经添加过了"); return;
        }
        EnemyStateDict.Add(trans, id);
    }

    public void DelectTransition(EnemyTransition trans)
    {
        if (trans == EnemyTransition.NullTransition)
        {
            Debug.Log("EnemyState Error : tran不能为空"); return;
        }
        if (EnemyStateDict.ContainsKey(trans))
        {
            EnemyStateDict.Remove(trans);
        }
        Debug.Log("EnemyState Error : id was not on the state's transition list");
    }

    public EnemyStateID GetPutoutID(EnemyTransition trans)
    {
        if (EnemyStateDict.ContainsKey(trans))
        {
            return EnemyStateDict[trans];
        }
        return EnemyStateID.NullStateID;
    }

    public virtual void DoBeforeEntering() { }
    public virtual void DoBeforeLeaving() { }

    public abstract void Act(List targets);
    public abstract void Reason(List targets);

}

开发状态管理类 EnemyFSMSystem

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyFSMSystem
{
    private List mEnemyStatesList = new List();
    private IEnemyState mCurrentState;
    public IEnemyState CurrentState{ get { return mCurrentState; } }

    public void AddState(IEnemyState state)
    {
        if (state == null)
        {
            Debug.Log("要添加的状态为空");
            return;

        }
        if (mEnemyStatesList.Count == 0)
        {
            mEnemyStatesList.Add(state);
            mCurrentState = state;
            mCurrentState.DoBeforeEntering(); //++
            return;
        }

        foreach (IEnemyState states in mEnemyStatesList)
        {
            if (states.EnemyStateID == state.EnemyStateID)
            {
                Debug.Log("存在相同的ID");
                return;
            }
        }
        mEnemyStatesList.Add(state);
    }

    public void DelectState(EnemyStateID stateID)
    {
        if (stateID == EnemyStateID.NullStateID)
        {
            Debug.Log("要删除的ID没有对应的状态");
        }
        foreach (IEnemyState states in mEnemyStatesList)
        {
            if (states.EnemyStateID == stateID)
            {
                mEnemyStatesList.Remove(states);
                return;
            }
        }
        Debug.Log("要删除的ID状态不在集合中_" + stateID);
    }

    public void PerformTransition(EnemyTransition trans)
    {
        if (trans == EnemyTransition.NullTransition)
        {
            Debug.LogWarning("要执行的转换条件为空:" + trans); return;
        }
        EnemyStateID currenID = mCurrentState.GetPutoutID(trans);
        if (currenID == EnemyStateID.NullStateID)
        {
            Debug.LogWarning("在转换条件[" + trans + "]下没有对应的状态"); return;
        }
        foreach (IEnemyState states in mEnemyStatesList)
        {
            if (states.EnemyStateID == currenID)
            {
                mCurrentState.DoBeforeLeaving();
                mCurrentState = states;
                mCurrentState.DoBeforeEntering();
            }
        }
    }
}

敌人状态图:

设计模式实战学习笔记(二):模板、有限状态机FSM、角色管理系统_第3张图片

EnemyAttackState  敌人的攻击状态

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyAttackState : IEnemyState
{
    public EnemyAttackState(EnemyFSMSystem fsm, ICharacter c) : base(fsm, c)
    {
        mEnemyStateID = EnemyStateID.Attack;
        mAttackIntervalTimer = mAttackIntervalTime;
    }

    private float mAttackIntervalTime = 1;//攻击间隔为一秒
    private float mAttackIntervalTimer = 1;//攻击间隔计时器

    public override void Act(List targets)
    {
        if (targets.Count == 0 || targets == null) return;
            mAttackIntervalTimer += Time.deltaTime;
            if (mAttackIntervalTimer >= mAttackIntervalTime)
            {
                mCharacter.Attack(targets[0]);
                mAttackIntervalTimer = 0;
            }
    }

    public override void Reason(List targets)
    {
        if (targets == null || targets.Count == 0)
        {
            mEnemyFSMSystem.PerformTransition(EnemyTransition.LostSoldier); return;
        }
        else
        {
            float dist = Vector3.Distance(targets[0].GetPosition, mCharacter.GetPosition);
            if (dist > mCharacter.mAtkRange)
            {
                mEnemyFSMSystem.PerformTransition(EnemyTransition.LostSoldier);
            }
        }
    }
}

EnemyChaseState  敌人的追击状态

重写了DoBeforeEntering(),利用中介者类Gamefacade得到敌人位置(后续开发)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyChaseState : IEnemyState
{
    public EnemyChaseState(EnemyFSMSystem fsm, ICharacter c) : base(fsm, c) { mEnemyStateID = EnemyStateID.Chase; }

    private Vector3 mTargetPosition;
    public override void DoBeforeEntering()
    {
        mTargetPosition = GameFacade.Instance.GetEnemyTargetPosition();
    }

    public override void Act(List targets)
    {
        if (targets != null && targets.Count > 0)
        {
            mCharacter.MoveToTarget(targets[0].GetPosition);
        }
        else
        {
            mCharacter.MoveToTarget(mTargetPosition);
        }

    }

    public override void Reason(List targets)
    {
        if (targets != null && targets.Count > 0)
        {
            float dist = Vector3.Distance(targets[0].GetPosition, mCharacter.GetPosition);
            if (dist <= mCharacter.mAtkRange)
            {
                mEnemyFSMSystem.PerformTransition(EnemyTransition.CanAttack);
            }
        }
    }

}

构建敌人的有限状态机

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class IEnemy : ICharacter
{
    protected EnemyFSMSystem fsm;

    public IEnemy()
    {
        MakeFSM();
    }

    public override void UpdateFSMAI(List targets)
    {
        fsm.CurrentState.Reason(targets);
        fsm.CurrentState.Act(targets);
    }

    public void MakeFSM()
    {
        fsm = new EnemyFSMSystem();

        EnemyChaseState eEnemyChaseState = new EnemyChaseState(fsm, this);
        eEnemyChaseState.AddTransiton(EnemyTransition.CanAttack, EnemyStateID.Attack);

        EnemyAttackState eEnemyAttackState = new EnemyAttackState(fsm, this);
        eEnemyAttackState.AddTransiton(EnemyTransition.LostSoldier, EnemyStateID.Chase);

        fsm.AddState(eEnemyChaseState);
        fsm.AddState(eEnemyAttackState);
    }
}

(八)角色管理系统

开发角色管理系统CharacterSystem:

管理所有角色,对其进行Update更新,并将ISoldier和IEnemy的UpdateFSMAI方法提取到ICharacter中,作为抽象方法;ICharacter中加入Update方法对IWeapon的Update()方法进行更新:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// 
/// 管理当前游戏所有实例化出的敌人和战士的更新
/// 
public class CharacterSystem : IGameSystem
{
    private List EnemyList = new List();
    private List SoldierList = new List();

    public void AddEnemy(IEnemy enemy)
    {
        //if (enemy == null) return;
        EnemyList.Add(enemy);
    }

    public void RemoveEnemy(IEnemy enemy)
    {
        //if (enemy == null) return;
        EnemyList.Remove(enemy);
    }

    public void AddSoldier(ISoldier soldier)
    {
        //if (enemy == null) return;
        SoldierList.Add(soldier);
    }

    public void RemoveSoldier(ISoldier soldier)
    {
        //if (enemy == null) return;
        SoldierList.Remove(soldier);
    }

    public override void Update()
    {
        foreach (ISoldier soldier in SoldierList)
        {
            soldier.Update();
            soldier.UpdateFSMAI(EnemyList);
        }

        foreach (IEnemy enemy in EnemyList)
        {
            enemy.Update();
            enemy.UpdateFSMAI(SoldierList);
        }
    }
}

 

 

对角色的攻击功能进行开发:

完善ICharacter的Attack方法,写入UnderAttck() - 受到攻击后的方法 - 调用自ICharacterAttri 角色属性接口,

ICharacterAttri中对收到攻击进行伤害计算 - 包括 暴击、血量等

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public abstract class ICharacter
{
    protected GameObject mGameObject;//游戏角色
    protected NavMeshAgent mNavMeshAgent;
    protected AudioSource mAudioSource;
    protected ICharacterAttr mCharacterAttri;//角色属性
    protected Animation mAnimation;//角色动画
    protected IWeapon mWeapon;
    public IWeapon Weapon { set { mWeapon = value; } }

    public float mAtkRange { get { return mWeapon.AtkRange; } } //武器的攻击距离

    public void Update()
    {
        mWeapon.Update();
    }

    public abstract void UpdateFSMAI(List targets);

    public void Attack(ICharacter target)
    {
        mWeapon.Fire(target.GetPosition);
        mGameObject.transform.LookAt(target.GetPosition);
        mAnimation.Play("attack");
        target.UnderAttck((int)mWeapon.Atk+mCharacterAttri.CritValue);
    }
    /// 
    /// 受到伤害后执行的方法
    /// 
    /// 受到的伤害
    public virtual void UnderAttck(int damage)
    {
        mCharacterAttri.TakeDamege(damage);
    }

    /// 
    /// 得到角色位置
    /// 
    /// 
    public Vector3 GetPosition
    {
        get
        {
            if (mGameObject == null)
            {
                Debug.LogWarning("mGameObject为空");
                return Vector3.zero;
            }
            return mGameObject.transform.position;
        }
    }
    /// 
    /// 设置角色动画
    /// 
    /// 
    public void SetAnimation(string animName)
    {
        mAnimation.CrossFade(animName);
    }
    /// 
    /// 追击状态下,移动至目标
    /// 
    /// 
    public void MoveToTarget(Vector3 target)
    {
        mNavMeshAgent.SetDestination(target);
        mAnimation.Play("move");
    }

}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ICharacterAttr
{
    protected string mName;
    protected int mMaxHp;
    protected float mMoveSpeed;
    protected int mCurrentHP;
    protected string mIconSprite; // 资源加载

    protected int mLv;
    protected float mCritRate;//0-1暴击率
    protected int mDmgDescValue; //减少的伤害

    private IAttrStrategy mStrategy;
    //角色实例化时就决定属性
    public ICharacterAttr(IAttrStrategy strategy)
    {
        mStrategy = strategy;
        mDmgDescValue = mStrategy.GetCritDmg(mCritRate);
        mCurrentHP = mMaxHp + mStrategy.GetExtraHPValue(mLv);
    }
    public int CritValue { get { return mStrategy.GetCritDmg(mCritRate); } }
    /// 
    /// 被攻击后的处理
    /// 
    /// 受到的伤害
    public void TakeDamege(int damage)
    {
        damage -= mDmgDescValue;
        if (damage <= 5) damage = 5;
        mCurrentHP -= damage;
    }
}

重写ICharacter的UnderAttck()方法,处理敌人和战士被攻击的效果:

被攻击的特效  (只有敌人有),死亡的动画、音频 (只有战士有)

Killed()、DoPlaySound()、DoPlayEffect()方法放在ICharacter中,因为战士和敌人都用得到

战士:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class ISoldier : ICharacter
{

    protected SoldierFSMSystem mSoldierFSMSystem;

    public ISoldier() : base()
    {
        MakeFSM();
    }

    public override void UpdateFSMAI(List targets)
    {
        mSoldierFSMSystem.CurrentState.Act(targets);
        mSoldierFSMSystem.CurrentState.Reason(targets);
    }

    public void MakeFSM()
    {
        SoldierAttackState attackState = new SoldierAttackState(mSoldierFSMSystem, this);
        attackState.AddTransition(SoldierTransition.NoEnemy, SoldierStateID.Idle);
        attackState.AddTransition(SoldierTransition.SeeEnemy, SoldierStateID.Chase);

        SoldierIdleState idleState = new SoldierIdleState(mSoldierFSMSystem, this);
        attackState.AddTransition(SoldierTransition.SeeEnemy, SoldierStateID.Chase);

        SoldierChaseState chaseState = new SoldierChaseState(mSoldierFSMSystem, this);
        attackState.AddTransition(SoldierTransition.CanAttack, SoldierStateID.Attack);
        attackState.AddTransition(SoldierTransition.NoEnemy, SoldierStateID.Idle);

        mSoldierFSMSystem = new SoldierFSMSystem();

        mSoldierFSMSystem.AddState(attackState);
        mSoldierFSMSystem.AddState(idleState);
        mSoldierFSMSystem.AddState(chaseState);
    }

    public override void UnderAttck(int damage)
    {
        base.UnderAttck(damage);
        if (mCharacterAttri.CurrentHP <= 0)
        {
            PlaySound();
            PlayEffect();
            Killed();
        }

    }

    public abstract void PlaySound();
    public abstract void PlayEffect();
}

战士子类 如:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// 
/// 上尉
/// 
public class SoldierCaptain : ISoldier
{
    public override void PlayEffect()
    {
        DoPlayEffect("CaptainDeadEffect");
    }

    public override void PlaySound()
    {
        DoPlaySound("CaptainDeath");
    }
}

敌人:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class IEnemy : ICharacter
{
    protected EnemyFSMSystem fsm;

    public IEnemy()
    {
        MakeFSM();
    }

    public override void UpdateFSMAI(List targets)
    {
        fsm.CurrentState.Reason(targets);
        fsm.CurrentState.Act(targets);
    }

    public void MakeFSM()
    {
        fsm = new EnemyFSMSystem();

        EnemyChaseState eEnemyChaseState = new EnemyChaseState(fsm, this);
        eEnemyChaseState.AddTransiton(EnemyTransition.CanAttack, EnemyStateID.Attack);

        EnemyAttackState eEnemyAttackState = new EnemyAttackState(fsm, this);
        eEnemyAttackState.AddTransiton(EnemyTransition.LostSoldier, EnemyStateID.Chase);

    }

    public override void UnderAttck(int damage)
    {
        base.UnderAttck(damage);
        PlayEffect();
        if (mCharacterAttri.CurrentHP <= 0)
        {
            Killed();
        }
    }
    //每个Enemy被攻击的特效不同
    protected abstract void PlayEffect();
}

敌人子类,如:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyOgre : IEnemy
{
    protected override void PlayEffect()
    {
        DoPlayEffect("OgreHitEffect");
    }
}

ICharacter:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public abstract class ICharacter
{
    protected GameObject mGameObject;//游戏角色
    protected NavMeshAgent mNavMeshAgent;
    protected AudioSource mAudioSource;
    protected ICharacterAttr mCharacterAttri;//角色属性
    protected Animation mAnimation;//角色动画
    protected IWeapon mWeapon;
    public IWeapon Weapon { set { mWeapon = value; } }

    public float mAtkRange { get { return mWeapon.AtkRange; } } //武器的攻击距离

    public void Update()
    {
        mWeapon.Update();
    }

    public abstract void UpdateFSMAI(List targets);

    public void Attack(ICharacter target)
    {
        mWeapon.Fire(target.GetPosition);
        mGameObject.transform.LookAt(target.GetPosition);
        mAnimation.Play("attack");
    }
    /// 
    /// 受到伤害后执行的方法
    /// 
    /// 受到的伤害
    public virtual void UnderAttck(int damage)
    {
        //被攻击的特效  (只有敌人有)
        //死亡的动画、音频 (只有战士有)
        mCharacterAttri.TakeDamege(damage);
    }

    protected void Killed()
    {
        //TODO
    }


    /// 
    /// 得到角色位置
    /// 
    /// 
    public Vector3 GetPosition
    {
        get
        {
            if (mGameObject == null)
            {
                Debug.LogWarning("mGameObject为空");
                return Vector3.zero;
            }
            return mGameObject.transform.position;
        }
    }
    /// 
    /// 设置角色动画
    /// 
    /// 
    public void SetAnimation(string animName)
    {
        mAnimation.CrossFade(animName);
    }
    /// 
    /// 追击状态下,移动至目标
    /// 
    /// 
    public void MoveToTarget(Vector3 target)
    {
        mNavMeshAgent.SetDestination(target);
        mAnimation.Play("move");
    }

    protected void DoPlayEffect(string effectName)
    {
        //加载特效 TODO 
        GameObject effectGO;
        //控制销毁 TODO
    }
    protected void DoPlaySound(string clipName)
    {
        AudioClip clip = null; //TODO 统一进行资源加载
        mAudioSource.clip = clip;
        mAudioSource.Play();
    }
}

 

你可能感兴趣的:(设计模式学习笔记)