SRPG游戏开发(六十)第十一章 地图动作与地图事件 - 九 触发事件与切换回合(Trigger Events and Change Turn)

版权声明:本文为博主原创文章,未经允许不得转载。 https://blog.csdn.net/darkrabbit/article/details/87918535

返回《SRPG游戏开发》导航

第十一章 地图动作与地图事件(Map Action and Map Event)

我们已经有了剧本,而且可以运行剧本,但我们还缺少对地图的操作控制。

我们这一章来完成地图上的操作,地图的操作将全部由MapAction控制。



九 触发事件与切换回合(Trigger Events and Change Turn)

光有地图事件是不行的,我们还需要知道如何触发它们。


1 触发事件方法(Trigger Events Method)

我们同样的使用一个Coroutine来触发事件:

        protected Coroutine m_EventCoroutine = null;

        /// <summary>
        /// 触发地图事件
        /// </summary>
        /// <param name="type"></param>
        /// <param name="onTriggerEnd"></param>
        public void TriggerEvents(MapEventConditionType type, Action onTriggerEnd)
        {
            mapStatus = MapStatus.Event;
            if (m_EventCoroutine != null)
            {
                error = "MapAction TriggerEvents -> event is running.";
                status = ActionStatus.Error;
                Debug.LogError(error);
                if (onTriggerEnd != null)
                {
                    onTriggerEnd();
                }
                return;
            }
            m_EventCoroutine = GameDirector.instance.StartCoroutine(EventsTriggering(type, onTriggerEnd));
        }

        public IEnumerator EventsTriggering(MapEventConditionType type, Action onTriggerEnd)
        {
            yield return null;

            // TODO
        }

关于触发事件,我们只用可以当做入口的条件来触发相应的事件:

            switch (type)
            {
                case MapEventConditionType.NoneCondition:
                    yield return m_MapEvents.TriggerStartEvents(
                        this, onError: eventError => error = eventError);
                    break;
                case MapEventConditionType.TurnCondition:
                    yield return m_MapEvents.TriggerTurnEvents(
                        this, onError: eventError => error = eventError);
                    break;
                case MapEventConditionType.PositionCondition:
                    if (movingEndCell != null)
                    {
                        yield return m_MapEvents.TriggerPositionEvents(
                            this, movingEndCell.position, onError: eventError => error = eventError);
                    }
                    break;
                case MapEventConditionType.RoleDeadCondition:
                    if (selectedUnit != null && selectedUnit.role.isDead)
                    {
                        yield return m_MapEvents.TriggerDeadEvents(
                            this, selectedUnit.role.characterId, onError: eventError => error = eventError);
                    }

                    if (targetUnit != null && targetUnit.role.isDead)
                    {
                        yield return m_MapEvents.TriggerDeadEvents(
                            this, targetUnit.role.characterId, onError: eventError => error = eventError);
                    }
                    break;
                case MapEventConditionType.RoleTalkCondition:
                    if (selectedUnit != null && targetUnit != null)
                    {
                        yield return m_MapEvents.TriggerRoleTalkEvents(
                            this, selectedUnit.role.characterId, targetUnit.role.characterId, onError: eventError => error = eventError);
                    }
                    break;
                case MapEventConditionType.RoleCombatTalkCondition:
                    if (selectedUnit != null && targetUnit != null)
                    {
                        yield return m_MapEvents.TriggerRoleCombatTalkEvents(
                            this, selectedUnit.role.characterId, targetUnit.role.characterId, onError: eventError => error = eventError);
                    }
                    break;
            }

            m_EventCoroutine = null;
            if (onTriggerEnd != null)
            {
                onTriggerEnd();
            }

2 切换回合(Change Turn)

切换回合的方法,我们命名为NextTurn。它需要注意几点:

  • 每一个回合是指所有阵营结束,并不单指玩家;

  • 阵营不是玩家时,光标应该隐藏;

  • 在玩家结束后,我们需要将待机的角色都设置成非待机,且要恢复它们的移动力;

  • 在切换阵营时,我们需要给出玩家提示。

基于以上,我们创建方法:

        /// <summary>
        /// 转换回合
        /// </summary>
        protected void NextTurn()
        {
            switch (turn)
            {
                case AttitudeTowards.Player:
                    turnToken++; // 只有所有阵营结束,回合数才+1

                    // 将所有玩家回复移动力,并将待机状态重置
                    string color = GetSwapperColorName(AttitudeTowards.Player);
                    foreach (MapClass unit in m_UnitDict[AttitudeTowards.Player])
                    {
                        unit.role.Holding(false);
                        unit.role.ResetMovePoint();
                        unit.swapper.SwapColors(color);
                    }

                    // 隐藏光标
                    DisplayMouseCursor(false);
                    turn = AttitudeTowards.Enemy;
                    GameDirector.instance.RunGameAction();
                    break;
                case AttitudeTowards.Enemy:
                    turn = AttitudeTowards.Ally;
                    break;
                case AttitudeTowards.Ally:
                    turn = AttitudeTowards.Neutral;
                    break;
                case AttitudeTowards.Neutral:
                    turn = AttitudeTowards.Player;
                    break;
            }


            if (m_UnitDict.ContainsKey(turn))
            {
                OnChangeTurn(turn);
            }
            else
            {
                // 如果不存在MapClass,直接下一组回合
                NextTurn();
            }
        }

        private void OnChangeTurn(AttitudeTowards turn)
        {
            // TODO 给出玩家切换回合的提示,并触发回合事件
        }

其中,OnChangeTurn是在切换回合时运行,它包含:

  • 给出玩家切换回合的提示;

  • 触发回合事件。

2.1 切换回合面板(UI Change Turn Panel)

我们创建一个面板,让其显示切换回合的提示。

UIChangeTurnPanel

  • 图 11.3 UIChangeTurnPanel

我在这里,只是单独改变文字透明度与颜色提示,你可以添加各种动画。

填充OnChangeTurn

        private void OnChangeTurn(AttitudeTowards turn)
        {
            // 播放转换回合的UI动画
            mapStatus = MapStatus.Animation;
            UIChangeTurnPanel panel = UIManager.views.OpenView<UIChangeTurnPanel>(UINames.k_UIChangeTurnPanel, false);
            panel.ChangeTurn(turn, () =>
            {
                UIManager.views.CloseView();

                // 触发回合事件
                TriggerEvents(MapEventConditionType.TurnCondition, () =>
                {
                    if (turn == AttitudeTowards.Player)
                    {
                        // 移动光标到首个玩家单位
                        MoveCursorCommand(m_UnitDict[AttitudeTowards.Player][0].cellPosition, 0.5f, ClearSelected);
                    }
                    else
                    {
                        ClearSelected();
                    }
                });
            });
        }

其中,MoveCursorCommand是移动光标到首个玩家单位。

2.2 移动光标(Move Cursor)

        /// <summary>
        /// 移动光标
        /// </summary>
        /// <param name="targetPos"></param>
        /// <param name="time"></param>
        public void MoveCursorCommand(Vector3Int targetPos, float time, Action onMoveEnd = null)
        {
            if (time <= 0f)
            {
                map.mouseCursor.UpdatePosition(targetPos);
                if (onMoveEnd != null)
                {
                    onMoveEnd();
                }
            }
            GameDirector.instance.StartCoroutine(MovingCursorToCell(targetPos, time, onMoveEnd));
        }

        private IEnumerator MovingCursorToCell(Vector3Int targetPos, float time, Action onMoveEnd)
        {
            mapStatus = MapStatus.Animation;

            Vector3 start = map.mouseCursor.transform.position;
            Vector3 end = map.GetCellPosition(targetPos);
            float t = 0f;

            while (t < time)
            {
                t += Time.deltaTime;
                Vector3 pos = Vector3.Lerp(start, end, t / time);
                map.mouseCursor.transform.position = pos;
                yield return null;
            }

            map.mouseCursor.UpdatePosition(targetPos);
            
            // 最后延迟0.5秒
            yield return new WaitForSeconds(0.5f);
            mapStatus = MapStatus.Normal;
            if (onMoveEnd != null)
            {
                onMoveEnd();
            }
        }

2.3 补充菜单(Change Turn Button)

这个操作,我们在MapMenu_OnButtonClick中进行补充:

                case UIMapMenuPanel.MenuTextID.TurnEnd:
                    NextTurn();
                    break;

3 触发事件(Trigger Events)

我们要在需要触发事件的地方,添加触发事件的方法。

  • 地图开始事件(LoadMapEvent)

            /// <summary>
            /// 读取事件
            /// </summary>
            /// <param name="info"></param>
            /// <returns></returns>
            private bool LoadMapEvent(MapEventInfo info)
            {
                // 省略代码
    
                // 执行地图加载事件
                TriggerEvents(MapEventConditionType.NoneCondition, () =>
                {
                    OnChangeTurn(AttitudeTowards.Player);
                });
    
                return true;
            }
    
  • 位置事件(HoldingMapClass)

            /// <summary>
            /// 待机
            /// </summary>
            /// <param name="mapClass"></param>
            protected void HoldingMapClass(MapClass mapClass)
            {
                // 只有玩家才会设置待机状态与颜色
                if (mapClass.role.attitudeTowards == AttitudeTowards.Player)
                {
                    mapClass.role.Holding(true);
                    mapClass.swapper.SwapColors(GetSwapperHoldingColorName());
                }
    
                // 如果是独有角色,触发坐标事件
                if (mapClass.role.roleType == RoleType.Unique)
                {
                    TriggerEvents(MapEventConditionType.PositionCondition, ClearSelected);
                }
                else
                {
                    ClearSelected();
                }
            }
    
  • 战斗对话事件(AttackMapClass)

            /// <summary>
            /// 攻击
            /// </summary>
            /// <param name="mapClass"></param>
            /// <param name="target"></param>
            protected void AttackMapClass(MapClass mapClass, MapClass target)
            {
                // 省略代码
    
                TriggerEvents(MapEventConditionType.RoleCombatTalkCondition, () =>
                {
                    mapStatus = MapStatus.Animation;
                    combatAnima.PlayAnimas(true);
                });
            }
    
  • 死亡事件(MapClass_OnCombatAnimaStop)

        /// <summary>
        /// 战斗结束回调
        /// </summary>
        /// <param name="combatAnima"></param>
        /// <param name="inMap"></param>
        private void MapClass_OnCombatAnimaStop(CombatAnimaController combatAnima, bool inMap)
        {
            // 省略代码

            if (unit0.role.isDead)
            {
                TriggerEvents(MapEventConditionType.RoleDeadCondition, () =>
                {
                    ClearSelected();
                    OnMapClassDead(unit0);
                    UIManager.views.CloseView();
                });
            }
            else if (unit1.role.isDead)
            {
                TriggerEvents(MapEventConditionType.RoleDeadCondition, () =>
                {
                    HoldingMapClass(unit0);
                    OnMapClassDead(unit1);
                    UIManager.views.CloseView();
                });
            }
            else
            {
                HoldingMapClass(unit0);
                UIManager.views.CloseView();
            }
        }

4 释放资源(Dispose)

同样的,我们的MapAction还没有重写Dispose方法。

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

            m_Status = ActionStatus.Error;
            if (m_ScenarioAction != null)
            {
                m_ScenarioAction.Dispose();
                m_ScenarioAction = null;
            }
            m_Turn = AttitudeTowards.Player;
            m_TurnToken = 0;

            m_SelectedCell = null;
            m_SelectedUnit = null;
            m_MapStatus = MapStatus.Normal;
            m_MovingEndCell = null;
            m_TargetUnit = null;

            m_NpcIndex = 0;

            foreach (KeyValuePair<AttitudeTowards, List<MapClass>> kvp in m_UnitDict)
            {
                if (kvp.Value == null)
                {
                    continue;
                }

                foreach (MapClass unit in kvp.Value)
                {
                    ObjectPool.DespawnUnsafe(unit.gameObject, true);
                }
            }
            m_UnitDict.Clear();

            foreach (MapObstacle obstacle in m_Obstacles)
            {
                ObjectPool.DespawnUnsafe(obstacle.gameObject, true);
            }
            m_Obstacles.Clear();

            if (m_EventCoroutine != null)
            {
                GameDirector.instance.StopCoroutine(m_EventCoroutine);
                m_EventCoroutine = null;
            }
            m_MapEvents.Clear();

            if (m_Map != null)
            {
                m_Map.HideRangeCursors();
                ObjectPool.DespawnUnsafe(m_Map.mouseCursor.gameObject);
                m_Map.mapCursorPool.DestroyRecycledImmediate();
                m_Map.mapObjectPool.DestroyRecycledImmediate();
                m_Map = null;
            }
        }

猜你喜欢

转载自blog.csdn.net/darkrabbit/article/details/87918535