Разрабатываю игру на юнити. Логика довольно объемна, поэтому оказалось очень удобным использовать события (event'ы). И пока должны выполняться несвязанные друг с другом события - например начало хода и фиксация камеры на игроке, все хорошо: в соответствующих скриптах подписываемся на событие, все красиво и удобно.
А вот другая ситуация: игрок щелкает мышью по детали корабля, нужно
сначала вызвать метод, узнающий, на какуюю деталь щелкнул игрок, и только
после этого несколько скриптов должны показать информацию об этой детали. Естественно, если вызвать в обратном порядке, то вылетит ошибка. Проблема: подписка скриптами осуществляется в Awake() или OnEnable() - при загрузке сцены. И никогда не знаешь, чей OnEnable() будет вызван первым. Какие есть варианты решения проблемы? Я вижу такие:
1)Делать два разных события - одно на обработку клика, второе для остальных, вызываемое в конце первого. В некоторых случаях я так и делал.
2)Делать подписку всех методов в одном месте. Т.е. в первом скрипте кроме своего метода подписывать и остальные - получится уродливая простыня, ООП в ужасе. Я такое использовал только один раз и все пытаюсь уйти от этого совсем. Вот, полюбуйтесь:
spoilerusing System.Collections;
using UnityEngine;
public class EventController_script : MonoBehaviour //Только методы, которые должны подписываться в строгом порядке
{
public EventContainer_class events;
public Trajectory_script trajectoryScript;
public TrajectoryGUI_script trajectoryGUIScript;
public PlayerMov_script playerMovScript;
public DateGUI_script dateGUIScript;
public CamMov_script camMovScript;
void OnEnable()
{
events = GetComponent<EventContainer_class>();
EventContainer_class.OnTrajectoryCall_event += events.CallOnTrajectoryCleanEvent;
EventContainer_class.OnTrajectoryCall_event += trajectoryScript.CalculateTrajectory;
EventContainer_class.OnTrajectoryCall_event += trajectoryGUIScript.DrawTrajectory;
EventContainer_class.OnTrajectoryClean_event += trajectoryGUIScript.CleanTrajectory;
EventContainer_class.OnTurnStart_event += WorldState_class.StartTurn;
EventContainer_class.OnTurnStart_event += dateGUIScript.UpdateDateBar;
EventContainer_class.OnTurnStart_event += events.CallOnTrajectoryCleanEvent;
EventContainer_class.OnTurnStart_event += events.CallOnCamReturnEvent;
EventContainer_class.OnTurnEnd_event += WorldState_class.StopTurn;
EventContainer_class.OnLand_event += WorldState_class.StopTurn;
EventContainer_class.OnLand_event += SceneSwitch_class.Land;
EventContainer_class.OnJump_event += WorldState_class.StopTurn;
EventContainer_class.OnJump_event += SceneSwitch_class.Jump;
}
void OnDisable()
{
events = GetComponent<EventContainer_class>();
EventContainer_class.OnTrajectoryCall_event -= events.CallOnTrajectoryCleanEvent;
EventContainer_class.OnTrajectoryCall_event -= trajectoryScript.CalculateTrajectory;
EventContainer_class.OnTrajectoryCall_event -= trajectoryGUIScript.DrawTrajectory;
EventContainer_class.OnTrajectoryClean_event -= trajectoryGUIScript.CleanTrajectory;
EventContainer_class.OnTurnStart_event -= WorldState_class.StartTurn;
EventContainer_class.OnTurnStart_event -= dateGUIScript.UpdateDateBar;
EventContainer_class.OnTurnStart_event -= events.CallOnTrajectoryCleanEvent;
EventContainer_class.OnTurnStart_event -= events.CallOnCamReturnEvent;
EventContainer_class.OnTurnEnd_event -= WorldState_class.StopTurn;
EventContainer_class.OnLand_event -= WorldState_class.StopTurn;
EventContainer_class.OnLand_event -= SceneSwitch_class.Land;
EventContainer_class.OnJump_event -= WorldState_class.StopTurn;
EventContainer_class.OnJump_event -= SceneSwitch_class.Jump;
}
}
И такой способ действует только для тех методов, которые должны быть подписаны один раз и существуют в единственном экземпляре. В общем, это решением не назвать.
3)Ваши варианты?
Еще у меня такой вопрос возник: где объявлять события? Пока у меня для этого отдельный класс-синглтон, в принципе устраивает, но интересно как в нормальных проектах такие вещи делаются.
P.S. поправка. OnEnable(), Awake() и прочие вызываются в порядке иерархии игровых объектов - метод родителя вызывается первым. Потестил - вроде действительно так. Но вот подписчики - они точно вызываются в порядке подписки? Хотя в какой-то статье читал, что да, но тем не менее. Да и как быть, если объекты не в иерархии друг друга или их иерархия заранее не известна?