Search Unity

Designing to Interfaces

Discussion in 'Scripting' started by gapMindful, Dec 10, 2013.

  1. gapMindful

    gapMindful

    Joined:
    Jun 26, 2013
    Posts:
    17
    Hey, I'm new to unity, having just jumped on with the 2D update. Also, my commercial programming experience is admittedly much more Java oriented than C#. That said, I'm coming up against a bit of a design question right off the bat.

    Using MonoBehaviour's "GetComponent" to access another MonoBehaviour Component on the current/child gameObject seems like a useful design approach. It's allowed me to offload a lot of factory / configuration work onto the inspector. However, given that Component is a class (vs an interface) and GetComponent requires referencing the component child class through its generic, this approach quickly introduces a lot of tight coupling between those classes.

    Code (csharp):
    1.  
    2.     public interface PlayerCharacter {
    3.         void DoPlayerStuff();        
    4.     }
    5.  
    6.     public interface RobotCharacter {
    7.        
    8.     }
    9.  
    10.     public class PlayerCharacterImpl : MonoBehaviour, PlayerCharacter
    11.     {
    12.         public void DoStuff() { }
    13.     }
    14.  
    15.     public class RobotCharacterImpl: MonoBehaviour, RobotCharacter
    16.     {
    17.         void Start()
    18.         {
    19.             PlayerCharacter player = GetComponent<PlayerCharacterImpl>(); //this class now tightly bound to PlayerCharacterImpl
    20.             //PlayerCharacter player = GetComponent<PlayerCharacter>(); //Impossible, PlayerCharacter not of type Component
    21.             player.DoPlayerStuff();
    22.         }  
    23.  
    24.  
    25.     }
    26.  
    27.  
    28.  

    I'd love an API similar to GetComponent, but which allowed an unbounded generic that was assignable from an interface and not only assignable from component. Looser coupling would be allowed and given that Component exposes the world, interfaces would introduce some encapsulation between the two scripts.

    I'm cooking up my own quick solution but I figured someone must have come up against this before and has a design solution out there. Alternatively, am I just way over-engineering this or using the functionality inappropriately?
     
  2. Patico

    Patico

    Joined:
    May 21, 2013
    Posts:
    886
    Here is a solution, but, as I think, this could be wrong way for game development

    Code (csharp):
    1.  
    2. public class RobotCharacterImpl : MonoBehaviour, RobotCharacter
    3. {
    4.     void Start()
    5.     {
    6.         PlayerCharacter player = (PlayerCharacter)GetComponent(typeof(PlayerCharacter)); // this works
    7.         //PlayerCharacter player = GetComponent<PlayerCharacterImpl>(); //this class now tightly bound to PlayerCharacterImpl
    8.         //PlayerCharacter player = GetComponent<PlayerCharacter>(); //Impossible, PlayerCharacter not of type Component
    9.         player.DoPlayerStuff();
    10.     }
    11. }
    12.  
    UPD:
    This way could bring you to hierarchical object oriented structure of classes that works well in the typical business oriented software, enterprise software development and small games. But in most games this approach won't work well because of not enought flexibility (yes, I know it sounds a little bit strange, maybe vertical-flexibility is more suitable term here, see fragile base class problem).

    Unity Engine offers to use component-based architecture which allow to avoid this dependencies on based classes or interfaces, I recommend to read the acticle of Ray Wenderlich - Introduction to Component Based Architecture in Games (http://www.raywenderlich.com/24878/), there are described this problem and supposed 3 ways to implement such architecture (2nd is very similar as Unity supposed).
     
    Last edited: Dec 10, 2013
  3. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
  4. gapMindful

    gapMindful

    Joined:
    Jun 26, 2013
    Posts:
    17
    Thanks for the link! Reading through it now.