Event system in Unity RPG game











up vote
9
down vote

favorite
4












I'm making event system for my RPG game, and I want to know what I can do better, because I think that there are a lot things that can be better. Note that this code is still not completed but it works good, so could you tell me what of bad practises can you find there?



Event:



using UnityEngine;

[System.Serializable]
public class Event
{
public enum Condition
{
VisitPlace,
HaveItem,
KillNpcs,
}

public enum Effect
{
ChangePlayerHP,
GiveItemToPlayer,
RemoveItemFromPlayerEquipment,
GiveExperiencePoints,
StartDialog,
EndDialog,
SpawnObject,
TeleportPlayer,
GiveQuest,
RemoveQuest,
IncrementActualStatusOfQuest,
ThrowSpell,
KillNpcs,
EnableOrDisableAnotherEvent
}

public string eventName;
public Condition condition;
public Effect effect;

public float delay; //delay after which event have to be executed
public int intModifiter; //int modifiter for every effect type that require it
public float floatModifiter; //float modifiter for every effect type that require it
public GameObject gameObjectToSpawn; //for spawnobject effect
public CharacterStats condCharacterStats; //character stats for condition
public CharacterStats effCharacterStats; //character stats for effect
public int conditionItemsIndexes; //indexes of items that will be required to play event
public int effectItemsIndexes; //indexes of items that have to be removed or given after executing event effect

public bool enable; //enable or disable another event?
public bool positiveResult; //defines that condition was satisfied or not.
public bool finished; //is event finished?
public bool isPlaying; //is event playing?
public bool isEnabled = true; //defines event activity

#region property drawer

//bool contains item expanded status
public bool expanded;

//condition items array
public bool condExpanded;
public int condArrLength;

//effect items array
public bool effExpanded;
public int effArrLength;

//character stats condition array
public bool chcExpanded;
public int chcArrLength;

//character stats condition array
public bool cheExpanded;
public int cheArrLength;

#endregion property drawer

public void PlayEvent(EventManager em)
{
IEventConditionable tmp = null;
switch (effect)
{
case Effect.GiveExperiencePoints: tmp = new ExperienceEvent(intModifiter); break;
case Effect.GiveItemToPlayer: tmp = new ItemEvent(effectItemsIndexes, true); break;
case Effect.RemoveItemFromPlayerEquipment: tmp = new ItemEvent(effectItemsIndexes, false); break;
case Effect.GiveQuest: tmp = new QuestEvent(QuestEventType.GiveQuest, intModifiter); break;
case Effect.RemoveQuest: tmp = new QuestEvent(QuestEventType.RemoveQuest, intModifiter); break;
case Effect.IncrementActualStatusOfQuest: tmp = new QuestEvent(QuestEventType.IncrementQuestStatus, intModifiter); break;
case Effect.EnableOrDisableAnotherEvent: tmp = new AnotherEventsRelationsEvent(intModifiter, enable, em); break;
default: Debug.Log("Event cannot be recognized."); break;
}

if(tmp != null)
tmp.Play();
}
}

public interface IEventConditionable
{
void Play();
}

public enum QuestEventType
{
GiveQuest,
RemoveQuest,
IncrementQuestStatus,
}

public class AnotherEventsRelationsEvent : IEventConditionable
{
private int eventIndex;
private bool enable;
private EventManager em;

public void Play()
{
em.events[eventIndex].isEnabled = enable;
}

public AnotherEventsRelationsEvent(int eventIndex, bool enable, EventManager em)
{
this.eventIndex = eventIndex;
this.enable = enable;
this.em = em;
}
}

public class QuestEvent : IEventConditionable
{
private QuestEventType questEventType;
private int questNr;

public void Play()
{
if (questNr < QuestManager.getInstance.GetAllQuestsLength)
{
switch(questEventType)
{
case QuestEventType.GiveQuest:
QuestManager.getInstance.AddQuest(questNr);
break;
case QuestEventType.RemoveQuest:
QuestManager.getInstance.RemoveQuest(questNr);
break;
case QuestEventType.IncrementQuestStatus:
QuestManager.getInstance.IncrementQuestStatus(questNr);
break;
}
}

QuestManager.getInstance.ShowQuestUpdatedIcon();
}

public QuestEvent(QuestEventType questEventType, int questNr)
{
this.questEventType = questEventType;
this.questNr = questNr;
}
}

public class ExperienceEvent : IEventConditionable
{
private int experience;

public void Play()
{
PlayerStatsManager.getInstance.stats.experience += experience;
}

public ExperienceEvent(int experience)
{
this.experience = experience;
}
}

public class ItemEvent : IEventConditionable
{
private int itemIndexes;
private bool give;

public void Play()
{
foreach (int itemIndex in itemIndexes)
{
if (give)
EquipmentContainer.getInstance.AddInternalItem(itemIndex);
else
EquipmentContainer.getInstance.RemoveItem(itemIndex);
}
}

public ItemEvent(int itemIndexes, bool give)
{
this.itemIndexes = itemIndexes;
this.give = give;
}
}


There are many variables because I created property drawer for this class.
The event class describes all events in game, it can give quests for player, remove it, give items etc.



EventManager:



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

public class EventManager : MonoBehaviour
{
private bool checking; //is CheckEvents coroutine running?
public float eventCheckerDelay = 0.1f; //divide every CheckEvents calling
public List<Event> events;

private IEnumerator CheckEvents()
{
checking = true;

if (!AllEventsAreFinished())
foreach (Event e in events)
if (e.isEnabled && !e.isPlaying && !e.finished && e.positiveResult)
StartCoroutine(PlayEvent(e));

yield return new WaitForSeconds(eventCheckerDelay); //execute coroutine after every eventCheckerDelay value

checking = false;
StopCoroutine(CheckEvents());
}

private IEnumerator PlayEvent(Event e)
{
e.isPlaying = true;

yield return new WaitForSeconds(e.delay);
e.PlayEvent(this);

e.isPlaying = false;
e.finished = true;
StopCoroutine(PlayEvent(e));
}


private bool AllEventsAreFinished()
{
return events.All(item => item.finished);
}

private void Update()
{
if(!checking)
StartCoroutine(CheckEvents());
}
}


The EventManager class manages all events and checks that they can be played.



EventHandler:



using UnityEngine;
using System.Collections;
using System.Linq;

public class EventHandler : MonoBehaviour {

private bool lastRes;
private bool collisionChecking;
public int indexesOfEventsToEnable; //enable events with indexes assigned in array

public EventManager connectedEventManager;

private IEnumerator CheckCollisions()
{
collisionChecking = true;
bool playerIsColliding = Physics.OverlapBox(transform.position,
transform.localScale * 0.5f,
transform.rotation).
Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player")).
ToArray().Length > 0; //Used overlapbox instead of onTriggerEnter or onCollisionEnter because overlap functions can catch many colliders in the same time

if (playerIsColliding && !lastRes) //if player is colliding, and last sended result is false
SendResult(true);
else if (!playerIsColliding && lastRes)
SendResult(false);

yield return new WaitForSeconds(0.2f); //the script doesn't need huge precision, it can repeat execution after every 200 milliseconds
collisionChecking = false;
StopCoroutine(CheckCollisions());
}

public void SendResult(bool result)
{
foreach (int i in indexesOfEventsToEnable)
if(connectedEventManager.events[i].isEnabled)
connectedEventManager.events[i].positiveResult = result;

lastRes = result; //set last result to sended as parameter result to stop send collision results
}

private void Update()
{
if (indexesOfEventsToEnable.Length > 0 && connectedEventManager && !collisionChecking)
StartCoroutine(CheckCollisions());
else
Debug.LogError("Event manager or Event conditions are not assigned. Instance name: " + name);
}
}


The EventHandler class that executes events when player collides with it.










share|improve this question




























    up vote
    9
    down vote

    favorite
    4












    I'm making event system for my RPG game, and I want to know what I can do better, because I think that there are a lot things that can be better. Note that this code is still not completed but it works good, so could you tell me what of bad practises can you find there?



    Event:



    using UnityEngine;

    [System.Serializable]
    public class Event
    {
    public enum Condition
    {
    VisitPlace,
    HaveItem,
    KillNpcs,
    }

    public enum Effect
    {
    ChangePlayerHP,
    GiveItemToPlayer,
    RemoveItemFromPlayerEquipment,
    GiveExperiencePoints,
    StartDialog,
    EndDialog,
    SpawnObject,
    TeleportPlayer,
    GiveQuest,
    RemoveQuest,
    IncrementActualStatusOfQuest,
    ThrowSpell,
    KillNpcs,
    EnableOrDisableAnotherEvent
    }

    public string eventName;
    public Condition condition;
    public Effect effect;

    public float delay; //delay after which event have to be executed
    public int intModifiter; //int modifiter for every effect type that require it
    public float floatModifiter; //float modifiter for every effect type that require it
    public GameObject gameObjectToSpawn; //for spawnobject effect
    public CharacterStats condCharacterStats; //character stats for condition
    public CharacterStats effCharacterStats; //character stats for effect
    public int conditionItemsIndexes; //indexes of items that will be required to play event
    public int effectItemsIndexes; //indexes of items that have to be removed or given after executing event effect

    public bool enable; //enable or disable another event?
    public bool positiveResult; //defines that condition was satisfied or not.
    public bool finished; //is event finished?
    public bool isPlaying; //is event playing?
    public bool isEnabled = true; //defines event activity

    #region property drawer

    //bool contains item expanded status
    public bool expanded;

    //condition items array
    public bool condExpanded;
    public int condArrLength;

    //effect items array
    public bool effExpanded;
    public int effArrLength;

    //character stats condition array
    public bool chcExpanded;
    public int chcArrLength;

    //character stats condition array
    public bool cheExpanded;
    public int cheArrLength;

    #endregion property drawer

    public void PlayEvent(EventManager em)
    {
    IEventConditionable tmp = null;
    switch (effect)
    {
    case Effect.GiveExperiencePoints: tmp = new ExperienceEvent(intModifiter); break;
    case Effect.GiveItemToPlayer: tmp = new ItemEvent(effectItemsIndexes, true); break;
    case Effect.RemoveItemFromPlayerEquipment: tmp = new ItemEvent(effectItemsIndexes, false); break;
    case Effect.GiveQuest: tmp = new QuestEvent(QuestEventType.GiveQuest, intModifiter); break;
    case Effect.RemoveQuest: tmp = new QuestEvent(QuestEventType.RemoveQuest, intModifiter); break;
    case Effect.IncrementActualStatusOfQuest: tmp = new QuestEvent(QuestEventType.IncrementQuestStatus, intModifiter); break;
    case Effect.EnableOrDisableAnotherEvent: tmp = new AnotherEventsRelationsEvent(intModifiter, enable, em); break;
    default: Debug.Log("Event cannot be recognized."); break;
    }

    if(tmp != null)
    tmp.Play();
    }
    }

    public interface IEventConditionable
    {
    void Play();
    }

    public enum QuestEventType
    {
    GiveQuest,
    RemoveQuest,
    IncrementQuestStatus,
    }

    public class AnotherEventsRelationsEvent : IEventConditionable
    {
    private int eventIndex;
    private bool enable;
    private EventManager em;

    public void Play()
    {
    em.events[eventIndex].isEnabled = enable;
    }

    public AnotherEventsRelationsEvent(int eventIndex, bool enable, EventManager em)
    {
    this.eventIndex = eventIndex;
    this.enable = enable;
    this.em = em;
    }
    }

    public class QuestEvent : IEventConditionable
    {
    private QuestEventType questEventType;
    private int questNr;

    public void Play()
    {
    if (questNr < QuestManager.getInstance.GetAllQuestsLength)
    {
    switch(questEventType)
    {
    case QuestEventType.GiveQuest:
    QuestManager.getInstance.AddQuest(questNr);
    break;
    case QuestEventType.RemoveQuest:
    QuestManager.getInstance.RemoveQuest(questNr);
    break;
    case QuestEventType.IncrementQuestStatus:
    QuestManager.getInstance.IncrementQuestStatus(questNr);
    break;
    }
    }

    QuestManager.getInstance.ShowQuestUpdatedIcon();
    }

    public QuestEvent(QuestEventType questEventType, int questNr)
    {
    this.questEventType = questEventType;
    this.questNr = questNr;
    }
    }

    public class ExperienceEvent : IEventConditionable
    {
    private int experience;

    public void Play()
    {
    PlayerStatsManager.getInstance.stats.experience += experience;
    }

    public ExperienceEvent(int experience)
    {
    this.experience = experience;
    }
    }

    public class ItemEvent : IEventConditionable
    {
    private int itemIndexes;
    private bool give;

    public void Play()
    {
    foreach (int itemIndex in itemIndexes)
    {
    if (give)
    EquipmentContainer.getInstance.AddInternalItem(itemIndex);
    else
    EquipmentContainer.getInstance.RemoveItem(itemIndex);
    }
    }

    public ItemEvent(int itemIndexes, bool give)
    {
    this.itemIndexes = itemIndexes;
    this.give = give;
    }
    }


    There are many variables because I created property drawer for this class.
    The event class describes all events in game, it can give quests for player, remove it, give items etc.



    EventManager:



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

    public class EventManager : MonoBehaviour
    {
    private bool checking; //is CheckEvents coroutine running?
    public float eventCheckerDelay = 0.1f; //divide every CheckEvents calling
    public List<Event> events;

    private IEnumerator CheckEvents()
    {
    checking = true;

    if (!AllEventsAreFinished())
    foreach (Event e in events)
    if (e.isEnabled && !e.isPlaying && !e.finished && e.positiveResult)
    StartCoroutine(PlayEvent(e));

    yield return new WaitForSeconds(eventCheckerDelay); //execute coroutine after every eventCheckerDelay value

    checking = false;
    StopCoroutine(CheckEvents());
    }

    private IEnumerator PlayEvent(Event e)
    {
    e.isPlaying = true;

    yield return new WaitForSeconds(e.delay);
    e.PlayEvent(this);

    e.isPlaying = false;
    e.finished = true;
    StopCoroutine(PlayEvent(e));
    }


    private bool AllEventsAreFinished()
    {
    return events.All(item => item.finished);
    }

    private void Update()
    {
    if(!checking)
    StartCoroutine(CheckEvents());
    }
    }


    The EventManager class manages all events and checks that they can be played.



    EventHandler:



    using UnityEngine;
    using System.Collections;
    using System.Linq;

    public class EventHandler : MonoBehaviour {

    private bool lastRes;
    private bool collisionChecking;
    public int indexesOfEventsToEnable; //enable events with indexes assigned in array

    public EventManager connectedEventManager;

    private IEnumerator CheckCollisions()
    {
    collisionChecking = true;
    bool playerIsColliding = Physics.OverlapBox(transform.position,
    transform.localScale * 0.5f,
    transform.rotation).
    Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player")).
    ToArray().Length > 0; //Used overlapbox instead of onTriggerEnter or onCollisionEnter because overlap functions can catch many colliders in the same time

    if (playerIsColliding && !lastRes) //if player is colliding, and last sended result is false
    SendResult(true);
    else if (!playerIsColliding && lastRes)
    SendResult(false);

    yield return new WaitForSeconds(0.2f); //the script doesn't need huge precision, it can repeat execution after every 200 milliseconds
    collisionChecking = false;
    StopCoroutine(CheckCollisions());
    }

    public void SendResult(bool result)
    {
    foreach (int i in indexesOfEventsToEnable)
    if(connectedEventManager.events[i].isEnabled)
    connectedEventManager.events[i].positiveResult = result;

    lastRes = result; //set last result to sended as parameter result to stop send collision results
    }

    private void Update()
    {
    if (indexesOfEventsToEnable.Length > 0 && connectedEventManager && !collisionChecking)
    StartCoroutine(CheckCollisions());
    else
    Debug.LogError("Event manager or Event conditions are not assigned. Instance name: " + name);
    }
    }


    The EventHandler class that executes events when player collides with it.










    share|improve this question


























      up vote
      9
      down vote

      favorite
      4









      up vote
      9
      down vote

      favorite
      4






      4





      I'm making event system for my RPG game, and I want to know what I can do better, because I think that there are a lot things that can be better. Note that this code is still not completed but it works good, so could you tell me what of bad practises can you find there?



      Event:



      using UnityEngine;

      [System.Serializable]
      public class Event
      {
      public enum Condition
      {
      VisitPlace,
      HaveItem,
      KillNpcs,
      }

      public enum Effect
      {
      ChangePlayerHP,
      GiveItemToPlayer,
      RemoveItemFromPlayerEquipment,
      GiveExperiencePoints,
      StartDialog,
      EndDialog,
      SpawnObject,
      TeleportPlayer,
      GiveQuest,
      RemoveQuest,
      IncrementActualStatusOfQuest,
      ThrowSpell,
      KillNpcs,
      EnableOrDisableAnotherEvent
      }

      public string eventName;
      public Condition condition;
      public Effect effect;

      public float delay; //delay after which event have to be executed
      public int intModifiter; //int modifiter for every effect type that require it
      public float floatModifiter; //float modifiter for every effect type that require it
      public GameObject gameObjectToSpawn; //for spawnobject effect
      public CharacterStats condCharacterStats; //character stats for condition
      public CharacterStats effCharacterStats; //character stats for effect
      public int conditionItemsIndexes; //indexes of items that will be required to play event
      public int effectItemsIndexes; //indexes of items that have to be removed or given after executing event effect

      public bool enable; //enable or disable another event?
      public bool positiveResult; //defines that condition was satisfied or not.
      public bool finished; //is event finished?
      public bool isPlaying; //is event playing?
      public bool isEnabled = true; //defines event activity

      #region property drawer

      //bool contains item expanded status
      public bool expanded;

      //condition items array
      public bool condExpanded;
      public int condArrLength;

      //effect items array
      public bool effExpanded;
      public int effArrLength;

      //character stats condition array
      public bool chcExpanded;
      public int chcArrLength;

      //character stats condition array
      public bool cheExpanded;
      public int cheArrLength;

      #endregion property drawer

      public void PlayEvent(EventManager em)
      {
      IEventConditionable tmp = null;
      switch (effect)
      {
      case Effect.GiveExperiencePoints: tmp = new ExperienceEvent(intModifiter); break;
      case Effect.GiveItemToPlayer: tmp = new ItemEvent(effectItemsIndexes, true); break;
      case Effect.RemoveItemFromPlayerEquipment: tmp = new ItemEvent(effectItemsIndexes, false); break;
      case Effect.GiveQuest: tmp = new QuestEvent(QuestEventType.GiveQuest, intModifiter); break;
      case Effect.RemoveQuest: tmp = new QuestEvent(QuestEventType.RemoveQuest, intModifiter); break;
      case Effect.IncrementActualStatusOfQuest: tmp = new QuestEvent(QuestEventType.IncrementQuestStatus, intModifiter); break;
      case Effect.EnableOrDisableAnotherEvent: tmp = new AnotherEventsRelationsEvent(intModifiter, enable, em); break;
      default: Debug.Log("Event cannot be recognized."); break;
      }

      if(tmp != null)
      tmp.Play();
      }
      }

      public interface IEventConditionable
      {
      void Play();
      }

      public enum QuestEventType
      {
      GiveQuest,
      RemoveQuest,
      IncrementQuestStatus,
      }

      public class AnotherEventsRelationsEvent : IEventConditionable
      {
      private int eventIndex;
      private bool enable;
      private EventManager em;

      public void Play()
      {
      em.events[eventIndex].isEnabled = enable;
      }

      public AnotherEventsRelationsEvent(int eventIndex, bool enable, EventManager em)
      {
      this.eventIndex = eventIndex;
      this.enable = enable;
      this.em = em;
      }
      }

      public class QuestEvent : IEventConditionable
      {
      private QuestEventType questEventType;
      private int questNr;

      public void Play()
      {
      if (questNr < QuestManager.getInstance.GetAllQuestsLength)
      {
      switch(questEventType)
      {
      case QuestEventType.GiveQuest:
      QuestManager.getInstance.AddQuest(questNr);
      break;
      case QuestEventType.RemoveQuest:
      QuestManager.getInstance.RemoveQuest(questNr);
      break;
      case QuestEventType.IncrementQuestStatus:
      QuestManager.getInstance.IncrementQuestStatus(questNr);
      break;
      }
      }

      QuestManager.getInstance.ShowQuestUpdatedIcon();
      }

      public QuestEvent(QuestEventType questEventType, int questNr)
      {
      this.questEventType = questEventType;
      this.questNr = questNr;
      }
      }

      public class ExperienceEvent : IEventConditionable
      {
      private int experience;

      public void Play()
      {
      PlayerStatsManager.getInstance.stats.experience += experience;
      }

      public ExperienceEvent(int experience)
      {
      this.experience = experience;
      }
      }

      public class ItemEvent : IEventConditionable
      {
      private int itemIndexes;
      private bool give;

      public void Play()
      {
      foreach (int itemIndex in itemIndexes)
      {
      if (give)
      EquipmentContainer.getInstance.AddInternalItem(itemIndex);
      else
      EquipmentContainer.getInstance.RemoveItem(itemIndex);
      }
      }

      public ItemEvent(int itemIndexes, bool give)
      {
      this.itemIndexes = itemIndexes;
      this.give = give;
      }
      }


      There are many variables because I created property drawer for this class.
      The event class describes all events in game, it can give quests for player, remove it, give items etc.



      EventManager:



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

      public class EventManager : MonoBehaviour
      {
      private bool checking; //is CheckEvents coroutine running?
      public float eventCheckerDelay = 0.1f; //divide every CheckEvents calling
      public List<Event> events;

      private IEnumerator CheckEvents()
      {
      checking = true;

      if (!AllEventsAreFinished())
      foreach (Event e in events)
      if (e.isEnabled && !e.isPlaying && !e.finished && e.positiveResult)
      StartCoroutine(PlayEvent(e));

      yield return new WaitForSeconds(eventCheckerDelay); //execute coroutine after every eventCheckerDelay value

      checking = false;
      StopCoroutine(CheckEvents());
      }

      private IEnumerator PlayEvent(Event e)
      {
      e.isPlaying = true;

      yield return new WaitForSeconds(e.delay);
      e.PlayEvent(this);

      e.isPlaying = false;
      e.finished = true;
      StopCoroutine(PlayEvent(e));
      }


      private bool AllEventsAreFinished()
      {
      return events.All(item => item.finished);
      }

      private void Update()
      {
      if(!checking)
      StartCoroutine(CheckEvents());
      }
      }


      The EventManager class manages all events and checks that they can be played.



      EventHandler:



      using UnityEngine;
      using System.Collections;
      using System.Linq;

      public class EventHandler : MonoBehaviour {

      private bool lastRes;
      private bool collisionChecking;
      public int indexesOfEventsToEnable; //enable events with indexes assigned in array

      public EventManager connectedEventManager;

      private IEnumerator CheckCollisions()
      {
      collisionChecking = true;
      bool playerIsColliding = Physics.OverlapBox(transform.position,
      transform.localScale * 0.5f,
      transform.rotation).
      Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player")).
      ToArray().Length > 0; //Used overlapbox instead of onTriggerEnter or onCollisionEnter because overlap functions can catch many colliders in the same time

      if (playerIsColliding && !lastRes) //if player is colliding, and last sended result is false
      SendResult(true);
      else if (!playerIsColliding && lastRes)
      SendResult(false);

      yield return new WaitForSeconds(0.2f); //the script doesn't need huge precision, it can repeat execution after every 200 milliseconds
      collisionChecking = false;
      StopCoroutine(CheckCollisions());
      }

      public void SendResult(bool result)
      {
      foreach (int i in indexesOfEventsToEnable)
      if(connectedEventManager.events[i].isEnabled)
      connectedEventManager.events[i].positiveResult = result;

      lastRes = result; //set last result to sended as parameter result to stop send collision results
      }

      private void Update()
      {
      if (indexesOfEventsToEnable.Length > 0 && connectedEventManager && !collisionChecking)
      StartCoroutine(CheckCollisions());
      else
      Debug.LogError("Event manager or Event conditions are not assigned. Instance name: " + name);
      }
      }


      The EventHandler class that executes events when player collides with it.










      share|improve this question















      I'm making event system for my RPG game, and I want to know what I can do better, because I think that there are a lot things that can be better. Note that this code is still not completed but it works good, so could you tell me what of bad practises can you find there?



      Event:



      using UnityEngine;

      [System.Serializable]
      public class Event
      {
      public enum Condition
      {
      VisitPlace,
      HaveItem,
      KillNpcs,
      }

      public enum Effect
      {
      ChangePlayerHP,
      GiveItemToPlayer,
      RemoveItemFromPlayerEquipment,
      GiveExperiencePoints,
      StartDialog,
      EndDialog,
      SpawnObject,
      TeleportPlayer,
      GiveQuest,
      RemoveQuest,
      IncrementActualStatusOfQuest,
      ThrowSpell,
      KillNpcs,
      EnableOrDisableAnotherEvent
      }

      public string eventName;
      public Condition condition;
      public Effect effect;

      public float delay; //delay after which event have to be executed
      public int intModifiter; //int modifiter for every effect type that require it
      public float floatModifiter; //float modifiter for every effect type that require it
      public GameObject gameObjectToSpawn; //for spawnobject effect
      public CharacterStats condCharacterStats; //character stats for condition
      public CharacterStats effCharacterStats; //character stats for effect
      public int conditionItemsIndexes; //indexes of items that will be required to play event
      public int effectItemsIndexes; //indexes of items that have to be removed or given after executing event effect

      public bool enable; //enable or disable another event?
      public bool positiveResult; //defines that condition was satisfied or not.
      public bool finished; //is event finished?
      public bool isPlaying; //is event playing?
      public bool isEnabled = true; //defines event activity

      #region property drawer

      //bool contains item expanded status
      public bool expanded;

      //condition items array
      public bool condExpanded;
      public int condArrLength;

      //effect items array
      public bool effExpanded;
      public int effArrLength;

      //character stats condition array
      public bool chcExpanded;
      public int chcArrLength;

      //character stats condition array
      public bool cheExpanded;
      public int cheArrLength;

      #endregion property drawer

      public void PlayEvent(EventManager em)
      {
      IEventConditionable tmp = null;
      switch (effect)
      {
      case Effect.GiveExperiencePoints: tmp = new ExperienceEvent(intModifiter); break;
      case Effect.GiveItemToPlayer: tmp = new ItemEvent(effectItemsIndexes, true); break;
      case Effect.RemoveItemFromPlayerEquipment: tmp = new ItemEvent(effectItemsIndexes, false); break;
      case Effect.GiveQuest: tmp = new QuestEvent(QuestEventType.GiveQuest, intModifiter); break;
      case Effect.RemoveQuest: tmp = new QuestEvent(QuestEventType.RemoveQuest, intModifiter); break;
      case Effect.IncrementActualStatusOfQuest: tmp = new QuestEvent(QuestEventType.IncrementQuestStatus, intModifiter); break;
      case Effect.EnableOrDisableAnotherEvent: tmp = new AnotherEventsRelationsEvent(intModifiter, enable, em); break;
      default: Debug.Log("Event cannot be recognized."); break;
      }

      if(tmp != null)
      tmp.Play();
      }
      }

      public interface IEventConditionable
      {
      void Play();
      }

      public enum QuestEventType
      {
      GiveQuest,
      RemoveQuest,
      IncrementQuestStatus,
      }

      public class AnotherEventsRelationsEvent : IEventConditionable
      {
      private int eventIndex;
      private bool enable;
      private EventManager em;

      public void Play()
      {
      em.events[eventIndex].isEnabled = enable;
      }

      public AnotherEventsRelationsEvent(int eventIndex, bool enable, EventManager em)
      {
      this.eventIndex = eventIndex;
      this.enable = enable;
      this.em = em;
      }
      }

      public class QuestEvent : IEventConditionable
      {
      private QuestEventType questEventType;
      private int questNr;

      public void Play()
      {
      if (questNr < QuestManager.getInstance.GetAllQuestsLength)
      {
      switch(questEventType)
      {
      case QuestEventType.GiveQuest:
      QuestManager.getInstance.AddQuest(questNr);
      break;
      case QuestEventType.RemoveQuest:
      QuestManager.getInstance.RemoveQuest(questNr);
      break;
      case QuestEventType.IncrementQuestStatus:
      QuestManager.getInstance.IncrementQuestStatus(questNr);
      break;
      }
      }

      QuestManager.getInstance.ShowQuestUpdatedIcon();
      }

      public QuestEvent(QuestEventType questEventType, int questNr)
      {
      this.questEventType = questEventType;
      this.questNr = questNr;
      }
      }

      public class ExperienceEvent : IEventConditionable
      {
      private int experience;

      public void Play()
      {
      PlayerStatsManager.getInstance.stats.experience += experience;
      }

      public ExperienceEvent(int experience)
      {
      this.experience = experience;
      }
      }

      public class ItemEvent : IEventConditionable
      {
      private int itemIndexes;
      private bool give;

      public void Play()
      {
      foreach (int itemIndex in itemIndexes)
      {
      if (give)
      EquipmentContainer.getInstance.AddInternalItem(itemIndex);
      else
      EquipmentContainer.getInstance.RemoveItem(itemIndex);
      }
      }

      public ItemEvent(int itemIndexes, bool give)
      {
      this.itemIndexes = itemIndexes;
      this.give = give;
      }
      }


      There are many variables because I created property drawer for this class.
      The event class describes all events in game, it can give quests for player, remove it, give items etc.



      EventManager:



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

      public class EventManager : MonoBehaviour
      {
      private bool checking; //is CheckEvents coroutine running?
      public float eventCheckerDelay = 0.1f; //divide every CheckEvents calling
      public List<Event> events;

      private IEnumerator CheckEvents()
      {
      checking = true;

      if (!AllEventsAreFinished())
      foreach (Event e in events)
      if (e.isEnabled && !e.isPlaying && !e.finished && e.positiveResult)
      StartCoroutine(PlayEvent(e));

      yield return new WaitForSeconds(eventCheckerDelay); //execute coroutine after every eventCheckerDelay value

      checking = false;
      StopCoroutine(CheckEvents());
      }

      private IEnumerator PlayEvent(Event e)
      {
      e.isPlaying = true;

      yield return new WaitForSeconds(e.delay);
      e.PlayEvent(this);

      e.isPlaying = false;
      e.finished = true;
      StopCoroutine(PlayEvent(e));
      }


      private bool AllEventsAreFinished()
      {
      return events.All(item => item.finished);
      }

      private void Update()
      {
      if(!checking)
      StartCoroutine(CheckEvents());
      }
      }


      The EventManager class manages all events and checks that they can be played.



      EventHandler:



      using UnityEngine;
      using System.Collections;
      using System.Linq;

      public class EventHandler : MonoBehaviour {

      private bool lastRes;
      private bool collisionChecking;
      public int indexesOfEventsToEnable; //enable events with indexes assigned in array

      public EventManager connectedEventManager;

      private IEnumerator CheckCollisions()
      {
      collisionChecking = true;
      bool playerIsColliding = Physics.OverlapBox(transform.position,
      transform.localScale * 0.5f,
      transform.rotation).
      Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player")).
      ToArray().Length > 0; //Used overlapbox instead of onTriggerEnter or onCollisionEnter because overlap functions can catch many colliders in the same time

      if (playerIsColliding && !lastRes) //if player is colliding, and last sended result is false
      SendResult(true);
      else if (!playerIsColliding && lastRes)
      SendResult(false);

      yield return new WaitForSeconds(0.2f); //the script doesn't need huge precision, it can repeat execution after every 200 milliseconds
      collisionChecking = false;
      StopCoroutine(CheckCollisions());
      }

      public void SendResult(bool result)
      {
      foreach (int i in indexesOfEventsToEnable)
      if(connectedEventManager.events[i].isEnabled)
      connectedEventManager.events[i].positiveResult = result;

      lastRes = result; //set last result to sended as parameter result to stop send collision results
      }

      private void Update()
      {
      if (indexesOfEventsToEnable.Length > 0 && connectedEventManager && !collisionChecking)
      StartCoroutine(CheckCollisions());
      else
      Debug.LogError("Event manager or Event conditions are not assigned. Instance name: " + name);
      }
      }


      The EventHandler class that executes events when player collides with it.







      c# game unity3d






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited May 6 at 13:02









      sonny

      18110




      18110










      asked Jan 21 '17 at 23:02









      Michael

      10517




      10517






















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          6
          down vote














          public int intModifiter;          //int modifiter for every effect type that require it
          public float floatModifiter; //float modifiter for every effect type that require it



          You write in the comment modifiter for every effect type so why not give the variable such a name: effectTypeModifier?



          I nowhere see the floatModifiter being used. This could be removed.






          public bool enable;           //enable or disable another event?
          public bool isEnabled = true; //defines event activity



          enable and isEnabled are too similar. You need a better name at least for one of them besides enable sound like an action so maybe canEnableNextEvent?






          public bool positiveResult;   //defines that condition was satisfied or not.



          How about success(ful)?






          public bool finished;         //is event finished?
          public bool isPlaying; //is event playing?



          The code could use some more consistency. Make them both have the is prefix or none of them.






          public bool condExpanded;
          public int condArrLength;
          public bool effExpanded;
          public int effArrLength;
          ..



          You shouldn't use abbreviated names if they are not some common abbreviations like Html or Xml.






          public interface IEventConditionable
          {
          void Play();
          }



          This interface is named Conditionable but it contains a Play method. There is nothing about any conditions. The name IPlayable would be much better I think.






          public void PlayEvent(EventManager em)
          {
          IEventConditionable tmp = null;
          switch (effect)
          {
          case Effect.GiveExperiencePoints: tmp = new ExperienceEvent(intModifiter); break;
          case Effect.GiveItemToPlayer: tmp = new ItemEvent(effectItemsIndexes, true); break;
          case Effect.RemoveItemFromPlayerEquipment: tmp = new ItemEvent(effectItemsIndexes, false); break;
          case Effect.GiveQuest: tmp = new QuestEvent(QuestEventType.GiveQuest, intModifiter); break;
          case Effect.RemoveQuest: tmp = new QuestEvent(QuestEventType.RemoveQuest, intModifiter); break;
          case Effect.IncrementActualStatusOfQuest: tmp = new QuestEvent(QuestEventType.IncrementQuestStatus, intModifiter); break;
          case Effect.EnableOrDisableAnotherEvent: tmp = new AnotherEventsRelationsEvent(intModifiter, enable, em); break;
          default: Debug.Log("Event cannot be recognized."); break;
          }

          if (tmp != null)
          tmp.Play();
          }



          This method doesn't require the tmp variable. You don't store the result anywhere so you could simply call Play inside the switch just after you create an event:



          switch (effect)
          {
          case Effect.GiveExperiencePoints: new ExperienceEvent(intModifiter).Play(); break;
          ..
          }





          private bool lastRes;



          And again an abbrevaited name. Does Res stand for result, resolution, rest or restaurant? You won't know this in a few days/weeks anymore.






          bool playerIsColliding = Physics.OverlapBox(
          transform.position,
          transform.localScale * 0.5f,
          transform.rotation
          )
          .Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player"))
          .ToArray()
          .Length > 0;



          You can call simply Count on this.



          bool playerIsColliding = Physics.OverlapBox(
          ..
          )
          .Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player"))
          .Count() > 0;





          share|improve this answer























          • Thanks, I will correct that things. Could you tell me how do you think about quality of my code if I will correct it?
            – Michael
            Jan 22 '17 at 15:20












          • @Michael we'll do, just keep in mind this: What should I do when someone answers my question? - you can post either a self-answer or a follow-up, don't edit your question ;-)
            – t3chb0t
            Jan 22 '17 at 15:26










          • @Michael but I recommend you wait another day or two or three, you might receive more answers and more advices.
            – t3chb0t
            Jan 22 '17 at 15:27












          • Ok, I didn't changed my code and I will not do it there.
            – Michael
            Jan 22 '17 at 15:32


















          up vote
          3
          down vote













          Wauw, many many things to go over.



          These are my versions of your "Events"



          public class GiveEquipment
          {
          private int items;
          private Equipment equipment;

          public GiveEquipment(int items, Equipment equipment)
          {
          this.items = items;
          this.equipment = equipment;
          }

          public void Execute()
          {
          equipment.AddAll(items);
          }
          }

          public class RemoveEquipment
          {
          private int items;
          private Equipment equipment;

          public RemoveEquipment(int items, Equipment equipment)
          {
          this.items = items;
          this.equipment = equipment;
          }

          public void Execute()
          {
          equipment.RemoveAll(items);
          }
          }

          public class GainExperience
          {
          private int experience;
          private PlayerStats playerStats;

          public void Execute()
          {
          playerStats.experience += experience; // Unsafe if threaded
          }

          public GainExperience(int experience, PlayerStats playerStats)
          {
          this.experience = experience;
          this.playerStats = playerStats;
          }
          }

          public class GiveQuest
          {
          private int questNr;
          private Quests quests;

          public GiveQuest(int questNr, Quests quests)
          {
          this.questNr = questNr;
          this.quests = quests;
          }

          public void Execute()
          {
          quests.Add(questNr);
          quests.ShowQuestUpdatedIcon();
          }
          }

          public class RemoveQuest
          {
          private int questNr;
          private Quests quests;

          public RemoveQuest(int questNr, Quests quests)
          {
          this.questNr = questNr;
          this.quests = quests;
          }

          public void Execute()
          {
          quests.Remove(questNr);
          quests.ShowQuestUpdatedIcon();
          }
          }

          public class IncrementQuestStatus
          {
          private int questNr;
          private Quests quests;

          public IncrementQuestStatus(int questNr, Quests quests)
          {
          this.questNr = questNr;
          this.quests = quests;
          }

          public void Execute()
          {
          quests.IncrementStatus(questNr);
          quests.ShowQuestUpdatedIcon();
          }
          }


          If you insist on your current structure for the class Event then you could redo PlayEvent like this:



              public void PlayEvent(EventManager em)
          {
          switch (effect)
          {
          case Effect.GiveExperiencePoints:
          new GainExperience(intModifiter, playerStats).Execute();
          break;
          case Effect.GiveItemToPlayer:
          new GiveEquipment(effectItemsIndexes, equipment).Execute();
          break;
          case Effect.RemoveItemFromPlayerEquipment:
          new RemoveEquipment(effectItemsIndexes, equipment).Execute();
          break;
          case Effect.GiveQuest:
          new GiveQuest(intModifiter, quests).Execute();
          break;
          case Effect.RemoveQuest:
          new RemoveQuest(intModifiter, quests).Execute();
          break;
          case Effect.IncrementActualStatusOfQuest:
          new IncrementQuestStatus(intModifiter, quests).Execute();
          break;
          case Effect.EnableOrDisableAnotherEvent:
          new AnotherEventsRelationsEvent(intModifiter, enable, em).Play();
          break;
          default:
          throw new UnknownEvent(effect);
          }
          }


          There are many many things to dig into and many things could be improved with this setup.




          1. The interface is unnecessary as you do not distribute these constructed events, so you do not need to communicate the exposed methods to anyone. If however you passed the actions to the Event type then an interface would make a lot of sense.


          2. Explicit dependency injection. You see that I have removed all your manager.getInstance methods. It is bad bad practice to use singletons in any sense. And in no case is it a necessity. (though it feels easier when you do it). Explicit dependency injection is passing the variables as arguments when you construct the types.



          Unity uses MonoBehaviours where you do not control the constructors, but you could construct a dependency system where you inject the types yourself. A bit much to go into, but you can have a think about it.





          1. Naming. Naming is hard but should be telling you something about the behaviour or content of the types inside of this. Manager, container, holder, EventConditional and the like, tells nothing. They can be managers, but don't name them as such. EquipmentContainer => Equipment, QuestManager => Quests, PlayerStatsManager => PlayerStats, etc. You get the point.


          2. Simplicity. Your events should be as simple as possible. I split your GiveQuest, RemoveQuest, IncrementQuestStatus into their own Event types, and removed your enum. This will give a good decoupling and their behaviour does not necessarily depend on each other. The code becomes a whole lot easier to read, which is the point. Simple code has fewer bugs than complex code. So keep it simple stupid (KISS from the U.S navy).


          3. Maintainability. (Then we have covered 3 out of 4 of the Code Health points). If you wanted to add a fourth version of Quest modification. In your old code you would have to modify the QuestEvent type. In this new code you never modify existing behaviours, you create a new type for the QuestEvent, therefore do not introduce new bugs into code that used to work. You decouple code to encapsulate problems to places you can easily fix.


          I have many more things that I could go into, but I will not overwhelm you more than I already have. The overall code looks good, but these are just my points. Simplifying code often ensure much better quality in the long run.






          share|improve this answer























            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "196"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f153257%2fevent-system-in-unity-rpg-game%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            6
            down vote














            public int intModifiter;          //int modifiter for every effect type that require it
            public float floatModifiter; //float modifiter for every effect type that require it



            You write in the comment modifiter for every effect type so why not give the variable such a name: effectTypeModifier?



            I nowhere see the floatModifiter being used. This could be removed.






            public bool enable;           //enable or disable another event?
            public bool isEnabled = true; //defines event activity



            enable and isEnabled are too similar. You need a better name at least for one of them besides enable sound like an action so maybe canEnableNextEvent?






            public bool positiveResult;   //defines that condition was satisfied or not.



            How about success(ful)?






            public bool finished;         //is event finished?
            public bool isPlaying; //is event playing?



            The code could use some more consistency. Make them both have the is prefix or none of them.






            public bool condExpanded;
            public int condArrLength;
            public bool effExpanded;
            public int effArrLength;
            ..



            You shouldn't use abbreviated names if they are not some common abbreviations like Html or Xml.






            public interface IEventConditionable
            {
            void Play();
            }



            This interface is named Conditionable but it contains a Play method. There is nothing about any conditions. The name IPlayable would be much better I think.






            public void PlayEvent(EventManager em)
            {
            IEventConditionable tmp = null;
            switch (effect)
            {
            case Effect.GiveExperiencePoints: tmp = new ExperienceEvent(intModifiter); break;
            case Effect.GiveItemToPlayer: tmp = new ItemEvent(effectItemsIndexes, true); break;
            case Effect.RemoveItemFromPlayerEquipment: tmp = new ItemEvent(effectItemsIndexes, false); break;
            case Effect.GiveQuest: tmp = new QuestEvent(QuestEventType.GiveQuest, intModifiter); break;
            case Effect.RemoveQuest: tmp = new QuestEvent(QuestEventType.RemoveQuest, intModifiter); break;
            case Effect.IncrementActualStatusOfQuest: tmp = new QuestEvent(QuestEventType.IncrementQuestStatus, intModifiter); break;
            case Effect.EnableOrDisableAnotherEvent: tmp = new AnotherEventsRelationsEvent(intModifiter, enable, em); break;
            default: Debug.Log("Event cannot be recognized."); break;
            }

            if (tmp != null)
            tmp.Play();
            }



            This method doesn't require the tmp variable. You don't store the result anywhere so you could simply call Play inside the switch just after you create an event:



            switch (effect)
            {
            case Effect.GiveExperiencePoints: new ExperienceEvent(intModifiter).Play(); break;
            ..
            }





            private bool lastRes;



            And again an abbrevaited name. Does Res stand for result, resolution, rest or restaurant? You won't know this in a few days/weeks anymore.






            bool playerIsColliding = Physics.OverlapBox(
            transform.position,
            transform.localScale * 0.5f,
            transform.rotation
            )
            .Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player"))
            .ToArray()
            .Length > 0;



            You can call simply Count on this.



            bool playerIsColliding = Physics.OverlapBox(
            ..
            )
            .Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player"))
            .Count() > 0;





            share|improve this answer























            • Thanks, I will correct that things. Could you tell me how do you think about quality of my code if I will correct it?
              – Michael
              Jan 22 '17 at 15:20












            • @Michael we'll do, just keep in mind this: What should I do when someone answers my question? - you can post either a self-answer or a follow-up, don't edit your question ;-)
              – t3chb0t
              Jan 22 '17 at 15:26










            • @Michael but I recommend you wait another day or two or three, you might receive more answers and more advices.
              – t3chb0t
              Jan 22 '17 at 15:27












            • Ok, I didn't changed my code and I will not do it there.
              – Michael
              Jan 22 '17 at 15:32















            up vote
            6
            down vote














            public int intModifiter;          //int modifiter for every effect type that require it
            public float floatModifiter; //float modifiter for every effect type that require it



            You write in the comment modifiter for every effect type so why not give the variable such a name: effectTypeModifier?



            I nowhere see the floatModifiter being used. This could be removed.






            public bool enable;           //enable or disable another event?
            public bool isEnabled = true; //defines event activity



            enable and isEnabled are too similar. You need a better name at least for one of them besides enable sound like an action so maybe canEnableNextEvent?






            public bool positiveResult;   //defines that condition was satisfied or not.



            How about success(ful)?






            public bool finished;         //is event finished?
            public bool isPlaying; //is event playing?



            The code could use some more consistency. Make them both have the is prefix or none of them.






            public bool condExpanded;
            public int condArrLength;
            public bool effExpanded;
            public int effArrLength;
            ..



            You shouldn't use abbreviated names if they are not some common abbreviations like Html or Xml.






            public interface IEventConditionable
            {
            void Play();
            }



            This interface is named Conditionable but it contains a Play method. There is nothing about any conditions. The name IPlayable would be much better I think.






            public void PlayEvent(EventManager em)
            {
            IEventConditionable tmp = null;
            switch (effect)
            {
            case Effect.GiveExperiencePoints: tmp = new ExperienceEvent(intModifiter); break;
            case Effect.GiveItemToPlayer: tmp = new ItemEvent(effectItemsIndexes, true); break;
            case Effect.RemoveItemFromPlayerEquipment: tmp = new ItemEvent(effectItemsIndexes, false); break;
            case Effect.GiveQuest: tmp = new QuestEvent(QuestEventType.GiveQuest, intModifiter); break;
            case Effect.RemoveQuest: tmp = new QuestEvent(QuestEventType.RemoveQuest, intModifiter); break;
            case Effect.IncrementActualStatusOfQuest: tmp = new QuestEvent(QuestEventType.IncrementQuestStatus, intModifiter); break;
            case Effect.EnableOrDisableAnotherEvent: tmp = new AnotherEventsRelationsEvent(intModifiter, enable, em); break;
            default: Debug.Log("Event cannot be recognized."); break;
            }

            if (tmp != null)
            tmp.Play();
            }



            This method doesn't require the tmp variable. You don't store the result anywhere so you could simply call Play inside the switch just after you create an event:



            switch (effect)
            {
            case Effect.GiveExperiencePoints: new ExperienceEvent(intModifiter).Play(); break;
            ..
            }





            private bool lastRes;



            And again an abbrevaited name. Does Res stand for result, resolution, rest or restaurant? You won't know this in a few days/weeks anymore.






            bool playerIsColliding = Physics.OverlapBox(
            transform.position,
            transform.localScale * 0.5f,
            transform.rotation
            )
            .Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player"))
            .ToArray()
            .Length > 0;



            You can call simply Count on this.



            bool playerIsColliding = Physics.OverlapBox(
            ..
            )
            .Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player"))
            .Count() > 0;





            share|improve this answer























            • Thanks, I will correct that things. Could you tell me how do you think about quality of my code if I will correct it?
              – Michael
              Jan 22 '17 at 15:20












            • @Michael we'll do, just keep in mind this: What should I do when someone answers my question? - you can post either a self-answer or a follow-up, don't edit your question ;-)
              – t3chb0t
              Jan 22 '17 at 15:26










            • @Michael but I recommend you wait another day or two or three, you might receive more answers and more advices.
              – t3chb0t
              Jan 22 '17 at 15:27












            • Ok, I didn't changed my code and I will not do it there.
              – Michael
              Jan 22 '17 at 15:32













            up vote
            6
            down vote










            up vote
            6
            down vote










            public int intModifiter;          //int modifiter for every effect type that require it
            public float floatModifiter; //float modifiter for every effect type that require it



            You write in the comment modifiter for every effect type so why not give the variable such a name: effectTypeModifier?



            I nowhere see the floatModifiter being used. This could be removed.






            public bool enable;           //enable or disable another event?
            public bool isEnabled = true; //defines event activity



            enable and isEnabled are too similar. You need a better name at least for one of them besides enable sound like an action so maybe canEnableNextEvent?






            public bool positiveResult;   //defines that condition was satisfied or not.



            How about success(ful)?






            public bool finished;         //is event finished?
            public bool isPlaying; //is event playing?



            The code could use some more consistency. Make them both have the is prefix or none of them.






            public bool condExpanded;
            public int condArrLength;
            public bool effExpanded;
            public int effArrLength;
            ..



            You shouldn't use abbreviated names if they are not some common abbreviations like Html or Xml.






            public interface IEventConditionable
            {
            void Play();
            }



            This interface is named Conditionable but it contains a Play method. There is nothing about any conditions. The name IPlayable would be much better I think.






            public void PlayEvent(EventManager em)
            {
            IEventConditionable tmp = null;
            switch (effect)
            {
            case Effect.GiveExperiencePoints: tmp = new ExperienceEvent(intModifiter); break;
            case Effect.GiveItemToPlayer: tmp = new ItemEvent(effectItemsIndexes, true); break;
            case Effect.RemoveItemFromPlayerEquipment: tmp = new ItemEvent(effectItemsIndexes, false); break;
            case Effect.GiveQuest: tmp = new QuestEvent(QuestEventType.GiveQuest, intModifiter); break;
            case Effect.RemoveQuest: tmp = new QuestEvent(QuestEventType.RemoveQuest, intModifiter); break;
            case Effect.IncrementActualStatusOfQuest: tmp = new QuestEvent(QuestEventType.IncrementQuestStatus, intModifiter); break;
            case Effect.EnableOrDisableAnotherEvent: tmp = new AnotherEventsRelationsEvent(intModifiter, enable, em); break;
            default: Debug.Log("Event cannot be recognized."); break;
            }

            if (tmp != null)
            tmp.Play();
            }



            This method doesn't require the tmp variable. You don't store the result anywhere so you could simply call Play inside the switch just after you create an event:



            switch (effect)
            {
            case Effect.GiveExperiencePoints: new ExperienceEvent(intModifiter).Play(); break;
            ..
            }





            private bool lastRes;



            And again an abbrevaited name. Does Res stand for result, resolution, rest or restaurant? You won't know this in a few days/weeks anymore.






            bool playerIsColliding = Physics.OverlapBox(
            transform.position,
            transform.localScale * 0.5f,
            transform.rotation
            )
            .Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player"))
            .ToArray()
            .Length > 0;



            You can call simply Count on this.



            bool playerIsColliding = Physics.OverlapBox(
            ..
            )
            .Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player"))
            .Count() > 0;





            share|improve this answer















            public int intModifiter;          //int modifiter for every effect type that require it
            public float floatModifiter; //float modifiter for every effect type that require it



            You write in the comment modifiter for every effect type so why not give the variable such a name: effectTypeModifier?



            I nowhere see the floatModifiter being used. This could be removed.






            public bool enable;           //enable or disable another event?
            public bool isEnabled = true; //defines event activity



            enable and isEnabled are too similar. You need a better name at least for one of them besides enable sound like an action so maybe canEnableNextEvent?






            public bool positiveResult;   //defines that condition was satisfied or not.



            How about success(ful)?






            public bool finished;         //is event finished?
            public bool isPlaying; //is event playing?



            The code could use some more consistency. Make them both have the is prefix or none of them.






            public bool condExpanded;
            public int condArrLength;
            public bool effExpanded;
            public int effArrLength;
            ..



            You shouldn't use abbreviated names if they are not some common abbreviations like Html or Xml.






            public interface IEventConditionable
            {
            void Play();
            }



            This interface is named Conditionable but it contains a Play method. There is nothing about any conditions. The name IPlayable would be much better I think.






            public void PlayEvent(EventManager em)
            {
            IEventConditionable tmp = null;
            switch (effect)
            {
            case Effect.GiveExperiencePoints: tmp = new ExperienceEvent(intModifiter); break;
            case Effect.GiveItemToPlayer: tmp = new ItemEvent(effectItemsIndexes, true); break;
            case Effect.RemoveItemFromPlayerEquipment: tmp = new ItemEvent(effectItemsIndexes, false); break;
            case Effect.GiveQuest: tmp = new QuestEvent(QuestEventType.GiveQuest, intModifiter); break;
            case Effect.RemoveQuest: tmp = new QuestEvent(QuestEventType.RemoveQuest, intModifiter); break;
            case Effect.IncrementActualStatusOfQuest: tmp = new QuestEvent(QuestEventType.IncrementQuestStatus, intModifiter); break;
            case Effect.EnableOrDisableAnotherEvent: tmp = new AnotherEventsRelationsEvent(intModifiter, enable, em); break;
            default: Debug.Log("Event cannot be recognized."); break;
            }

            if (tmp != null)
            tmp.Play();
            }



            This method doesn't require the tmp variable. You don't store the result anywhere so you could simply call Play inside the switch just after you create an event:



            switch (effect)
            {
            case Effect.GiveExperiencePoints: new ExperienceEvent(intModifiter).Play(); break;
            ..
            }





            private bool lastRes;



            And again an abbrevaited name. Does Res stand for result, resolution, rest or restaurant? You won't know this in a few days/weeks anymore.






            bool playerIsColliding = Physics.OverlapBox(
            transform.position,
            transform.localScale * 0.5f,
            transform.rotation
            )
            .Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player"))
            .ToArray()
            .Length > 0;



            You can call simply Count on this.



            bool playerIsColliding = Physics.OverlapBox(
            ..
            )
            .Where(item => item.gameObject.layer == LayerMask.NameToLayer("Player"))
            .Count() > 0;






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 22 '17 at 5:59

























            answered Jan 22 '17 at 5:04









            t3chb0t

            33.8k746110




            33.8k746110












            • Thanks, I will correct that things. Could you tell me how do you think about quality of my code if I will correct it?
              – Michael
              Jan 22 '17 at 15:20












            • @Michael we'll do, just keep in mind this: What should I do when someone answers my question? - you can post either a self-answer or a follow-up, don't edit your question ;-)
              – t3chb0t
              Jan 22 '17 at 15:26










            • @Michael but I recommend you wait another day or two or three, you might receive more answers and more advices.
              – t3chb0t
              Jan 22 '17 at 15:27












            • Ok, I didn't changed my code and I will not do it there.
              – Michael
              Jan 22 '17 at 15:32


















            • Thanks, I will correct that things. Could you tell me how do you think about quality of my code if I will correct it?
              – Michael
              Jan 22 '17 at 15:20












            • @Michael we'll do, just keep in mind this: What should I do when someone answers my question? - you can post either a self-answer or a follow-up, don't edit your question ;-)
              – t3chb0t
              Jan 22 '17 at 15:26










            • @Michael but I recommend you wait another day or two or three, you might receive more answers and more advices.
              – t3chb0t
              Jan 22 '17 at 15:27












            • Ok, I didn't changed my code and I will not do it there.
              – Michael
              Jan 22 '17 at 15:32
















            Thanks, I will correct that things. Could you tell me how do you think about quality of my code if I will correct it?
            – Michael
            Jan 22 '17 at 15:20






            Thanks, I will correct that things. Could you tell me how do you think about quality of my code if I will correct it?
            – Michael
            Jan 22 '17 at 15:20














            @Michael we'll do, just keep in mind this: What should I do when someone answers my question? - you can post either a self-answer or a follow-up, don't edit your question ;-)
            – t3chb0t
            Jan 22 '17 at 15:26




            @Michael we'll do, just keep in mind this: What should I do when someone answers my question? - you can post either a self-answer or a follow-up, don't edit your question ;-)
            – t3chb0t
            Jan 22 '17 at 15:26












            @Michael but I recommend you wait another day or two or three, you might receive more answers and more advices.
            – t3chb0t
            Jan 22 '17 at 15:27






            @Michael but I recommend you wait another day or two or three, you might receive more answers and more advices.
            – t3chb0t
            Jan 22 '17 at 15:27














            Ok, I didn't changed my code and I will not do it there.
            – Michael
            Jan 22 '17 at 15:32




            Ok, I didn't changed my code and I will not do it there.
            – Michael
            Jan 22 '17 at 15:32












            up vote
            3
            down vote













            Wauw, many many things to go over.



            These are my versions of your "Events"



            public class GiveEquipment
            {
            private int items;
            private Equipment equipment;

            public GiveEquipment(int items, Equipment equipment)
            {
            this.items = items;
            this.equipment = equipment;
            }

            public void Execute()
            {
            equipment.AddAll(items);
            }
            }

            public class RemoveEquipment
            {
            private int items;
            private Equipment equipment;

            public RemoveEquipment(int items, Equipment equipment)
            {
            this.items = items;
            this.equipment = equipment;
            }

            public void Execute()
            {
            equipment.RemoveAll(items);
            }
            }

            public class GainExperience
            {
            private int experience;
            private PlayerStats playerStats;

            public void Execute()
            {
            playerStats.experience += experience; // Unsafe if threaded
            }

            public GainExperience(int experience, PlayerStats playerStats)
            {
            this.experience = experience;
            this.playerStats = playerStats;
            }
            }

            public class GiveQuest
            {
            private int questNr;
            private Quests quests;

            public GiveQuest(int questNr, Quests quests)
            {
            this.questNr = questNr;
            this.quests = quests;
            }

            public void Execute()
            {
            quests.Add(questNr);
            quests.ShowQuestUpdatedIcon();
            }
            }

            public class RemoveQuest
            {
            private int questNr;
            private Quests quests;

            public RemoveQuest(int questNr, Quests quests)
            {
            this.questNr = questNr;
            this.quests = quests;
            }

            public void Execute()
            {
            quests.Remove(questNr);
            quests.ShowQuestUpdatedIcon();
            }
            }

            public class IncrementQuestStatus
            {
            private int questNr;
            private Quests quests;

            public IncrementQuestStatus(int questNr, Quests quests)
            {
            this.questNr = questNr;
            this.quests = quests;
            }

            public void Execute()
            {
            quests.IncrementStatus(questNr);
            quests.ShowQuestUpdatedIcon();
            }
            }


            If you insist on your current structure for the class Event then you could redo PlayEvent like this:



                public void PlayEvent(EventManager em)
            {
            switch (effect)
            {
            case Effect.GiveExperiencePoints:
            new GainExperience(intModifiter, playerStats).Execute();
            break;
            case Effect.GiveItemToPlayer:
            new GiveEquipment(effectItemsIndexes, equipment).Execute();
            break;
            case Effect.RemoveItemFromPlayerEquipment:
            new RemoveEquipment(effectItemsIndexes, equipment).Execute();
            break;
            case Effect.GiveQuest:
            new GiveQuest(intModifiter, quests).Execute();
            break;
            case Effect.RemoveQuest:
            new RemoveQuest(intModifiter, quests).Execute();
            break;
            case Effect.IncrementActualStatusOfQuest:
            new IncrementQuestStatus(intModifiter, quests).Execute();
            break;
            case Effect.EnableOrDisableAnotherEvent:
            new AnotherEventsRelationsEvent(intModifiter, enable, em).Play();
            break;
            default:
            throw new UnknownEvent(effect);
            }
            }


            There are many many things to dig into and many things could be improved with this setup.




            1. The interface is unnecessary as you do not distribute these constructed events, so you do not need to communicate the exposed methods to anyone. If however you passed the actions to the Event type then an interface would make a lot of sense.


            2. Explicit dependency injection. You see that I have removed all your manager.getInstance methods. It is bad bad practice to use singletons in any sense. And in no case is it a necessity. (though it feels easier when you do it). Explicit dependency injection is passing the variables as arguments when you construct the types.



            Unity uses MonoBehaviours where you do not control the constructors, but you could construct a dependency system where you inject the types yourself. A bit much to go into, but you can have a think about it.





            1. Naming. Naming is hard but should be telling you something about the behaviour or content of the types inside of this. Manager, container, holder, EventConditional and the like, tells nothing. They can be managers, but don't name them as such. EquipmentContainer => Equipment, QuestManager => Quests, PlayerStatsManager => PlayerStats, etc. You get the point.


            2. Simplicity. Your events should be as simple as possible. I split your GiveQuest, RemoveQuest, IncrementQuestStatus into their own Event types, and removed your enum. This will give a good decoupling and their behaviour does not necessarily depend on each other. The code becomes a whole lot easier to read, which is the point. Simple code has fewer bugs than complex code. So keep it simple stupid (KISS from the U.S navy).


            3. Maintainability. (Then we have covered 3 out of 4 of the Code Health points). If you wanted to add a fourth version of Quest modification. In your old code you would have to modify the QuestEvent type. In this new code you never modify existing behaviours, you create a new type for the QuestEvent, therefore do not introduce new bugs into code that used to work. You decouple code to encapsulate problems to places you can easily fix.


            I have many more things that I could go into, but I will not overwhelm you more than I already have. The overall code looks good, but these are just my points. Simplifying code often ensure much better quality in the long run.






            share|improve this answer



























              up vote
              3
              down vote













              Wauw, many many things to go over.



              These are my versions of your "Events"



              public class GiveEquipment
              {
              private int items;
              private Equipment equipment;

              public GiveEquipment(int items, Equipment equipment)
              {
              this.items = items;
              this.equipment = equipment;
              }

              public void Execute()
              {
              equipment.AddAll(items);
              }
              }

              public class RemoveEquipment
              {
              private int items;
              private Equipment equipment;

              public RemoveEquipment(int items, Equipment equipment)
              {
              this.items = items;
              this.equipment = equipment;
              }

              public void Execute()
              {
              equipment.RemoveAll(items);
              }
              }

              public class GainExperience
              {
              private int experience;
              private PlayerStats playerStats;

              public void Execute()
              {
              playerStats.experience += experience; // Unsafe if threaded
              }

              public GainExperience(int experience, PlayerStats playerStats)
              {
              this.experience = experience;
              this.playerStats = playerStats;
              }
              }

              public class GiveQuest
              {
              private int questNr;
              private Quests quests;

              public GiveQuest(int questNr, Quests quests)
              {
              this.questNr = questNr;
              this.quests = quests;
              }

              public void Execute()
              {
              quests.Add(questNr);
              quests.ShowQuestUpdatedIcon();
              }
              }

              public class RemoveQuest
              {
              private int questNr;
              private Quests quests;

              public RemoveQuest(int questNr, Quests quests)
              {
              this.questNr = questNr;
              this.quests = quests;
              }

              public void Execute()
              {
              quests.Remove(questNr);
              quests.ShowQuestUpdatedIcon();
              }
              }

              public class IncrementQuestStatus
              {
              private int questNr;
              private Quests quests;

              public IncrementQuestStatus(int questNr, Quests quests)
              {
              this.questNr = questNr;
              this.quests = quests;
              }

              public void Execute()
              {
              quests.IncrementStatus(questNr);
              quests.ShowQuestUpdatedIcon();
              }
              }


              If you insist on your current structure for the class Event then you could redo PlayEvent like this:



                  public void PlayEvent(EventManager em)
              {
              switch (effect)
              {
              case Effect.GiveExperiencePoints:
              new GainExperience(intModifiter, playerStats).Execute();
              break;
              case Effect.GiveItemToPlayer:
              new GiveEquipment(effectItemsIndexes, equipment).Execute();
              break;
              case Effect.RemoveItemFromPlayerEquipment:
              new RemoveEquipment(effectItemsIndexes, equipment).Execute();
              break;
              case Effect.GiveQuest:
              new GiveQuest(intModifiter, quests).Execute();
              break;
              case Effect.RemoveQuest:
              new RemoveQuest(intModifiter, quests).Execute();
              break;
              case Effect.IncrementActualStatusOfQuest:
              new IncrementQuestStatus(intModifiter, quests).Execute();
              break;
              case Effect.EnableOrDisableAnotherEvent:
              new AnotherEventsRelationsEvent(intModifiter, enable, em).Play();
              break;
              default:
              throw new UnknownEvent(effect);
              }
              }


              There are many many things to dig into and many things could be improved with this setup.




              1. The interface is unnecessary as you do not distribute these constructed events, so you do not need to communicate the exposed methods to anyone. If however you passed the actions to the Event type then an interface would make a lot of sense.


              2. Explicit dependency injection. You see that I have removed all your manager.getInstance methods. It is bad bad practice to use singletons in any sense. And in no case is it a necessity. (though it feels easier when you do it). Explicit dependency injection is passing the variables as arguments when you construct the types.



              Unity uses MonoBehaviours where you do not control the constructors, but you could construct a dependency system where you inject the types yourself. A bit much to go into, but you can have a think about it.





              1. Naming. Naming is hard but should be telling you something about the behaviour or content of the types inside of this. Manager, container, holder, EventConditional and the like, tells nothing. They can be managers, but don't name them as such. EquipmentContainer => Equipment, QuestManager => Quests, PlayerStatsManager => PlayerStats, etc. You get the point.


              2. Simplicity. Your events should be as simple as possible. I split your GiveQuest, RemoveQuest, IncrementQuestStatus into their own Event types, and removed your enum. This will give a good decoupling and their behaviour does not necessarily depend on each other. The code becomes a whole lot easier to read, which is the point. Simple code has fewer bugs than complex code. So keep it simple stupid (KISS from the U.S navy).


              3. Maintainability. (Then we have covered 3 out of 4 of the Code Health points). If you wanted to add a fourth version of Quest modification. In your old code you would have to modify the QuestEvent type. In this new code you never modify existing behaviours, you create a new type for the QuestEvent, therefore do not introduce new bugs into code that used to work. You decouple code to encapsulate problems to places you can easily fix.


              I have many more things that I could go into, but I will not overwhelm you more than I already have. The overall code looks good, but these are just my points. Simplifying code often ensure much better quality in the long run.






              share|improve this answer

























                up vote
                3
                down vote










                up vote
                3
                down vote









                Wauw, many many things to go over.



                These are my versions of your "Events"



                public class GiveEquipment
                {
                private int items;
                private Equipment equipment;

                public GiveEquipment(int items, Equipment equipment)
                {
                this.items = items;
                this.equipment = equipment;
                }

                public void Execute()
                {
                equipment.AddAll(items);
                }
                }

                public class RemoveEquipment
                {
                private int items;
                private Equipment equipment;

                public RemoveEquipment(int items, Equipment equipment)
                {
                this.items = items;
                this.equipment = equipment;
                }

                public void Execute()
                {
                equipment.RemoveAll(items);
                }
                }

                public class GainExperience
                {
                private int experience;
                private PlayerStats playerStats;

                public void Execute()
                {
                playerStats.experience += experience; // Unsafe if threaded
                }

                public GainExperience(int experience, PlayerStats playerStats)
                {
                this.experience = experience;
                this.playerStats = playerStats;
                }
                }

                public class GiveQuest
                {
                private int questNr;
                private Quests quests;

                public GiveQuest(int questNr, Quests quests)
                {
                this.questNr = questNr;
                this.quests = quests;
                }

                public void Execute()
                {
                quests.Add(questNr);
                quests.ShowQuestUpdatedIcon();
                }
                }

                public class RemoveQuest
                {
                private int questNr;
                private Quests quests;

                public RemoveQuest(int questNr, Quests quests)
                {
                this.questNr = questNr;
                this.quests = quests;
                }

                public void Execute()
                {
                quests.Remove(questNr);
                quests.ShowQuestUpdatedIcon();
                }
                }

                public class IncrementQuestStatus
                {
                private int questNr;
                private Quests quests;

                public IncrementQuestStatus(int questNr, Quests quests)
                {
                this.questNr = questNr;
                this.quests = quests;
                }

                public void Execute()
                {
                quests.IncrementStatus(questNr);
                quests.ShowQuestUpdatedIcon();
                }
                }


                If you insist on your current structure for the class Event then you could redo PlayEvent like this:



                    public void PlayEvent(EventManager em)
                {
                switch (effect)
                {
                case Effect.GiveExperiencePoints:
                new GainExperience(intModifiter, playerStats).Execute();
                break;
                case Effect.GiveItemToPlayer:
                new GiveEquipment(effectItemsIndexes, equipment).Execute();
                break;
                case Effect.RemoveItemFromPlayerEquipment:
                new RemoveEquipment(effectItemsIndexes, equipment).Execute();
                break;
                case Effect.GiveQuest:
                new GiveQuest(intModifiter, quests).Execute();
                break;
                case Effect.RemoveQuest:
                new RemoveQuest(intModifiter, quests).Execute();
                break;
                case Effect.IncrementActualStatusOfQuest:
                new IncrementQuestStatus(intModifiter, quests).Execute();
                break;
                case Effect.EnableOrDisableAnotherEvent:
                new AnotherEventsRelationsEvent(intModifiter, enable, em).Play();
                break;
                default:
                throw new UnknownEvent(effect);
                }
                }


                There are many many things to dig into and many things could be improved with this setup.




                1. The interface is unnecessary as you do not distribute these constructed events, so you do not need to communicate the exposed methods to anyone. If however you passed the actions to the Event type then an interface would make a lot of sense.


                2. Explicit dependency injection. You see that I have removed all your manager.getInstance methods. It is bad bad practice to use singletons in any sense. And in no case is it a necessity. (though it feels easier when you do it). Explicit dependency injection is passing the variables as arguments when you construct the types.



                Unity uses MonoBehaviours where you do not control the constructors, but you could construct a dependency system where you inject the types yourself. A bit much to go into, but you can have a think about it.





                1. Naming. Naming is hard but should be telling you something about the behaviour or content of the types inside of this. Manager, container, holder, EventConditional and the like, tells nothing. They can be managers, but don't name them as such. EquipmentContainer => Equipment, QuestManager => Quests, PlayerStatsManager => PlayerStats, etc. You get the point.


                2. Simplicity. Your events should be as simple as possible. I split your GiveQuest, RemoveQuest, IncrementQuestStatus into their own Event types, and removed your enum. This will give a good decoupling and their behaviour does not necessarily depend on each other. The code becomes a whole lot easier to read, which is the point. Simple code has fewer bugs than complex code. So keep it simple stupid (KISS from the U.S navy).


                3. Maintainability. (Then we have covered 3 out of 4 of the Code Health points). If you wanted to add a fourth version of Quest modification. In your old code you would have to modify the QuestEvent type. In this new code you never modify existing behaviours, you create a new type for the QuestEvent, therefore do not introduce new bugs into code that used to work. You decouple code to encapsulate problems to places you can easily fix.


                I have many more things that I could go into, but I will not overwhelm you more than I already have. The overall code looks good, but these are just my points. Simplifying code often ensure much better quality in the long run.






                share|improve this answer














                Wauw, many many things to go over.



                These are my versions of your "Events"



                public class GiveEquipment
                {
                private int items;
                private Equipment equipment;

                public GiveEquipment(int items, Equipment equipment)
                {
                this.items = items;
                this.equipment = equipment;
                }

                public void Execute()
                {
                equipment.AddAll(items);
                }
                }

                public class RemoveEquipment
                {
                private int items;
                private Equipment equipment;

                public RemoveEquipment(int items, Equipment equipment)
                {
                this.items = items;
                this.equipment = equipment;
                }

                public void Execute()
                {
                equipment.RemoveAll(items);
                }
                }

                public class GainExperience
                {
                private int experience;
                private PlayerStats playerStats;

                public void Execute()
                {
                playerStats.experience += experience; // Unsafe if threaded
                }

                public GainExperience(int experience, PlayerStats playerStats)
                {
                this.experience = experience;
                this.playerStats = playerStats;
                }
                }

                public class GiveQuest
                {
                private int questNr;
                private Quests quests;

                public GiveQuest(int questNr, Quests quests)
                {
                this.questNr = questNr;
                this.quests = quests;
                }

                public void Execute()
                {
                quests.Add(questNr);
                quests.ShowQuestUpdatedIcon();
                }
                }

                public class RemoveQuest
                {
                private int questNr;
                private Quests quests;

                public RemoveQuest(int questNr, Quests quests)
                {
                this.questNr = questNr;
                this.quests = quests;
                }

                public void Execute()
                {
                quests.Remove(questNr);
                quests.ShowQuestUpdatedIcon();
                }
                }

                public class IncrementQuestStatus
                {
                private int questNr;
                private Quests quests;

                public IncrementQuestStatus(int questNr, Quests quests)
                {
                this.questNr = questNr;
                this.quests = quests;
                }

                public void Execute()
                {
                quests.IncrementStatus(questNr);
                quests.ShowQuestUpdatedIcon();
                }
                }


                If you insist on your current structure for the class Event then you could redo PlayEvent like this:



                    public void PlayEvent(EventManager em)
                {
                switch (effect)
                {
                case Effect.GiveExperiencePoints:
                new GainExperience(intModifiter, playerStats).Execute();
                break;
                case Effect.GiveItemToPlayer:
                new GiveEquipment(effectItemsIndexes, equipment).Execute();
                break;
                case Effect.RemoveItemFromPlayerEquipment:
                new RemoveEquipment(effectItemsIndexes, equipment).Execute();
                break;
                case Effect.GiveQuest:
                new GiveQuest(intModifiter, quests).Execute();
                break;
                case Effect.RemoveQuest:
                new RemoveQuest(intModifiter, quests).Execute();
                break;
                case Effect.IncrementActualStatusOfQuest:
                new IncrementQuestStatus(intModifiter, quests).Execute();
                break;
                case Effect.EnableOrDisableAnotherEvent:
                new AnotherEventsRelationsEvent(intModifiter, enable, em).Play();
                break;
                default:
                throw new UnknownEvent(effect);
                }
                }


                There are many many things to dig into and many things could be improved with this setup.




                1. The interface is unnecessary as you do not distribute these constructed events, so you do not need to communicate the exposed methods to anyone. If however you passed the actions to the Event type then an interface would make a lot of sense.


                2. Explicit dependency injection. You see that I have removed all your manager.getInstance methods. It is bad bad practice to use singletons in any sense. And in no case is it a necessity. (though it feels easier when you do it). Explicit dependency injection is passing the variables as arguments when you construct the types.



                Unity uses MonoBehaviours where you do not control the constructors, but you could construct a dependency system where you inject the types yourself. A bit much to go into, but you can have a think about it.





                1. Naming. Naming is hard but should be telling you something about the behaviour or content of the types inside of this. Manager, container, holder, EventConditional and the like, tells nothing. They can be managers, but don't name them as such. EquipmentContainer => Equipment, QuestManager => Quests, PlayerStatsManager => PlayerStats, etc. You get the point.


                2. Simplicity. Your events should be as simple as possible. I split your GiveQuest, RemoveQuest, IncrementQuestStatus into their own Event types, and removed your enum. This will give a good decoupling and their behaviour does not necessarily depend on each other. The code becomes a whole lot easier to read, which is the point. Simple code has fewer bugs than complex code. So keep it simple stupid (KISS from the U.S navy).


                3. Maintainability. (Then we have covered 3 out of 4 of the Code Health points). If you wanted to add a fourth version of Quest modification. In your old code you would have to modify the QuestEvent type. In this new code you never modify existing behaviours, you create a new type for the QuestEvent, therefore do not introduce new bugs into code that used to work. You decouple code to encapsulate problems to places you can easily fix.


                I have many more things that I could go into, but I will not overwhelm you more than I already have. The overall code looks good, but these are just my points. Simplifying code often ensure much better quality in the long run.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Dec 4 at 23:54









                Sᴀᴍ Onᴇᴌᴀ

                8,12861751




                8,12861751










                answered Dec 4 at 22:32









                miniwolf

                312




                312






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    Use MathJax to format equations. MathJax reference.


                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f153257%2fevent-system-in-unity-rpg-game%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Список кардиналов, возведённых папой римским Каликстом III

                    Deduzione

                    Mysql.sock missing - “Can't connect to local MySQL server through socket”