A couple of questions about the application architecture

Hello!

I wtote simple classes with UI, User Inputs and Model ( it’s only for example)

public class Player : MonoBehaviour
{
    private Item item;

    private void Update()
    {
        HandleInput();
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.CompareTag("Item"))
        {
            PickItem(other);
        }
    }

    private void PickItem(Collider2D other)
    {
        other.gameObject.SetActive(false);
        item =  gameObject.AddComponent<Item>();
        item.SetOwner(gameObject);
        UIController.Instance.SetStatus("Item Picked");
    }


    private void HandleInput()
    {
         // Handle User Input 
    }


public class Item : MonoBehaviour
{
    private GameObject owner;
    
    private void Update()
    {
        if (owner != null )
            if (Input.GetKeyDown(KeyCode.E))
                ApplyEffect();
    }

    private void ApplyEffect()
    {
        UIController.Instance.SetStatus("Item Activated");
    }
    
    public void SetOwner(GameObject owner)
    {
        this.owner = owner;
    }
}

public class UIController : MonoBehaviour
{
    [SerializeField] private Text statusText;
        
    public void SetStatus(String status)
    {
        statusText.text = status;
    }
}

}

I’m trying to find patterns for my code and i rewrited this to solve followinf problem:

  1. User input handling is implemented in different classes
  2. Model depends on controller - t’s convenient to use a singleton controller, but I’m not sure if this is architecturally correct.
public class InputHandler : MonoBehaviour
{
    [SerializeField]
    private Player actor;
    private KeyCode activateItemKey = KeyCode.E;       
    // Update is called once per frame
    void Update()
    {
        HandleInput();
    }

    private void HandleInput()
    {
        // Handle Another User Input
        if (Input.GetKeyDown(activateItemKey ))
            actor.ActivateItem();
    }
}

public class UIController : MonoBehaviour
{
    [SerializeField] private Player actor;
    [SerializeField] private Text statusText;
    
    private void OnEnable()
    {
        actor.OnItemStatusChanged += OnItemStatusChanged;
    }

    private void OnItemStatusChanged(string status)
    {
        statusText.text = status;
    }

    private void OnDisable()
    {
        actor.OnItemStatusChanged -= OnItemStatusChanged;
    }
}


public class Player : MonoBehaviour
{
    private Item item;
    public event Action<string> OnItemStatusChanged;

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.CompareTag("Item"))
        {
            PickItem(other);
        }
    }

    private void PickItem(Collider2D other)
    {
        other.gameObject.SetActive(false);
        item =  gameObject.AddComponent<Item>();
        item.SetOwner(gameObject);
        OnItemStatusChanged?.Invoke("Item Picked");
    }

    public void ActivateItem()
    {
        if (item != null)
        {
            OnItemStatusChanged?.Invoke("Item Activated");
            item.ApplyEffect();
        }
    }

}

public class Item : MonoBehaviour
{
    private GameObject owner;
    
    public void ApplyEffect()
    {
      
    }
    
    public void SetOwner(GameObject owner)
    {
        this.owner = owner;
    }
}

My solution seems more complicated than it was written earlier.
I would like to ask, how would you write such code?

Creating an input manager which your other classes can call, or which can send messages/events to other classes, is often sensible.

You may be interested in the new Input system (available as a Package), which is actually just basically that exact thing.

1 Like

Thank you for new Input System - That’s what I was looking for.

Can you share your opinion on the interaction between the model and the UI controller ( and also with classes like StatisticManager, AchievementManager etc)?

Should they be global singletons (game classes call them directly) or should they receive change events?