Interchangable scripts without resorting to SendMessage

Hi,

I’m trying to create a weapons interface script that has one function, FireWeapon, that can then be accessed by a separate AI script.

The purpose of the weapons interface is so that I can attach a variety of different weapon scripts to my characters but always use FireWeapon to actually trigger the weapon script…

The reason for me doing this is that I am trying to avoid using SendMessage, as I here it is quite slow and I may have lots of characters (instead I will use GetComponent to give my AI script access to the weapons interface script).

But… I’ve run into a bit of a brick wall. The only way I can see to make the weapon interface work with a variety of weapon scripts is to include them ALL in the weapons interface, then check to see which ones are actually attached (is it null?)

Sorry for not explaining it very well! Here is my script. I am SURE there is a better way of doing this…

using UnityEngine;
using System.Collections;

public class WeaponInterface : MonoBehaviour 
{
	// this is really just to avoid using SendMessage which might go slow if using machine guns etc
	
	MissileLauncher missileLauncher;
	MachineGun machineGun;
	Laser laser;

	
	void Start()
	{
		missileLauncher = GetComponentInChildren<MissileLauncher>();
		machineGun = GetComponentInChildren<MachineGun>();
		laser = GetComponentInChildren<Laser>();
	}
	
	public void FireWeapon ( Transform t )
	{
		if ( missileLauncher != null ) missileLauncher.FireWeapon ( t );
		if ( machineGun != null ) machineGun.FireWeapon ( t );
		if ( laser != null ) laser.FireWeapon ( t );
	}
	
	
}

As for the main problem, it sounds like this is a good place to read up a bit on interfaces, as this allows you to define a common set of functionality that can be used without regard to the actual type of object.

I’d like to offer a few thoughts on that… While certainly well-intentioned, you have to be careful of this kind of assumption (you ‘heard somewhere’). While reflection and dynamic invocation are definitely a great deal slower than using interfaces and delegates, performance is typically quite good. The only way to know if something is ‘too slow’ is to directly measure the performance. Always remember that the #1 rule of performance optimization is measure measure measure (to quote Rico Mariani).

It often turns out that the perception of something being ‘slow’ doesn’t match the reality. In either case, you may just want to get your code working in the most productive way before addressing speed concerns which it is quite possible you’d never actually notice.

Having said that, the situation you are describing above definitely sounds like a job for interfaces for more than just performance reasons, and that would be my recommendation.

This sounds like a job for Polymorphism and inheritance.

Try something like this

public class WeaponBase : MonoBehaviour
{
 public virtual void FireWeapon( Transform t)
 {
  //Does not need to be used
 }
}

Then create weapons like this.

public class NewWeapon : WeaponBase
{
 public override void FireWeapon( Transform t)
 {
  //The firing mechanics for this weapon
 }
}

Then you can use:

Weapon[] myWeapons = GetComponentsInChildren<Weapon>();

for(int i = 0; i < myWeapons.Length; i++)
{
 myWeapons[i].FireWeapon(transform);
}

And each new type of weapon you create and add will fire using it’s own fire method. Polymorphism is the concept that you can call a base class pointer or reference and have the object use it’s own inheritted method.

You can use GetComponent(if each character only has one weapon ever), or Transform.Find(and name your weapons) to get the weapon itself, as the new issue that will arise, which should be an easier issue, is to get the correct Weapon should the player have multiple weapon scripts at once.

Edit: as the above posted making the base weapon an Interface would also be a good idea.

Yay! Thankyou…

I read all about interfaces and although they sound useful I also read here that they have a couple of limitations that would prevent me designing my system the way I wanted it, namely that you can’t use GetComponent<>()with interfaces (I did not test this however).

Instead, I went with Ntero’s suggestion of using a WeaponBase class, which works just fine.

Out of interest, how could I have implemented the interface route?

I’m very glad to hear that you got it working. I was not aware that Unity’s Inspector could not handle interfaces (where I use them most isn’t affected by that, so I never ran into that problem), and I guess I didn’t fully realize that you wanted to be able to use GetComponent<>() on the components directly, so it sounds like you chose the best solution.

.

you CAN do getcomponent on an interface, and it is very useful. if the generic version doesnt work for some reason use the normal way:

go.GetComponent (typeof(IInterface)) as IInterface;

To use an interface on this weapon example would be almost the same, except that you could not put any code into your base functions. In simplest terms an interface is just a list of functions your child classes must implement.

The main advantage of interfaces is that you can use more than one. so you could have something like:

public class Knife : Monobehaviour, ICollectableItem, IWeapon