iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0

這邊是假設今天有個是要在玩家全部行動完畢時結束回合,而這邊會用Visitor獲取玩家單位的可行動數量+用Observer每次在控制狀態為等待輸入(CALWaitingForInputCellGridState)觸發更新

Unit.cs

public virtual void RunVisitor(IUnitVisitor unitVisitor) 
{ 
    unitVisitor.VisitUnit(this); 
}

UnitSystem.cs

using LinXuan.Common.Main; 
using LinXuan.Common.Misc; 
using LuLuBearStudio.Characters; 
using System.Collections.Generic; 

namespace LinXuan.TBSF.Misc 
{ 
    public class UnitSystem : IGameSystem 
    { 
        private CellGrid m_CellGrid; 
        private List<Unit> m_PlayerUnits = new List<Unit>(); 
        private List<Unit> m_EnemyUnits = new List<Unit>(); 
        private List<Unit> m_AllUnits = new List<Unit>(); 
        public List<Unit> PlayableUnit { get; private set; } 

        public UnitSystem(CellGrid cellGrid) 
        { 
            m_CellGrid = cellGrid; 
            Initialize(); 
        } 

        public void Initialize() 
        { 
        } 

        public void Initialize(List<Unit> units) 
        { 
            m_AllUnits = units; 
            m_PlayerUnits.AddRange(m_AllUnits.FindAll(u => u is IPlayer)); 
            m_EnemyUnits.AddRange(m_AllUnits.FindAll(u => u is IEnemy)); 
        } 

        public void RunVisitor(IUnitVisitor unitVisitor) 
        { 
            foreach (Unit unit in m_AllUnits) 
                unit.RunVisitor(unitVisitor); 
        } 
    } 
}

IUnitVisitor.cs

using LuLuBearStudio.Characters; 

namespace LinXuan.Common.Misc 
{ 
    public abstract class IUnitVisitor 
    { 
        public virtual void VisitUnit(Unit unit) 
        { 
        }

        public virtual void VisitPlayerUnit(IPlayer player) 
        { 
            VisitUnit(player); 
        }

        public virtual void VisitEnemyUnit(IEnemy enemy) 
        { 
            VisitUnit(enemy); 
        } 
    } 
}

UnitInfoVisitor.cs

using Assets.Scripts.GUI.GUITool; 
using LinXuan.Common.Misc; 
using LuLuBearStudio.CALAbilities; 
using LuLuBearStudio.Characters; 

namespace LinXuan.TBSF.Misc 
{ 
    public class UnitInfoVisitor : IUnitVisitor 
    { 
        public int UnitCount { get; private set; } 
        public int PlayerCount { get; private set; } 
        public int EnemyCount { get; private set; } 
        public int UseableUnitCount { get; private set; } 
        public int MovableUnitCount { get; private set; } 
        public int AttackableUnitCount { get; private set; }

        public override void VisitUnit(Unit unit) 
        { 
            base.VisitUnit(unit); 
            UnitCount++; 
            if (unit as IPlayer) 
                VisitPlayerUnit(unit as IPlayer); 
        }

        public override void VisitPlayerUnit(IPlayer player) 
        { 
            AbilityEditor abilityEditor = player.AbilityEditor; 
            if (abilityEditor.CanPerform(UIInputObserver.CellGrid)) 
            { 
                UseableUnitCount++; 
            } 
            PlayerCount++; 
        }

        public void VisitorReset() 
        { 
            EnemyCount = 0; 
            UnitCount = 0; 
            UseableUnitCount = 0; 
        } 
    } 
}

IGameEventObserver.cs

namespace LinXuan.Common.GameEvent
{
    public interface IGameEventObserver
    {
        void SetSubject(IGameEventSubject subject);
        void ObserverUpdate();
    }
}

UnitUseAbilityObserverGUI.cs

using LinXuan.Common.GameEvent;
using TbsFramework.Grid;

namespace LinXuan.TBSF.GameEvent
{
    public class UnitUseAbilityObserverGUI : IGameEventObserver
    {
        private UseableUnitCountSubject m_UseableUnitCountSubject = null;
        private CellGrid m_CellGrid = null;

        public UnitUseAbilityObserverGUI(CellGrid cellGrid)
        {
            m_CellGrid = cellGrid;
        }

        public void ObserverUpdate()
        {
            m_CellGrid.UseableUnitCountGUIUpdate();
        }

        public void SetSubject(IGameEventSubject subject)
        {
            m_UseableUnitCountSubject = subject as UseableUnitCountSubject;
        }
    }
}

UseableUnitCountSubject.cs

namespace LinXuan.Common.GameEvent
{
    public class UseableUnitCountSubject : IGameEventSubject
    {
        public UnitCountEventArgs UnitCountEventArgs { get; private set; }

        public override void SetParameter(object parameter)
        {
            Notify();
        }
    }
}

CALWaitingForInputCellGridState.cs

using Assets.Scripts.GUI.GUITool;
using LuLuBearStudio.CALAbilities;
using System.Collections.Generic;

namespace Assets.Scripts.TBS_Framework_extends.CellGridStates
{
    public class CALWaitingForInputCellGridState : CellGridState
    {
        ...
        public override void OnStateEnter()
        {
            base.OnStateEnter();
            UIInputObserver.IsPlayerCanInput = true;

            foreach (Unit unit in units)
            {
                AbilityEditor abilityEditor = unit.GetComponent<AbilityEditor>();

                var canPerformAction = abilityEditor.CanPerform(_cellGrid);

                if (!canPerformAction)
                {
                    unit.SetState(new UnitStateMarkedAsFinished(unit));
                }
                else
                {
                    unit.SetState(new UnitStateNormal(unit));
                }
            }

UIInputObserver.CellGrid.NotifyGameEvent(LinXuan.TBSF.Enums.GameEventType.GetUseableUnitCount, null);

        }
        ...
    }
}

CellGrid.cs

public event EventHandler UseableUnitCountUpdate;

private UnitSystem m_UnitSystem;

private void Awake() 
{ 
    m_UnitSystem = new UnitSystem(this); 
}

private void Initialize() 
{
    ...
    m_UnitSystem.Initialize(Units);
}

public void RunUnitVisitor(IUnitVisitor unitVisitor) 
{ 
    m_UnitSystem.RunVisitor(unitVisitor); 
}

public void UseableUnitCountGUIUpdate()
{
    UseableUnitCountUpdate.Invoke(this, null);
}

CALGUIController.cs

private UnitInfoVisitor m_UnitInfoVisitor = new UnitInfoVisitor();

private void Awake() 
{ 
    CellGrid.UseableUnitCountUpdate += ShowUseableUnitCount;
}

private void Start()
{
    CellGrid.RegisterGameEvent(LinXuan.TBSF.Enums.GameEventType.GetUseableUnitCount, new UnitUseAbilityObserverGUI(UIInputObserver.CellGrid));
}

...

private void ShowUseableUnitCount(object sender, EventArgs e) 
{ 
    m_UnitInfoVisitor.VisitorReset(); 
    CellGrid.RunUnitVisitor(m_UnitInfoVisitor); 
    int useableCount = m_UnitInfoVisitor.UseableUnitCount; 
    Debug.Log("Useable count " + useableCount); 
}

這邊當角色還沒消耗完行動次數時,就會顯示可行動人數為兩人
https://ithelp.ithome.com.tw/upload/images/20221006/20151894nZXc1GOoMS.png

而要是有單位消耗完行動次數後,數字就會相應減少
https://ithelp.ithome.com.tw/upload/images/20221006/201518944WI2iFFxyg.png

老實說寫起來有點繞一大圈的感覺,好處大概就是需要重新計算的時候在去做重新讀一次陣列的行為,不用每次都跑一次全部的陣列讀目前狀態,在陣列數量大的時候應該會更有感覺點

參考資料

設計模式與遊戲開發的完美結合(暢銷回饋版)
Turn Based Strategy Framework
流離之歌


上一篇
Day 23:Visitor模式(一)
下一篇
Day 25:interface與abstract class
系列文
如何在Unity裡寫出具有一定擴充性的遊戲30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言