In my project there is a robot. It has two important components:

  • An AI that chooses an enemy object and moves towards it.
  • A weapon that automatically shoots at the chosen enemy object.

These two components are independent and only need one piece of communication. After the movement AI has chosen a target it needs to inform the weapon system of its decision. Unfortunately I can’t just call GetComponent() since there are difference weapon systems. I need an abstraction layer. Its the typical case for an interface that contains jsut that one method setTarget. I’ve added the interface to my project and implemented it in my weapon script. Now I thought it would be possible to access it with GetComponent(). But a component must be a MonoBehaviour, so my interface doesn’t work.

How do I abstract over the different weapon systems? I want to have one movement AI work with all possible weapons.

Key point is: ITest test = (ITest)GetComponent(typeof(ITest));

public class Test:MonoBehaviour
{
    void Start()
    {
        ITest test = (ITest)GetComponent(typeof(ITest));
        if (test != null)
            test.Test();
    }
}

//Car.cs
public class Car : MonoBehaviour, ITest
{
    public void Test()
    {
        Debug.Log("car");
    }
}

//Robot.cs
public class Robot : MonoBehaviour, ITest
{
    public void Test()
    {
        Debug.Log("robot");
    }
}

//ITest.cs
public interface ITest
{
    void Test();
}

P.S. In Unity 3.x interface must be in separate file.

you have said the key word yourself, “abstract”

`

abstract public class AbsClass : InheritedObject
{

 //functions here
 abstract returntype FunctionName();

}

public class Class : AbsClass
{

 override returntype FunctionName()
 {
      //do stuff
 }

}

`

In your component script, add a reference to the weapon system interface…

public IWeaponSystem WeaponSystem;

Call GetComponent to get the script component, then use the WeaponSystem property to access the weapon system.

Interface for your robot to the weapon system and some proxy function to shoot.

public interface IRobot {
  IWeaponSystem WeaponSystem { get; set; }
  void ShootTarget();
}

Interface for your weapon system and some undefined way to settarget and shoot.

public interface IWeaponSystem {
  void SetTarget();
  void Shoot();
}

Base class for the Robot that extends MonoBehaviour, and uses the IRobot interface.

public class Robot : MonoBehaviour, IRobot {
  private IWeaponSystem weaponSystem;
  /// <summary>
  /// Can be set to some initial weapon system in UI
  /// or set programmatically from code.
  /// </summary>
  public IWeaponSystem WeaponSystem {
    // assumes some sort of IWeaponSystem is attached
    get { return weaponSystem; }
    set { weaponSystem = value; }
  }
  void Update() {
    WeaponSystem.SetTarget(); // if there is one
    ShootTarget(); // same as above, but the weapon system still handles it
  }
  public void ShootTarget() {
    WeaponSystem.Shoot();
  }
}

Base astract class for WeaponSystem. Can’t be instantiated i.e. abstract, extend this for all weapon systems.

public abstract class WeaponSystem : MonoBehaviour, IWeaponSystem {
  void IWeaponSystem.SetTarget() {
    /*do set target ai logic at this level*/
  }
  void IWeaponSystem.Shoot() { /*do nothing abstract base*/ }
}

Subclass for some turret weapon system.

public class TurretWeaponSystem : WeaponSystem {
  // re-define shoot here
  public void Shoot() {
    // do TurretWeaponSystem specific Shoot() behavior
  }
}

Most of your logic will take place elsewhere, but here is a rough example of the indirect interactions.

void exampleUsage() {
  Robot myRobot = new Robot();
  WeaponSystem genericWeaponSystem = new TurretWeaponSystem();
  // noting that myRobot.WeaponSystem is of IWeaponSystem type
  myRobot.WeaponSystem = genericWeaponSystem;
  myRobot.ShootTarget();
}

This isn’t exactly how I would do it, but based on what I read, I tried to keep the interfaces in there. With interfaces, if performance is a concern, you’ll want to avoid boxing and unboxing of the real types the interfaces point to as often as possible. Once it gets pass and set to to a variable, it should be fine, but constant marshaling will amount to some level of performance hit across the whole system if you use the pattern a lot.