设计模式实战学习笔记(四):享元、组合、命令模式

本文介绍了游戏开发中享元、组合、命令模式的应用。通过享元模式优化角色和武器属性存储,降低内存占用;利用组合模式实现UI界面设计;采用命令模式管理兵营系统,包括训练士兵的命令执行与UI交互。同时,文章还涉及UI系统、能量系统的设计与策略模式的运用。

(十一)享元模式:

当相同的角色(如多个新手士兵)共享多个不变的属性时,使不变的属性只存在一份(会变化的属性如 当前生命值、等级…),每次要使用的时候,就去储存相同属性的BaseAttr工厂中取得该属性,可减少所占用的内存。

——重构代码——

完成战士/敌人角色的构造(使用享元) :

将ICharacterAttr 中的基础属性删除,创建CharacterBaseAttr用于管理角色的相同基础属性:

/// <summary>
///管理游戏角色共有的属性
/// </summary>
public class CharacterBaseAttr
{
    protected string mName;
    protected int mMaxHp;
    protected float mMoveSpeed;
    protected string mIconSprite; // 资源加载
    protected string mPrefabName;// 通过Prefab名字实例化Prefab
    protected float mCritRate;//0-1暴击率

    public CharacterBaseAttr(string Name, int MaxHp, float MoveSpeed, string IconSprite, string PrefabName, float CritRate)
    {
        this.mName = Name;
        this.mMaxHp = MaxHp;
        this.mMoveSpeed = MoveSpeed;
        this.mIconSprite = IconSprite;
        this.mPrefabName = PrefabName;
        this.mCritRate = CritRate;
    }

    public string Name { get { return mName; } }
    public int MaxHp { get { return mMaxHp; } }
    public float MoveSpeed { get { return mMoveSpeed; } }
    public string IconSprite { get { return mIconSprite; } }
    public string PrefabName { get { return mPrefabName; } }
    public float CritRate { get { return mCritRate; } }
}

创建工厂接口类IAttrFactory,写入用于得到角色基础的方法:

public interface IAttrFactory
{
    CharacterBaseAttr GetCharacterBaseAttr(System.Type t);
}

创建工厂类AttrFactory(享元模式核心),用字典将 通过战士/敌人的类型来存储战士/敌人的基础属性,每次实例化战士/敌人只需要调用 得到角色基础属性的方法 ,不需要每次都在内存中存一份相同的基础属性。构造方法中将所有需要共享的对象初始化

/// <summary>
/// 享元模式核心 
/// </summary>
public class AttrFactory : IAttrFactory
{
    //通过角色类型来存储角色共有的属性
    private Dictionary<Type, CharacterBaseAttr> mCharacterBaseAttrDict;

    /// <summary>
    /// 构造方法中将所有需要共享的对象初始化
    /// </summary>
    public AttrFactory()
    {
        InitCharacterBaseAttr();
    }

    private void InitCharacterBaseAttr()
    {
        //初始化字典
        mCharacterBaseAttrDict = new Dictionary<Type, CharacterBaseAttr>();

        mCharacterBaseAttrDict.Add(typeof(SoldierRookie), new CharacterBaseAttr("新手士兵", 80, 2.5f, "RookieIcon", "Soldier3", 0));
        mCharacterBaseAttrDict.Add(typeof(SoldierSergeant), new CharacterBaseAttr("中士士兵", 90, 3, "SergeantIcon", "Soldier2", 0));
        mCharacterBaseAttrDict.Add(typeof(SoldierCaptain), new CharacterBaseAttr("上尉士兵", 100, 3, "CaptainIcon", "Soldier1", 0));

        mCharacterBaseAttrDict.Add(typeof(EnemyElf), new CharacterBaseAttr("小精灵", 100, 3, "ElfIcon", "Enemy1", 0.2f));
        mCharacterBaseAttrDict.Add(typeof(EnemyOgre), new CharacterBaseAttr("怪物", 120, 2, "OgreIcon", "Enemy2", 0.3f));
        mCharacterBaseAttrDict.Add(typeof(EnemyTroll), new CharacterBaseAttr("巨魔", 200, 1, "TrollIcon", "Enemy3", 0.2f));
    }
    /// <summary>
    /// 得到角色基础属性
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public CharacterBaseAttr GetCharacterBaseAttr(Type t)
    {
        if (mCharacterBaseAttrDict.ContainsKey(t) == false)
        {
            Debug.LogWarning("无法根据类型["+t+"]得到角色的基础属性"); return null;
        }
        return mCharacterBaseAttrDict[t];
    }

}

在FactoryManager中加入IAttrFactory 静态属性,可用于外界调用:

public static class FactoryManager
{
    private static IAssetFactory mAssetFactory;
    private static IWeaponFactory mWeaponFactory;
    private static ICharacterFactory mSoldierFactory;
    private static ICharacterFactory mEnemyFactory;
    private static IAttrFactory mAttrFactory;

    public static IAttrFactory attrFactory
    {
        get
        {
            if (mAttrFactory== null)
            {
                mAttrFactory= new ResourcesAssetFactory();
            }
            return mAttrFactory;
        }
    }
省略………

在ICharacterAttr中声明可被子类取得的属性 CharacterBaseAttr , 修改其构造方法,将基础属性 改为 CharacterBaseAttr类,并修改其子类的构造方法:

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

public class ICharacterAttr
{
    protected CharacterBaseAttr mCharacterBaseAttr;

    protected int mLv;
    protected int mCurrentHP;
    protected int mDmgDescValue; //减少的伤害

    public int CurrentHP { get { return mCurrentHP; } }

    private IAttrStrategy mStrategy;

    //角色实例化时就决定属性,后续不改变
    public ICharacterAttr(IAttrStrategy strategy, int lv, CharacterBaseAttr characterBaseAttr)
    {
        mCharacterBaseAttr = characterBaseAttr;
        mLv = lv;

        mStrategy = strategy;
        mDmgDescValue = mStrategy.GetCritDmg(mCharacterBaseAttr.CritRate);
        mCurrentHP = mCharacterBaseAttr.MaxHp + mStrategy.GetExtraHPValue(mLv);
    }
    public int CritValue { get { return mStrategy.GetCritDmg(mCharacterBaseAttr.CritRate); } }

    /// <summary>
    /// 被攻击后的处理
    /// </summary>
    /// <param name="damage">受到的伤害</param>
    public void TakeDamege(int damage)
    {
        damage -= mDmgDescValue;
        if (damage <= 5) damage = 5;
        mCurrentHP -= damage;
    }
}

修改SoldierBuilder 和 EnemyrBuilder的 AddCharacterAttr()  给角色添加属性的方法:

 

通过FactoryManager调用attrFactory 属性工厂的 GetCharacterBaseAttr()方法,得到角色基础属性:

public class SoldierBuilder : ICharacterBuilder
{
 
    public SoldierBuilder(ICharacter character, Type t, WeaponType weaponType, Vector3 spawnPos, int lv) : base(character, t, weaponType, spawnPos, lv){
    }

    public override void AddCharacterAttr()
    {
        CharacterBaseAttr characterBaseAttr =  FactoryManager.attrFactory.GetCharacterBaseAttr(mT);
        mPrefabName = characterBaseAttr.PrefabName;
        ICharacterAttr attr = new SoldierAttr(new SoldierAttrStrategy(), mLV, characterBaseAttr);
        mCharacter.CharacterAttri = attr;
    }
public class EnemyrBuilder : ICharacterBuilder
{
    public EnemyrBuilder(ICharacter character, Type t, WeaponType weaponType, Vector3 spawnPos, int lv) : base(character, t, weaponType, spawnPos, lv){ }

    public override void AddCharacterAttr()
    {
        CharacterBaseAttr characterBaseAttr = FactoryManager.attrFactory.GetCharacterBaseAttr(mT);
        mPrefabName = characterBaseAttr.PrefabName;
        ICharacterAttr attr = new EnemyAttr(new EnemyAttrStrategy(), mLV, characterBaseAttr);
        mCharacter.CharacterAttri = attr;
    }
省略……

将武器属性修改为享元模式 :

将IWeaponAttr 中的基础属性删除,创建CharacterBaseAttr用于管理角色的基础属性:

public class WeaponBaseAttr
{
    protected string mName;
    protected int mAtk;//最大攻击力
    protected float mAtkRange;//最大攻击范围
    protected string mAssetsName;//资源名称

    public WeaponBaseAttr(string Name,int Atk,float AtkRange,string AssetsName)
    {
        mName = Name;
        mAtk = Atk;
        mAtkRange = AtkRange;
        mAssetsName = AssetsName;
    }

    public string Name { get { return mName; } }
    public int Atk { get { return Atk; } }
    public float AtkRange { get { return mAtkRange; } }
    public string AssetsName { get { return mAssetsName; } }
}

在IWeaponAttr  中声明可被子类取得的属性 WeaponBaseAttr , 修改其构造方法,将基础属性 改为 WeaponBaseAttr 类,并

修改其子类的构造方法

public abstract class IWeapon
{

    //protected int mAtkPlusValue;//暴击
    protected WeaponBaseAttr mWeaponBaseAttr;

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

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

    public float AtkRange { get { return mWeaponBaseAttr.AtkRange; } }
    public float Atk { get { return mWeaponBaseAttr.Atk; } } // 武器攻击力
    public ICharacter Owner { set { mOwner = value; } }
    public GameObject gameObject { get { return mGameObject; } }

    public IWeapon(WeaponBaseAttr weaponBaseAttr, GameObject gameObject)
    {
        mWeaponBaseAttr = weaponBaseAttr;
        mGameObject = gameObject;
        //得到武器特效射线灯光音效的组件,在武器的子物体Effect中
        Transform effect = mGameObject.transform.Find("Effect");
        mParticle = effect.GetComponent<ParticleSystem>();
        mLineRender = effect.GetComponent<LineRenderer>();
        mLight = effect.GetComponent<Light>();
        mAudioSource = effect.GetComponent<AudioSource>();
    }

在IAttrFactory中加入得到武器基础属性的方法:

public interface IAttrFactory
{
    CharacterBaseAttr GetCharacterBaseAttr(System.Type t);
    WeaponBaseAttr GetWeaponBaseAttr(WeaponType weaponType);
}

在AttrFactory中用字典将 通过武器的类型来存储武器的基础属性,每次实例化武器只需要调用 得到角色基础属性的方法 ,不需要每次都在内存中存一份相同的基础属性构造方法中将所有需要共享的对象初始化

/// <summary>
/// 享元模式核心 
/// </summary>
public class AttrFactory : IAttrFactory
{
    //通过角色类型来存储角色共有的属性
    private Dictionary<Type, CharacterBaseAttr> mCharacterBaseAttrDict;
    private Dictionary<WeaponType, WeaponBaseAttr> mWeaponBaseAttrDict;

    /// <summary>
    /// 构造方法中将所有需要共享的对象初始化
    /// </summary>
    public AttrFactory()
    {
        InitCharacterBaseAttr();
        InitWeaponBaseAttr();
    }

    private void InitWeaponBaseAttr()
    {
        //初始化字典
        mWeaponBaseAttrDict = new Dictionary<WeaponType, WeaponBaseAttr>();

        mWeaponBaseAttrDict.Add(WeaponType.Gun, new WeaponBaseAttr("手枪",20, 5, "WeaponGun"));
        mWeaponBaseAttrDict.Add(WeaponType.Rifle, new WeaponBaseAttr("长枪",30, 7, "WeaponRifle"));
        mWeaponBaseAttrDict.Add(WeaponType.Rocket, new WeaponBaseAttr("火箭",40, 8, "WeaponRocket"));
    }

    private void InitCharacterBaseAttr()
    {
        //初始化字典
        mCharacterBaseAttrDict = new Dictionary<Type, CharacterBaseAttr>();

        mCharacterBaseAttrDict.Add(typeof(SoldierRookie), new CharacterBaseAttr("新手士兵", 80, 2.5f, "RookieIcon", "Soldier3", 0));
        mCharacterBaseAttrDict.Add(typeof(SoldierSergeant), new CharacterBaseAttr("中士士兵", 90, 3, "SergeantIcon", "Soldier2", 0));
        mCharacterBaseAttrDict.Add(typeof(SoldierCaptain), new CharacterBaseAttr("上尉士兵", 100, 3, "CaptainIcon", "Soldier1", 0));

        mCharacterBaseAttrDict.Add(typeof(EnemyElf), new CharacterBaseAttr("小精灵", 100, 3, "ElfIcon", "Enemy1", 0.2f));
        mCharacterBaseAttrDict.Add(typeof(EnemyOgre), new CharacterBaseAttr("小精灵", 120, 2, "OgreIcon", "Enemy2", 0.3f));
        mCharacterBaseAttrDict.Add(typeof(EnemyElf), new CharacterBaseAttr("巨魔", 200, 1, "TrollIcon", "Enemy3", 0.2f));
    }
    /// <summary>
    /// 得到角色基础属性
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public CharacterBaseAttr GetCharacterBaseAttr(Type t)
    {
        if (mCharacterBaseAttrDict.ContainsKey(t) == false)
        {
            Debug.LogWarning("无法根据类型["+t+"]得到角色的基础属性"); return null;
        }
        return mCharacterBaseAttrDict[t];
    }

    /// <summary>
    /// 得到武器基础属性
    /// </summary>
    /// <param name="weaponType"></param>
    /// <returns></returns>
    public WeaponBaseAttr GetWeaponBaseAttr(WeaponType weaponType)
    {
        if(mWeaponBaseAttrDict.ContainsKey(weaponType) == false)
        {
            Debug.LogWarning("无法根据类型[" + weaponType + "]得到武器的基础属性"); return null;
        }
        return mWeaponBaseAttrDict[weaponType];
    }
}

修改WeaponFactory的创建武器方法CreateWeapon():

public class WeaponFactory : IWeaponFactory
{
    public IWeapon CreateWeapon(WeaponType weaponType)
    {
        IWeapon weapon = null;
        WeaponBaseAttr weaponBaseAttr = FactoryManager.attrFactory.GetWeaponBaseAttr(weaponType);

        GameObject weaponGO= FactoryManager.assetFactory.LoadWeapon(weaponBaseAttr.AssetsName);
        switch (weaponType)
        {
            case WeaponType.Gun:
                weapon = new WeaponGun(weaponBaseAttr, weaponGO);
                break;
            case WeaponType.Rifle:
                weapon = new WeaponRifle(weaponBaseAttr, weaponGO);
                break;
            case WeaponType.Rocket:
                weapon = new WeaponRocket(weaponBaseAttr, weaponGO);
                break;
        }
        return weapon;
    }
}

(十二)组合模式:

事例代码:

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

public class CompositeDM : MonoBehaviour
{
    void Start()
    {
        DMComposite root = new DMComposite("root");

        DMLeaf leaf1 = new DMLeaf("leaf1");
        DMComposite c1 = new DMComposite("composite1");
        DMLeaf leaf2 = new DMLeaf("leaf2");

        root.AddChild(leaf1);
        root.AddChild(c1);
        root.AddChild(leaf2);

        DMLeaf g1 = new DMLeaf("GameObject");
        DMLeaf g2 = new DMLeaf("GameObject (1)");

        c1.AddChild(g1);
        c1.AddChild(g2);

        ReadComposite(root);
    }

    //深度优先
    private void ReadComposite(DMComponent c)
    {
        Debug.Log(c.name);

        List<DMComponent> c1 = c.ComponentList;

        if (c1 == null || c1.Count == 0)  return; 
        foreach (DMComponent item in c1)
        {
            ReadComposite(item);
        }
    }
}

public abstract class DMComponent
{
    protected List<DMComponent> mComponentList;
    protected string mName;

    public string name { get { return mName; } }
    public List<DMComponent> ComponentList { get { return mComponentList; } }

    public DMComponent(string Name)
    {
        mComponentList = new List<DMComponent>();
        mName = Name;
    }

    public abstract void AddChild(DMComponent c);
    public abstract void RemoveChild(DMComponent c);
    public abstract DMComponent GetChild(int index);
}

public class DMLeaf : DMComponent
{
    public DMLeaf(string Name) : base(Name) { }

    public override void AddChild(DMComponent c)
    {
        return;
    }

    public override void RemoveChild(DMComponent c)
    {
        return;
    }

    public override DMComponent GetChild(int index)
    {
        return null;
    }
}

public class DMComposite : DMComponent
{
    public DMComposite(string Name) : base(Name) { }

    public override void AddChild(DMComponent c)
    {
        mComponentList.Add(c);
    }

    public override DMComponent GetChild(int index)
    {
        return mComponentList[index];
    }

    public override void RemoveChild(DMComponent c)
    {
        mComponentList.Remove(c);
    }
}

(十三)UI界面设计部分:

UI查找工具类:

public static class UITools  {

    public static T FindChild<T>(GameObject parent,string childName)
    {
        GameObject uiGO = UnityTools.FindChild(parent,childName);
        if (uiGO == null)
        {
            Debug.LogError("在游戏物体" + parent + "下面查找不到" + childName);
            return default(T);
        }
        return uiGO.GetComponent<T>();
    }

}

IBaseUI部分:

public abstract class IBaseUI
{
    public GameObject mRootUI;

    public virtual void Init() { }
    public virtual void Release() { }
    public virtual void Update(){ }

    public void Show()
    {
        mRootUI.SetActive(true);
    }

    public void Hide()
    {
        mRootUI.SetActive(false);
    }  
}

UI信息部分:

public class GamePauseUI : IBaseUI
{
    private Text mCurrentStageLv;
    private Button mContinueBtn;
    private Button mBackMenuBtn;

    public override void Init()
    {
        base.Init();
        GameObject canvas = GameObject.Find("Canvas");
        mRootUI = UnityTools.FindChild(canvas, "GamePauseUI");

        mCurrentStageLv = UITools.FindChild<Text>(mRootUI, "CurrentStageLv");
        mContinueBtn = UITools.FindChild<Button>(mRootUI, "ContinueBtn");
        mBackMenuBtn = UITools.FindChild<Button>(mRootUI, "BackMenuBtn"); 
        Hide();  
    }
}

public class SoldierInfoUI : IBaseUI
{
    private Image mSoldierIcon;
    private Image mSoldierName;
    private Text mHPText;
    private Slider mHPSlider;
    private Text mLv;
    private Text mAtk;
    private Text mAtkRange;
    private Text mMoveSpeed;

    public override void Init()
    {
        base.Init();
        GameObject canvas = GameObject.Find("Canvas");
        mRootUI = UnityTools.FindChild(canvas, "SoldierInfoUI");

        mSoldierIcon = UITools.FindChild<Image>(mRootUI, "SoldierIcon");
        mSoldierName = UITools.FindChild<Image>(mRootUI, "SoldierName");
        mHPText = UITools.FindChild<Text>(mRootUI, "HPNumber");
        mHPSlider = UITools.FindChild<Slider>(mRootUI, "HPSlider");
        mLv = UITools.FindChild<Text>(mRootUI, "Level");
        mAtk = UITools.FindChild<Text>(mRootUI, "Atk");
        mAtkRange = UITools.FindChild<Text>(mRootUI, "AtkRange");
        mMoveSpeed = UITools.FindChild<Text>(mRootUI, "MoveSpeed");
        Hide();  
    }
}

public class CampInfoUI : IBaseUI
{
    private Image mCampIcon;
    private Text mCampName;
    private Text mCampLevel;
    private Text mWeaponLevel;
    private Button mCampUpgradeBtn;
    private Button mWeaponUpgradeBtn;
    private Button mTrainBtn;
    private Text mTrainBtnText;
    private Button mCancelTrainBtn;
    private Text mAliveCount;
    private Text mTrainingCount;
    private Text mTrainTime;

    public override void Init()
    {
        base.Init();
        GameObject canvas = GameObject.Find("Canvas");
        mRootUI = UnityTools.FindChild(canvas, "CampInfoUI");

        mCampIcon = UITools.FindChild<Image>(mRootUI, "CampIcon");
        mCampName = UITools.FindChild<Text>(mRootUI, "CampName");
        mCampLevel = UITools.FindChild<Text>(mRootUI, "CampLv");
        mWeaponLevel = UITools.FindChild<Text>(mRootUI, "WeaponLv");
        mCampUpgradeBtn = UITools.FindChild<Button>(mRootUI, "CampUpgradeBtn");
        mWeaponUpgradeBtn = UITools.FindChild<Button>(mRootUI, "WeaponUpgradeBtn");
        mTrainBtn = UITools.FindChild<Button>(mRootUI, "TrainBtn");
        mTrainBtnText = UITools.FindChild<Text>(mRootUI, "TrainBtnText");
        mCancelTrainBtn = UITools.FindChild<Button>(mRootUI, "CancelTrainBtn");
        mAliveCount = UITools.FindChild<Text>(mRootUI, "AliveCount");
        mTrainingCount = UITools.FindChild<Text>(mRootUI, "TrainingCount");
        mTrainTime = UITools.FindChild<Text>(mRootUI, "TrainTime");
        Hide();  
    }
}


public class GameStateUI : IBaseUI
{
    private List<GameObject> mHearts; //左上角星星
    private Text mSoldierCount;
    private Text mEnemyCount;
    private Text mCurrentStage;
    private Button mPauseBtn;
    private GameObject mGameOverUI;
    private Button mBackMenuBtn;
    private Text mMessage;
    private Slider mEnergySlider;
    private Text mEnergyText;

    public override void Init()
    {
        base.Init(); base.Init();
        GameObject canvas = GameObject.Find("Canvas");
        mRootUI = UnityTools.FindChild(canvas, "GameStateUI");

        GameObject heart1 = UnityTools.FindChild(mRootUI, "Heart1");
        GameObject heart2 = UnityTools.FindChild(mRootUI, "Heart2");
        GameObject heart3 = UnityTools.FindChild(mRootUI, "Heart3");
        mHearts = new List<GameObject>  // 简化集合,即为Add():
        {
            heart1,
            heart2,
            heart3
        };
        mSoldierCount = UITools.FindChild<Text>(mRootUI, "SoldierCount");

        mEnemyCount = UITools.FindChild<Text>(mRootUI, "EnemyCount");
        mCurrentStage = UITools.FindChild<Text>(mRootUI, "StageCount");
        mPauseBtn = UITools.FindChild<Button>(mRootUI, "PauseBtn");
        mGameOverUI = UnityTools.FindChild(mRootUI, "GameOver");
        mBackMenuBtn = UITools.FindChild<Button>(mRootUI, "BackMenuBtn");
        mMessage = UITools.FindChild<Text>(mRootUI, "Message");
        mEnergySlider = UITools.FindChild<Slider>(mRootUI, "EnergySlider");
        mEnergyText = UITools.FindChild<Text>(mRootUI, "EnergyText");

        mMessage.text = "";
        mGameOverUI.SetActive(false);
    }
}

(十四) :命令模式(兵营系统)

创建脚本ICamp作为兵营的父类,并声明构造方法

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

public abstract class ICamp
{
    protected GameObject mGameObject; //兵营
    protected string mName;
    protected string mIconSprite;
    protected SoldierType mSoldierType;
    protected Vector3 mPos; // 集合位置
    protected float mTrainTime; //训练时间

    public ICamp(GameObject gameObject,string name,string iconSprite,SoldierType soldierType,Vector3 pos,float trainTime)
    {
        mGameObject = gameObject;
        mName = name;
        mIconSprite = iconSprite;
        mSoldierType = soldierType;
        mPos = pos;
        mTrainTime = trainTime;
    }

    public virtual void Update()
    {

    }
}

在ISoldier中声明SoldierType 士兵类型

public enum SoldierType
{
  Rookie,
  Sergeant,
  Captain
}

创建SoldierCamp,继承自ICamp

public class SoldierCamp : ICamp
{

    private int mMAX_Lv;
    private int mLv =1;
    private WeaponType mWeaponType = WeaponType.Gun;

    public SoldierCamp(GameObject gameObject, string name, string iconSprite, SoldierType soldierType, Vector3 pos,float trainTime, WeaponType weaponType = WeaponType.Gun, int lv = 1)
        : base(gameObject, name, iconSprite, soldierType, pos,trainTime)
    {
        mLv = lv;
        mWeaponType = weaponType;
    }

    public override void Update()
    {
        
    }
}

创建兵营系统 CampSystem,管理所有兵营的更新

public class CampSystem : IGameSystem
{
    private Dictionary<SoldierType, SoldierCamp> mSoldierCampDict = new Dictionary<SoldierType, SoldierCamp>();

    public override void Init()
    {
        base.Init();
        InitCamp(SoldierType.Rookie);
        InitCamp(SoldierType.Sergeant);
        InitCamp(SoldierType.Captain);
    }
    /// <summary>
    /// 初始化创建兵营
    /// </summary>
    private void InitCamp(SoldierType soldierType)
    {
        GameObject gameObject = null;
        string gameObjectName = null;
        string name = null;
        string iconSprite = null;
        Vector3 pos = Vector3.zero;
        float trainTime = 0;

        switch (soldierType)
        {
            case SoldierType.Rookie:
                gameObjectName = "SoldierCamp_Rookie";
                name = "新手兵营";
                iconSprite = "RookieCamp";
                trainTime = 3;
                break;
            case SoldierType.Sergeant:
                gameObjectName = "SoldierCamp_Sergeant";
                name = "中士兵营";
                iconSprite = "SergeantCamp";
                trainTime = 4;
                break;
            case SoldierType.Captain:
                gameObjectName = "SoldierCamp_Captain";
                name = "上尉兵营";
                iconSprite = "CaptainCamp";
                trainTime = 5;
                break;
            default:
                Debug.LogError("无法根据战士类型" + soldierType + "初始化兵营");
                break;
        }
        gameObject = GameObject.Find(gameObjectName);
        pos = UnityTools.FindChild(gameObject, "TrainPoint").transform.position;
        SoldierCamp soldierCamp = new SoldierCamp(gameObject,name,iconSprite,soldierType,pos,trainTime);
        mSoldierCampDict.Add(soldierType,soldierCamp);
    }

    public override void Update()
    {
        //更新所有兵营的内部游戏逻辑
        foreach (SoldierCamp camp in mSoldierCampDict.Values)
        {
            camp.Update();
        }
    }
}

点击兵营显示UI界面及兵营信息:

在CampInfoUI  兵营信息显示的脚本中声明ShowCampInfoUI() 方法用于UI的显示以及显示兵营信息

    public void ShowCampInfoUI(ICamp camp)
    {
        Show();
    }

在GameFacade脚本中声明ShowCampInfoUI()方法,用于在外界调用

    public void ShowCampInfoUI(ICamp camp)
    {
        campInfoUI.ShowCampInfoUI(camp);
    }

创建脚本CampUIOnClick,继承自mono,OnMouseUpAsButton方法—> MonoBehaviour.OnMouseUpAsButton()

public class CampUIOnClick : MonoBehaviour {

    private ICamp camp;
    public ICamp Camp { set { camp = value; } }

    void OnMouseUpAsButton()
    {
        GameFacade.Instance.ShowCampInfoUI(camp);
    }
}

在CampSystem中初始化兵营时将CampUIOnClick 脚本添加并为CampUIOnClick的camp属性赋值:

 /// <summary>
    /// 初始化创建兵营
    /// </summary>
    private void InitCamp(SoldierType soldierType)
    {
        GameObject gameObject = null;
        string gameObjectName = null;
        string name = null;
        string iconSprite = null;
        Vector3 pos = Vector3.zero;
        float trainTime = 0;

        switch (soldierType)
        {
          ……此处省略
        }
        gameObject = GameObject.Find(gameObjectName);
        pos = UnityTools.FindChild(gameObject, "TrainPoint").transform.position;
        SoldierCamp soldierCamp = new SoldierCamp(gameObject,name,iconSprite,soldierType,pos,trainTime);

        这句——>  gameObject.AddComponent<CampUIOnClick>().Camp = soldierCamp;

        mSoldierCampDict.Add(soldierType,soldierCamp);
    }

用get{}方法访问ICamp中的私有变量,子类的变量用abstract方法在子类中重写

ICamp:

    public string Name{ get { return mName; } }
    public string IconSprite { get { return mIconSprite; } }
    public abstract WeaponType GetCampWeaponType();
    public abstract int GetCampLv();

SoldierCamp(继承自ICamp):

    public override WeaponType GetCampWeaponType()
    {
        return mWeaponType;
    }

    public override int GetCampLv()
    {
        return mLv;
    }

修改CampInfoUI的ShowCampInfoUI()方法,使其兵营信息界面显示UI信息:

   public void ShowCampInfoUI(ICamp camp)
    {
        Show();
        mCamp = camp;
        mCampIcon.sprite = FactoryManager.assetFactory.LoadSprites(camp.IconSprite);
        mCampName.text = camp.Name;
        ShowWeaponLevel(camp.GetCampWeaponType());
        mCampLevel.text = camp.GetCampLv().ToString();
    }

    void ShowWeaponLevel(WeaponType weaponType)
    {
        switch (weaponType)
        {
            case WeaponType.Gun:
                mWeaponLevel.text = "短枪";
                break;
            case WeaponType.Rifle:
                mWeaponLevel.text = "长枪";
                break;
            case WeaponType.Rocket:
                mWeaponLevel.text = "火箭";
                break;
            case WeaponType.MAX:
                break;
            default:
                break;
        }
    }

修改资源加载工厂的方法:

    public AudioClip LoadAudioClip(string name)
    {
        return Resources.Load<AudioClip>(AudioPath + name);
    }

    public Sprite LoadSprites(string name)
    {
        return Resources.Load<Sprite>(SpritePath+name);
    }

命令模式示例脚本:

public class CommandDM : MonoBehaviour
{
    private void Start()
    {
        IDammandDM dm1 = new ConcreteCommand1(new Receiver1DM());

        InvokerDM invoker = new InvokerDM();
        invoker.AddCommand(dm1);
        invoker.ExcuteCommand();
    }
}

public class InvokerDM
{
    private List<IDammandDM> mDamandList = new List<IDammandDM>();

    public void AddCommand(IDammandDM dammandDM)
    {
        mDamandList.Add(dammandDM);
    }

    public void ExcuteCommand()
    {
        foreach (IDammandDM item in mDamandList)
        {
            item.Excute();
        }
        mDamandList.Clear();
    }

}

public abstract class IDammandDM
{
    public abstract void Excute();
}

public class ConcreteCommand1 : IDammandDM
{
    private Receiver1DM mReceiver;

    public ConcreteCommand1(Receiver1DM receiver)
    {
        mReceiver = receiver;
    }

    public override void Excute()
    {
        mReceiver.Action("Command1");
    }
}

public class Receiver1DM
{
    public void Action(string cmd)
    {
        Debug.Log("命令:" + cmd + ",Receiver1执行了命令");
    }
}

将命令模式应用于士兵的训练:

创建命令的抽象类 ITrainCommand

public abstract class ITrainCommand  {

    public abstract void Excute();
}

创建战士的命令类 SoldierTrainCommand,继承自ITrainCommand

根据不同的战士类型,调用战士工厂的创建角色方法,并声明战士工厂的创建角色时所需要的变量

public class SoldierTrainCommand : ITrainCommand
{
    private SoldierType mSoldierType;
    private WeaponType mWeaponType;
    private Vector3 mVec;
    private int mLV;

    public SoldierTrainCommand(SoldierType soldierType, WeaponType weaponType, Vector3 vec, int lv)
    {
        mSoldierType = soldierType;
        mWeaponType = weaponType;
        mVec = vec;
        mLV = lv;
    }

    public override void Excute()
    {
        switch (mSoldierType)
        {
            case SoldierType.Rookie:
                FactoryManager.soldierFactory.CreateCharacter<SoldierRookie>(mWeaponType,mVec,mLV);
                break;
            case SoldierType.Sergeant:
                FactoryManager.soldierFactory.CreateCharacter<SoldierSergeant>(mWeaponType, mVec, mLV);
                break;
            case SoldierType.Captain:
                FactoryManager.soldierFactory.CreateCharacter<SoldierCaptain>(mWeaponType, mVec, mLV);
                break;
            default:
                Debug.LogWarning("无法执行命令,无法根据SoldierType["+mSoldierType+"]创建角色");
                break;
        }
    }
}

添加训练命令和命令的管理

在ICamp 中 声明 一个管理命令的集合 mTrainCommandList ,并在构造方法中初始化

并在ICamp中 声明   添加训练士兵的命令   和   取消训练士兵命令的方法 :AddTrainCommand() 和 CancelTrainCommand()

public abstract class ICamp
{
    protected GameObject mGameObject; //兵营
    protected string mName;
    protected string mIconSprite;
    protected SoldierType mSoldierType;
    protected Vector3 mPos; // 集合位置
    protected float mTrainTime; //训练时间
    protected float mTrainTimer; //训练计时器

    protected List<ITrainCommand> mTrainCommandList; // 管理训练命令集合

    public ICamp(GameObject gameObject,string name,string iconSprite,SoldierType soldierType,Vector3 pos,float trainTime)
    {
        mGameObject = gameObject;
        mName = name;
        mIconSprite = iconSprite;
        mSoldierType = soldierType;
        mPos = pos;
        mTrainTime = trainTime;
        mTrainTimer = mTrainTime;
        mTrainCommandList = new List<ITrainCommand>();
    }

    public string Name{ get { return mName; } }
    public string IconSprite { get { return mIconSprite; } }
    public abstract WeaponType GetCampWeaponType();
    public abstract int GetCampLv();


    public virtual void Update()
    {

    }
    //训练士兵的方法
    public abstract void AddTrainCommand();

    //取消训练士兵的方法,在命令集合中将最后一个命令移除
    public void CancelTrainCommand()
    {
        if (mTrainCommandList.Count > 0)
        {
            mTrainCommandList.RemoveAt(mTrainCommandList.Count - 1);
        }
    }
}

在子类 SoldierCamp 中重写 训练方法 (避免后期添加其他兵营)

public class SoldierCamp : ICamp
{

    private int mMAX_Lv;
    private int mLv =1;
    private WeaponType mWeaponType = WeaponType.Gun;

    public SoldierCamp(GameObject gameObject, string name, string iconSprite, SoldierType soldierType, Vector3 pos,float trainTime, WeaponType weaponType = WeaponType.Gun, int lv = 1)
        : base(gameObject, name, iconSprite, soldierType, pos,trainTime)
    {
        mLv = lv;
        mWeaponType = weaponType;
    }

    public override void Update()
    {
    }

    public override WeaponType GetCampWeaponType()
    {
        return mWeaponType;
    }

    public override int GetCampLv()
    {
        return mLv;
    }

    public override void AddTrainCommand()
    {
        //添加训练命令
        SoldierTrainCommand soldierTrainCommand = new SoldierTrainCommand(mSoldierType,mWeaponType,mPos,mLv);
        mTrainCommandList.Add(soldierTrainCommand);
    }
}

接着 在 CampInfoUI 中 对训练士兵的 button 进行 点击注册:

public class CampInfoUI : IBaseUI
{
    private Image mCampIcon;
    private Text mCampName;
    private Text mCampLevel;
    private Text mWeaponLevel;
    private Button mCampUpgradeBtn;
    private Button mWeaponUpgradeBtn;
    private Button mTrainBtn;
    private Text mTrainBtnText;
    private Button mCancelTrainBtn;
    private Text mAliveCount;
    private Text mTrainingCount;
    private Text mTrainTime;

    private ICamp mCamp; // 记录兵营

    public override void Init()
    {
        base.Init();
        GameObject canvas = GameObject.Find("Canvas");
        mRootUI = UnityTools.FindChild(canvas, "CampInfoUI");

        mCampIcon = UITools.FindChild<Image>(mRootUI, "CampIcon");
        mCampName = UITools.FindChild<Text>(mRootUI, "CampName");
        mCampLevel = UITools.FindChild<Text>(mRootUI, "CampLv");
        mWeaponLevel = UITools.FindChild<Text>(mRootUI, "WeaponLv");
        mCampUpgradeBtn = UITools.FindChild<Button>(mRootUI, "CampUpgradeBtn");
        mWeaponUpgradeBtn = UITools.FindChild<Button>(mRootUI, "WeaponUpgradeBtn");
        mTrainBtn = UITools.FindChild<Button>(mRootUI, "TrainBtn");
        mTrainBtnText = UITools.FindChild<Text>(mRootUI, "TrainBtnText");
        mCancelTrainBtn = UITools.FindChild<Button>(mRootUI, "CancelTrainBtn");
        mAliveCount = UITools.FindChild<Text>(mRootUI, "AliveCount");
        mTrainingCount = UITools.FindChild<Text>(mRootUI, "TrainingCount");
        mTrainTime = UITools.FindChild<Text>(mRootUI, "TrainTime");

        mTrainBtn.onClick.AddListener(OnTrainClick);
        mCancelTrainBtn.onClick.AddListener(OnCancelTrainClick);

        Hide();
    }

    public void ShowCampInfoUI(ICamp camp)
    {
        Show();
        mCamp = camp;
        mCampIcon.sprite = FactoryManager.assetFactory.LoadSprites(camp.IconSprite);
        mCampName.text = camp.Name;
        ShowWeaponLevel(camp.GetCampWeaponType());
        mCampLevel.text = camp.GetCampLv().ToString();
    }

    void ShowWeaponLevel(WeaponType weaponType)
    {
        switch (weaponType)
        {
            case WeaponType.Gun:
                mWeaponLevel.text = "短枪";
                break;
            case WeaponType.Rifle:
                mWeaponLevel.text = "长枪";
                break;
            case WeaponType.Rocket:
                mWeaponLevel.text = "火箭";
                break;
            case WeaponType.MAX:
                break;
            default:
                break;
        }
    }

    public void OnTrainClick()
    {
        // TODO 判断能量是否足够
        mCamp.Train();
    }

    public void OnCancelTrainClick()
    {
        //TODO 将消耗的能量回收
        mCamp.CancelTrain();
    }
}

在兵营中控制训练命令的执行

声明UpdataCommand()方法,在ICamp的Update中更新其命令

利用计时器,当计时器为0时,执行 命令集合 中的第一个命令,即 List[0].excute(),再将其从集合中删除,计时器重新计时

当 取消训练士兵的命令时 ,在命令集合中将最后一个命令移除,如果没有命令,计时器重新计时

public abstract class ICamp
{
    protected GameObject mGameObject; //兵营
    protected string mName;
    protected string mIconSprite;
    protected SoldierType mSoldierType;
    protected Vector3 mPos; // 集合位置
    protected float mTrainTime; //训练时间
    protected float mTrainTimer; //训练计时器

    protected List<ITrainCommand> mTrainCommandList; // 管理训练命令集合

    public ICamp(GameObject gameObject,string name,string iconSprite,SoldierType soldierType,Vector3 pos,float trainTime)
    {
        mGameObject = gameObject;
        mName = name;
        mIconSprite = iconSprite;
        mSoldierType = soldierType;
        mPos = pos;
        mTrainTime = trainTime;
        mTrainTimer = mTrainTime;
        mTrainCommandList = new List<ITrainCommand>();
    }

    public string Name{ get { return mName; } }
    public string IconSprite { get { return mIconSprite; } }
    public abstract WeaponType GetCampWeaponType();
    public abstract int GetCampLv();


    public virtual void Update()
    {
        UpdataCommand();
    }
    //更新命令
    public void UpdataCommand()
    {
        if (mTrainCommandList.Count <= 0) return;
        mTrainTimer -= Time.deltaTime;
        if (mTrainTimer <= 0)
        {
            mTrainCommandList[0].Excute();
            mTrainCommandList.RemoveAt(0);
            mTrainTimer = mTrainTime;
        }
    }
    // 添加训练命令
    public abstract void AddTrainCommand();

    //取消训练士兵的命令,在命令集合中将最后一个命令移除
    public void CancelTrainCommand()
    {
        if (mTrainCommandList.Count > 0)
        {
            mTrainCommandList.RemoveAt(mTrainCommandList.Count - 1);
            if (mTrainCommandList.Count == 0)
            {
                mTrainTimer = mTrainTime;
            }
        }
    }
}

UI部分:

控制正在训练信息的显示

重写Update方法,从ICamp中获取计时器和命令的个数,更新训练部分的UI


    public float GetTrainTimer { get { return mTrainTimer; } }
    public int GetTrainCount { get { return mTrainCommandList.Count; } }
public class CampInfoUI : IBaseUI
{
    private Image mCampIcon;
    private Text mCampName;
    private Text mCampLevel;
    private Text mWeaponLevel;
    private Button mCampUpgradeBtn;
    private Button mWeaponUpgradeBtn;
    private Button mTrainBtn;
    private Text mTrainBtnText;
    private Button mCancelTrainBtn;
    private Text mAliveCount;
    private Text mTrainingCount;
    private Text mTrainTime;

    private ICamp mCamp; // 记录兵营

    public override void Init()
    {
        base.Init();
        GameObject canvas = GameObject.Find("Canvas");
        mRootUI = UnityTools.FindChild(canvas, "CampInfoUI");

        mCampIcon = UITools.FindChild<Image>(mRootUI, "CampIcon");
        mCampName = UITools.FindChild<Text>(mRootUI, "CampName");
        mCampLevel = UITools.FindChild<Text>(mRootUI, "CampLv");
        mWeaponLevel = UITools.FindChild<Text>(mRootUI, "WeaponLv");
        mCampUpgradeBtn = UITools.FindChild<Button>(mRootUI, "CampUpgradeBtn");
        mWeaponUpgradeBtn = UITools.FindChild<Button>(mRootUI, "WeaponUpgradeBtn");
        mTrainBtn = UITools.FindChild<Button>(mRootUI, "TrainBtn");
        mTrainBtnText = UITools.FindChild<Text>(mRootUI, "TrainBtnText");
        mCancelTrainBtn = UITools.FindChild<Button>(mRootUI, "CancelTrainBtn");
        mAliveCount = UITools.FindChild<Text>(mRootUI, "AliveCount");
        mTrainingCount = UITools.FindChild<Text>(mRootUI, "TrainingCount");
        mTrainTime = UITools.FindChild<Text>(mRootUI, "TrainTime");

        mTrainBtn.onClick.AddListener(OnTrainClick);
        mCancelTrainBtn.onClick.AddListener(OnCancelTrainClick);

        Hide();
    }

    public override void Update()
    {
        base.Update();
        if (mCamp != null)
        {
            ShowTrainInfo();
        }
    }

    public void ShowCampInfoUI(ICamp camp)
    {
        Show();
        mCamp = camp;
        mCampIcon.sprite = FactoryManager.assetFactory.LoadSprites(camp.IconSprite);
        mCampName.text = camp.Name;
        ShowWeaponLevel(camp.GetCampWeaponType());
        mCampLevel.text = camp.GetCampLv().ToString();

        ShowTrainInfo();
    }
    //兵营训练信息
    public void ShowTrainInfo()
    {
        mTrainingCount.text = mCamp.GetTrainCount.ToString();
        mTrainTime.text = mCamp.GetTrainTimer.ToString("0.00");
        if (mCamp.GetTrainCount == 0)
            mCancelTrainBtn.interactable = false;        
        else
            mCancelTrainBtn.interactable = true;
    }

    void ShowWeaponLevel(WeaponType weaponType)
    {
        switch (weaponType)
        {
            case WeaponType.Gun:
                mWeaponLevel.text = "短枪";
                break;
            case WeaponType.Rifle:
                mWeaponLevel.text = "长枪";
                break;
            case WeaponType.Rocket:
                mWeaponLevel.text = "火箭";
                break;
            case WeaponType.MAX:
                break;
            default:
                break;
        }
    }

    public void OnTrainClick()
    {
        // TODO 判断能量是否足够
        mCamp.AddTrainCommand();
    }

    public void OnCancelTrainClick()
    {
        //TODO 将消耗的能量回收
        mCamp.CancelTrainCommand();
    }
}

控制角色添加到角色管理系统

在GameFacade中声明添加士兵和敌人的方法

在ICharacterBuilder中添加  public abstract void AddInCharacterSystem();   控制角色添加到角色管理系统

SoldierBuilder 、 EnemyrBuilder 中重写 AddInCharacterSystem() 方法

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

public abstract class ICharacterBuilder
{
    protected WeaponType mWeaponType;
    protected Vector3 mSpawnPos;
    protected int mLV;
    protected ICharacter mCharacter;//设置给谁
    protected System.Type mT;
    protected string mPrefabName;

    public ICharacterBuilder(ICharacter character, System.Type t,WeaponType weaponType, Vector3 spawnPos, int lv)
    {
        mCharacter = character;
        mT = t ;
        mWeaponType = weaponType;
        mLV = lv;
        mSpawnPos = spawnPos;
    }
   
    public abstract void AddCharacterAttr();
    public abstract void AddInstGameObject();
    public abstract void AddWeapon();
    /// <summary>
    ///  将实例化的角色添加到角色系统中
    /// </summary>
    public abstract void AddInCharacterSystem(); 
    public abstract ICharacter GetResult();
}
GameFacade 中:

    public void AddSoldier(ISoldier soldier)
    {
        characterSystem.AddSoldier(soldier);
    }

    public void AddEnemy(IEnemy enemy)
    {
        characterSystem.AddEnemy(enemy);
    }


EnemyrBuilder中:

    public override void AddInCharacterSystem()
    {
        GameFacade.Instance.AddEnemy(mCharacter as IEnemy);
    }

SoldierBuilder中:

    public override void AddInCharacterSystem()
    {
        GameFacade.Instance.AddSoldier(mCharacter as ISoldier);
    }

使用策略模式计算升级和训练所需要的能量消耗值

创建IEnergyCostStategy  用策略模式计算升级和训练所需要的能量消耗值

创建SoldierEnergyCostStategy  继承自 IEnergyCostStategy 

public abstract  class IEnergyCostStategy  {

    public abstract int GetWeaponUpgradeStategy(WeaponType weaponType);
    public abstract int GetSoldierTrainStategy(int lv , SoldierType soldierType);
    public abstract int GetCampUpgradeStategy(int lv, SoldierType soldierType); 
}
public class SoldierEnergyCostStategy : IEnergyCostStategy
{
    public override int GetCampUpgradeStategy(int lv, SoldierType soldierType)
    {
        int energy = 0;

        switch (soldierType)
        {
            case SoldierType.Rookie:
                energy = 60;
                break;
            case SoldierType.Sergeant:
                energy = 65;
                break;
            case SoldierType.Captain:
                energy = 70;
                break;
            default:
                Debug.LogError("无法获取士兵类型为" + soldierType+"升级所消耗的能力值");
                break;
        }
        energy += (lv - 1) * 2;
        if (energy >= 100) energy = 100;
        return energy;
    }

    public override int GetSoldierTrainStategy(int lv, SoldierType soldierType)
    {
        int energy = 0;

        switch (soldierType)
        {
            case SoldierType.Rookie:
                energy = 10;
                break;
            case SoldierType.Sergeant:
                energy = 15;
                break;
            case SoldierType.Captain:
                energy = 20;
                break;
            default:
                Debug.LogError("无法获取士兵类型为" + soldierType + "升级所消耗的能力值");
                break;
        }
        energy += (lv - 1) * 2;
        return energy;
    }

    public override int GetWeaponUpgradeStategy(WeaponType weaponType)
    {
        int energy = 0;

        switch (weaponType)
        {
            case WeaponType.Gun:
                energy = 30;
                break;
            case WeaponType.Rifle:
                energy = 40;
                break;
            default:
                Debug.LogError("无法获取武器类型为" + weaponType + "升级所消耗的能力值");
                break;
        }
        return energy;
    }
}

能量消耗值计算策略的调用

在ICamp中声明 能量消耗的策略类 IEnergyCostStategy mEnergyCostStategy,并在子类SoldierCamp的构造方法中new出来;

在ICamp中声明变量 mGetWeaponUpgrade 、mGetSoldierTrain、mGetCampUpgrade ,用于得到武器、士兵、兵营的更新

并声明 更新所有的能量消耗  更新武器的升级   更新兵营的升级 的抽象类方法,在子类中重写;

提供get方法获取升级和训练所需要的能量值 :

GetTrainEnergyCost { get; }       GetWeaponUpgradeEnergyCost { get; }       GetCampUpgradeEnergyCost{ get; }

public abstract class ICamp
{
    protected GameObject mGameObject; //兵营
    protected string mName;
    protected string mIconSprite;
    protected SoldierType mSoldierType;
    protected Vector3 mPos; // 集合位置
    protected float mTrainTime; //训练时间
    protected float mTrainTimer; //训练计时器
    protected IEnergyCostStategy mEnergyCostStategy; // 能量消耗策略
    //得到武器升级的消耗值
    protected int mGetWeaponUpgrade;
    //得到士兵训练的消耗值
    protected int mGetSoldierTrain;
    //得到兵营升级的消耗值
    protected int mGetCampUpgrade;

    public float GetTrainTimer { get { return mTrainTimer; } }
    public int GetTrainCount { get { return mTrainCommandList.Count; } }

    protected List<ITrainCommand> mTrainCommandList; // 管理训练命令集合

    public ICamp(GameObject gameObject,string name,string iconSprite,SoldierType soldierType,Vector3 pos,float trainTime)
    {
        mGameObject = gameObject;
        mName = name;
        mIconSprite = iconSprite;
        mSoldierType = soldierType;
        mPos = pos;
        mTrainTime = trainTime;
        mTrainTimer = mTrainTime;
        mTrainCommandList = new List<ITrainCommand>();
    }

    public string Name{ get { return mName; } }
    public string IconSprite { get { return mIconSprite; } }
    //用于得到训练所消耗的能量
    public abstract int GetTrainEnergyCost { get; }
    //用于得到武器升级所消耗的能量
    public abstract int GetWeaponUpgradeEnergyCost { get; }
    //用于得到兵营升级所消耗的能量
    public abstract int GetCampUpgradeEnergyCost{ get; }

    public abstract WeaponType GetCampWeaponType();
    public abstract int GetCampLv();

    public virtual void Update()
    {
        UpdataCommand();
    }

    public void UpdataCommand()
    {
        if (mTrainCommandList.Count <= 0) return;
        mTrainTimer -= Time.deltaTime;
        if (mTrainTimer <= 0)
        {
            mTrainCommandList[0].Excute();
            mTrainCommandList.RemoveAt(0);
            mTrainTimer = mTrainTime;
        }
    }
    // 添加训练命令
    public abstract void AddTrainCommand();
    //更新所有的能量消耗
    public abstract void UpdateEnergyCost();
    //更新武器的升级
    public abstract void UpdateWeaponUpgrade();
    //更新兵营的升级
    public abstract void UpdateCampUpgrade();

    //取消训练士兵的命令,在命令集合中将最后一个命令移除
    public void CancelTrainCommand()
    {
        if (mTrainCommandList.Count > 0)
        {
            mTrainCommandList.RemoveAt(mTrainCommandList.Count - 1);
            if (mTrainCommandList.Count == 0)
            {
                mTrainTimer = mTrainTime;
            }
        }
    }
}
public class SoldierCamp : ICamp
{

    private int mMAX_Lv;
    private int mLv = 1;
    private WeaponType mWeaponType = WeaponType.Gun;

    public override int GetTrainEnergyCost
    {
        get
        {
            return mGetSoldierTrain;
        }
    }

    public override int GetWeaponUpgradeEnergyCost
    {
        get
        {
            if (mWeaponType + 1 == WeaponType.MAX)
                return -1;
            else
                return mGetWeaponUpgrade;
        }
    }

    public override int GetCampUpgradeEnergyCost
    {
        get
        {
            if (mLv == mMAX_Lv)
                return -1;
            else
                return mGetCampUpgrade;
        }
    }


    public SoldierCamp(GameObject gameObject, string name, string iconSprite, SoldierType soldierType, Vector3 pos, float trainTime, WeaponType weaponType = WeaponType.Gun, int lv = 1)
        : base(gameObject, name, iconSprite, soldierType, pos, trainTime)
    {
        mLv = lv;
        mWeaponType = weaponType;
        mEnergyCostStategy = new SoldierEnergyCostStategy();
        UpdateEnergyCost();
    }

    public override void Update()
    {
        base.Update();
    }

    public override WeaponType GetCampWeaponType()
    {
        return mWeaponType;
    }

    public override int GetCampLv()
    {
        return mLv;
    }

    public override void AddTrainCommand()
    {
        //添加训练命令
        SoldierTrainCommand soldierTrainCommand = new SoldierTrainCommand(mSoldierType, mWeaponType, mPos, mLv);
        mTrainCommandList.Add(soldierTrainCommand);
    }

    public override void UpdateEnergyCost()
    {
        mGetCampUpgrade = mEnergyCostStategy.GetCampUpgradeStategy(mLv, mSoldierType);
        mGetSoldierTrain = mEnergyCostStategy.GetSoldierTrainStategy(mLv, mSoldierType);
        mGetWeaponUpgrade = mEnergyCostStategy.GetWeaponUpgradeStategy(mWeaponType);
    }

    public override void UpdateWeaponUpgrade()
    {
        mWeaponType = mWeaponType + 1;
        UpdateEnergyCost();
    }

    public override void UpdateCampUpgrade()
    {
        mLv ++;
        UpdateEnergyCost();
    }


}

UI系统 -- 处理升级按钮的点击

CampInfoUI:

mWeaponUpgradeBtn.onClick.AddListener(WeaponUpgradeClick);
mCampUpgradeBtn.onClick.AddListener(CampUpgradeClick);  

public void WeaponUpgradeClick()
    {
        int energy = mCamp.GetWeaponUpgradeEnergyCost;
        if (energy < 0)
        {
            Debug.Log("武器已经满级");
            return;
        }
        //TODO
        mCamp.UpdateWeaponUpgrade();
        ShowCampInfoUI(mCamp);
    }

    public void CampUpgradeClick()
    {
        int energy = mCamp.GetCampUpgradeEnergyCost;
        if (energy < 0)
        {
            Debug.Log("武器已经满级");
            return;
        }
        //TODO
        mCamp.UpdateCampUpgrade();
        ShowCampInfoUI(mCamp);
    }

能量系统:

设计能量系统

Update中更新能量的增加 和 UI中能量的显示

声明能量消耗和返回的方法并声明在GameFacade中方便外界调用

public class EnergySystem : IGameSystem
{
    private const int MAX_Energy = 100;

    private float mCurrentEnergy = MAX_Energy;

    private float mRecoverpeed = 3;  // 能量回复速度

    public override void Init()
    {
        base.Init();

    }

    public override void Update()
    {
        base.Update();

        //更新能量条
        mFacade.UpdateEnergySlider((int)mCurrentEnergy, MAX_Energy); 
        //增加能量
        if (mCurrentEnergy >= MAX_Energy) return;
        mCurrentEnergy += mRecoverpeed * Time.deltaTime;
        mCurrentEnergy = Mathf.Min(mCurrentEnergy, MAX_Energy);
    }
    //消耗的能量
    public bool TakeEnergy(int value)
    {
        if (mCurrentEnergy >= value)
        {
            mCurrentEnergy -= value;
            return true;
        }
        return false;
    }
    //取消训练后返还的能量
    public void RecycleEnergy(int value)
    {
        mCurrentEnergy += value;
        mCurrentEnergy = Mathf.Min(mCurrentEnergy, MAX_Energy);
    }
}

GameStateUI

声明显示提示信息和更新能量条的方法并声明在GameFacade中方便外界调用

public class GameStateUI : IBaseUI
{
    private List<GameObject> mHearts; //左上角星星
    private Text mSoldierCount;
    private Text mEnemyCount;
    private Text mCurrentStage;
    private Button mPauseBtn;
    private GameObject mGameOverUI;
    private Button mBackMenuBtn;
    private Text mMessage;
    private Slider mEnergySlider;
    private Text mEnergyText;

    private float mMsgTimer = 0;
    private float mMsgTime = 2;

    public override void Init()
    {
        省略…
    }

    public override void Update()
    {
        base.Update();
        if (mMsgTimer > 0)
        {
            mMsgTimer -= Time.deltaTime;
            if (mMsgTimer <= 0)
            {
                mMessage.text = "";
            }
        }
    }

    public void ShowMsg(string msg)
    {
        mMessage.text = msg;
        mMsgTimer = mMsgTime;
    }

    public void UpdateEnergySlider(int currentEnergy,int maxEnergy)
    {
        mEnergySlider.value =(float)currentEnergy / maxEnergy;
        mEnergyText.text = "(" + currentEnergy + "/" + maxEnergy + ")";
    }
}
GameFacade中:   

    public void UpdateEnergySlider(int currentEnergy, int maxEnergy)
    {
        gameStateUI.UpdateEnergySlider(currentEnergy,maxEnergy);
    }

    public void ShowMsg(string msg)
    {
        gameStateUI.ShowMsg(msg);
    }

完善CampInfoUI的点击事件及其UI的更新

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

public class CampInfoUI : IBaseUI
{
    private Image mCampIcon;
    private Text mCampName;
    private Text mCampLevel;
    private Text mWeaponLevel;
    private Button mCampUpgradeBtn;
    private Button mWeaponUpgradeBtn;
    private Button mTrainBtn;
    private Text mTrainBtnText;
    private Button mCancelTrainBtn;
    private Text mAliveCount;
    private Text mTrainingCount;
    private Text mTrainTime;

    private ICamp mCamp; // 记录兵营

    public override void Init()
    {
        base.Init();
        GameObject canvas = GameObject.Find("Canvas");
        mRootUI = UnityTools.FindChild(canvas, "CampInfoUI");

        mCampIcon = UITools.FindChild<Image>(mRootUI, "CampIcon");
        mCampName = UITools.FindChild<Text>(mRootUI, "CampName");
        mCampLevel = UITools.FindChild<Text>(mRootUI, "CampLv");
        mWeaponLevel = UITools.FindChild<Text>(mRootUI, "WeaponLv");
        mCampUpgradeBtn = UITools.FindChild<Button>(mRootUI, "CampUpgradeBtn");
        mWeaponUpgradeBtn = UITools.FindChild<Button>(mRootUI, "WeaponUpgradeBtn");
        mTrainBtn = UITools.FindChild<Button>(mRootUI, "TrainBtn");
        mTrainBtnText = UITools.FindChild<Text>(mRootUI, "TrainBtnText");
        mCancelTrainBtn = UITools.FindChild<Button>(mRootUI, "CancelTrainBtn");
        mAliveCount = UITools.FindChild<Text>(mRootUI, "AliveCount");
        mTrainingCount = UITools.FindChild<Text>(mRootUI, "TrainingCount");
        mTrainTime = UITools.FindChild<Text>(mRootUI, "TrainTime");

        mTrainBtn.onClick.AddListener(OnTrainClick);
        mCancelTrainBtn.onClick.AddListener(OnCancelTrainClick);
        mWeaponUpgradeBtn.onClick.AddListener(WeaponUpgradeClick);
        mCampUpgradeBtn.onClick.AddListener(CampUpgradeClick);

        Hide();
    }

    public override void Update()
    {
        base.Update();
        if (mCamp != null)
        {
            ShowTrainInfo();
        }
    }

    public void ShowCampInfoUI(ICamp camp)
    {
        Show();
        mCamp = camp;
        mCampIcon.sprite = FactoryManager.assetFactory.LoadSprites(camp.IconSprite);
        mCampName.text = camp.Name;
        ShowWeaponLevel(camp.GetCampWeaponType());
        mCampLevel.text = camp.GetCampLv().ToString();
        mTrainBtnText.text = "训练需要" + mCamp.GetTrainEnergyCost+ "点能量";
        ShowTrainInfo();
    }
    //兵营训练信息
    public void ShowTrainInfo()
    {
        mTrainingCount.text = mCamp.GetTrainCount.ToString();
        mTrainTime.text = mCamp.GetTrainTimer.ToString("0.00");
        if (mCamp.GetTrainCount == 0)
            mCancelTrainBtn.interactable = false;
        else
            mCancelTrainBtn.interactable = true;
    }

    void ShowWeaponLevel(WeaponType weaponType)
    {
        switch (weaponType)
        {
            case WeaponType.Gun:
                mWeaponLevel.text = "短枪";
                break;
            case WeaponType.Rifle:
                mWeaponLevel.text = "长枪";
                break;
            case WeaponType.Rocket:
                mWeaponLevel.text = "火箭";
                break;
            case WeaponType.MAX:
                break;
            default:
                break;
        }
    }

    public void OnTrainClick()
    {
        //  判断能量是否足够
        if (mGameFacade.TakeEnergy(mCamp.GetTrainEnergyCost))
        {
            mCamp.AddTrainCommand();
        }
        else
            mGameFacade.ShowMsg("能量不足,无法训练新的士兵");
    }

    public void OnCancelTrainClick()
    {
        // 将消耗的能量回收
        mGameFacade.RecycleEnergy(mCamp.GetTrainEnergyCost);
        mCamp.CancelTrainCommand();
    }

    public void WeaponUpgradeClick()
    {
        int energy = mCamp.GetWeaponUpgradeEnergyCost;
        if (energy < 0)
        {
            mGameFacade.ShowMsg("武器已经到最大等级,无法升级"); 
            return;
        }
        if (mGameFacade.TakeEnergy(energy))
        {
            mCamp.UpdateWeaponUpgrade();
            ShowCampInfoUI(mCamp);
        }
        else
        {
            mGameFacade.ShowMsg("能量不足,请稍后再进行升级");
        }
    }

    public void CampUpgradeClick()
    {
        int energy = mCamp.GetCampUpgradeEnergyCost;
        if (energy < 0)
        {
            mGameFacade.ShowMsg("兵营已经到最大等级,无法升级");
            return;
        }
        if (mGameFacade.TakeEnergy(energy))
        {
            mCamp.UpdateCampUpgrade();
            ShowCampInfoUI(mCamp);
        }
        else
        {
            mGameFacade.ShowMsg("能量不足,请稍后再进行升级");
        }
    }
}

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值