Shield
、ShieldController
、Bomb
、BombController
的创建略。
在GameUIView
中添加挂载Shield
和Bomb
的逻辑
1 2 3 4 5 6 7 protected override void InitChild (){ UIUtil.Get("Life" ).AddCo<Life>(); UIUtil.Get("Bomb" ).AddCo<Bomb>(); UIUtil.Get("Shield" ).AddCo<Shield>(); }
修改ExtendUtil和UIUtil 在ExtendUtil
中添加更加便捷的动态挂载脚本的transform拓展方法。方便Controller
动态挂载脚本。
1 2 3 4 5 6 7 8 public static T AddCo <T >(this Transform target ) where T : Component{ return target.gameObject.AddComponent<T>(); } public static T AddCo <T >(this Transform target, string path ) where T : Component{ return target.Find(path).gameObject.AddComponent<T>(); }
然后再在GameUIController
中添加动态挂载ShieldController
和BombController
的逻辑
1 2 3 4 5 6 7 8 9 10 protected override void InitChild (){ transform.AddCo<LifeController>("Life" ); transform.AddCo<ShieldController>("Shield" ); transform.AddCo<BombController>("Bomb" ); transform.ButtonAction("Pause" , () => { UIMgr.Instance.Show(Pathes.PAUSE_VIEW); }); }
修改UIUtil.UIUtilData
的AddCo
方法,让它返回添加的组件。
1 2 3 4 5 6 7 8 9 10 public T AddCo <T >() where T : UnityEngine.Component{ if (Go != null ) return Go.AddComponent<T>(); else { Debug.LogError("当前Go为空" ); return null ; } }
GameModel 修改GameModel
,添加炸弹数量和护盾数量。并添加重置方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class GameModel : NormalSingleton <GameModel > { public GameModel () { Life = Consts.LIFE_MAX; } public int Life { get ; set ; } public int Score { get ; set ; } public int Stars { get ; set ; } public int ShieldCount { get ; set ; } public int BombCount { get ; set ; } public void Clear () { m_Instance = new (); } }
注意这里的Clear
方法,使用新的instance实例来重置。
GameModel重置 我们的GameModel
是普通单例类,可以重新赋值单例来重置GameModel
修改单例模板
1 2 3 4 5 public class NormalSingleton <T > where T : class ,new (){ protected static T m_Instance; public static T Instance => m_Instance??= new T(); }
特效 护盾和炸弹按钮在可以点击的情况下会显示一个转圈特效。
我们将UI特效做成一个prefab,等到使用时动态加载这个特效。这个prefab就是一个Image组件,使用Dotween不断旋转。注意除了Image组件,UI特效的prefab还需要挂载Canvas组件 ,子Canvas不会触发主Canvas的Mesh重建。
将这个prefab命名为ItemEffect,放在Resources——Prefab——Game——Effect文件夹下。
在Pathes
中指定Prefab的路径
1 2 3 public const string PREFAB_EFFECT_FOLDER = "Prefab/Game/Effect/" ;public const string EFFECT_SHIELDEFFECT = PREFAB_EFFECT_FOLDER + "ItemEffect" ;
ItemEffect 在Scripts——UI文件夹中新建Effect文件夹,在其中新建ItemEffect
,它是挂载在特效prefab上的脚本,控制特效的表现,它比较独立,不接入UI系统。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using UnityEngine;using DG.Tweening;public class ItemEffect : MonoBehaviour { private void OnEnable () { transform.DORotate(Vector3.forward * -90 , 0.2f ).SetEase(Ease.Linear).SetLoops(-1 , LoopType.Incremental); } private void OnDisable () { transform.DOKill(); transform.localEulerAngles = Vector3.zero; } public void SetActive (bool active ) { gameObject.SetActive(active); } }
ItemCDEffect 用来控制UICD动画
先在Consts
中添加CD时长
1 public const float CD_EFFECT_TIME = 2.0f ;
然后修改ItemCDEffect
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 using UnityEngine;using UnityEngine.UI;public class ItemCDEffect : MonoBehaviour ,IUpdate { private Image _image; private Image Image { get { if (_image == null ) _image = GetComponent<Image>(); return _image; } } private System.Action _cdEndCallback; public void SetShow () { Image.fillAmount = 0 ; } public void SetMask () { Image.fillAmount = 1 ; } public void StartCD (System.Action callback ) { Image.fillAmount = 1 ; LifeCycleMgr.Instance.Add(LifeName.UPDATE, this ); _cdEndCallback = callback; } public void UpdateFun () { Image.fillAmount -= Time.deltaTime / Consts.CD_EFFECT_TIME; if (Image.fillAmount <= 0 ) { LifeCycleMgr.Instance.Remove(LifeName.UPDATE,this ); _cdEndCallback?.Invoke(); } } }
炸弹和护盾 添加数量更新事件 修改MsgEvent
1 2 3 4 public const int EVENT_SHIELD = 2 ;public const int EVENT_BOMB = 3 ;public const int EVENT_USE_SHIELD = 4 ;public const int EVENT_USE_BOMB = 5 ;
修改Shield和Bomb脚本 Shield
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 public class Shield : ViewBase , IReceiver { private ItemCDEffect _cdEffect; private ItemEffect _itemEffect; private int _shieldCount; protected override void InitChild () { var effect = LoadMgr.Instance.LoadPrefabAndInstantiate(Pathes.EFFECT_ITEMEFFECT, transform); _itemEffect = effect.AddComponent<ItemEffect>(); _cdEffect = UIUtil.Get("Mask" ).AddCo<ItemCDEffect>(); _cdEffect.SetShow(); } public override void Show () { base .Show(); MessageMgr.Instance.AddListener(MsgEvent.EVENT_SHIELD, this ); MessageMgr.Instance.AddListener(MsgEvent.EVENT_USE_SHIELD, this ); _shieldCount = GameModel.Instance.ShieldCount; UpdateCount(); UpdateState(); } public override void Hide () { base .Hide(); MessageMgr.Instance.RemoveListener(MsgEvent.EVENT_SHIELD, this ); MessageMgr.Instance.RemoveListener(MsgEvent.EVENT_USE_SHIELD,this ); } private void UpdateCount () { UIUtil.Get("Num" ).SetText(GameModel.Instance.ShieldCount); } public void ReceiveMessage (params object [] args ) { UpdateCount(); UpdateState(); } private void UpdateState () { if (GameModel.Instance.ShieldCount == 0 ) { _cdEffect.SetMask(); _itemEffect.SetActive(false ); } else { if (_shieldCount > GameModel.Instance.ShieldCount) { _cdEffect.StartCD(() => _itemEffect.SetActive(true )); _shieldCount = GameModel.Instance.ShieldCount; _itemEffect.SetActive(false ); } } } }
Bomb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class Bomb : ViewBase , IReceiver { private ItemCDEffect _cdEffect; private ItemEffect _itemEffect; private int _bombCount; protected override void InitChild () { var effect = LoadMgr.Instance.LoadPrefabAndInstantiate(Pathes.EFFECT_ITEMEFFECT, transform); _itemEffect = effect.AddComponent<ItemEffect>(); _cdEffect = UIUtil.Get("Mask" ).AddCo<ItemCDEffect>(); _cdEffect.SetShow(); } public override void Show () { base .Show(); MessageMgr.Instance.AddListener(MsgEvent.EVENT_BOMB, this ); MessageMgr.Instance.AddListener(MsgEvent.EVENT_USE_BOMB, this ); _bombCount = GameModel.Instance.BombCount; UpdateCount(); UpdateState(); } public override void Hide () { base .Hide(); MessageMgr.Instance.RemoveListener(MsgEvent.EVENT_BOMB, this ); MessageMgr.Instance.RemoveListener(MsgEvent.EVENT_USE_BOMB, this ); } private void UpdateCount () { UIUtil.Get("Num" ).SetText(GameModel.Instance.BombCount); } public void ReceiveMessage (params object [] args ) { UpdateCount(); UpdateState(); } private void UpdateState () { if (GameModel.Instance.BombCount == 0 ) { _cdEffect.SetMask(); _itemEffect.SetActive(false ); } else { if (_bombCount > GameModel.Instance.BombCount) { _cdEffect.StartCD(() => _itemEffect.SetActive(true )); _bombCount = GameModel.Instance.BombCount; _itemEffect.SetActive(false ); } } } }
修改各自的Controller ShieldController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class ShieldController : ControllerBase { protected override void InitChild () { transform.ButtonAction("Icon" , Shield); } private void Shield () { if (GameModel.Instance.ShieldCount > 0 ) { GameModel.Instance.ShieldCount--; } MessageMgr.Instance.DispatchMsg(MsgEvent.EVENT_USE_SHIELD); } }
BombController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class BombController : ControllerBase { protected override void InitChild () { transform.ButtonAction("Icon" , Click); } private void Click () { if (GameModel.Instance.BombCount > 0 ) { GameModel.Instance.BombCount--; } MessageMgr.Instance.DispatchMsg(MsgEvent.EVENT_USE_BOMB); } }