Home > Software engineering >  Is it possible to set a method of a class from another script in Unity C#?
Is it possible to set a method of a class from another script in Unity C#?

Time:12-14

I'm working on a weapon system that for my fps game. The player class contains it's own methods that might need to change when a weapon is used. The problem is I want to define the methods that will be replaced with player class' methods on the weapon class.

For example I have a shooting coroutine which uses private members of Player class, I want to change the corouitine using delegates but a coroutine defined in the Weapon class won't be able to access those members.

I know that I can define the coroutine that will come with given Weapon at the Player class and change it according to the attached item, but for clarity of the code, I want to define the shooting corouitines on the Weapon classes. Is there any approach to overcome this issue? Thanks in advance.

CodePudding user response:

If I understand you correctly, something like this should work?

public interface IWeapon 
{
   void Shoot();
}

// -------------------------------------

public class WaterGun : IWeapon 
{
  void Shoot() 
  {
     // Shoot water?
  }
}

// -------------------------------------

public class LaserPistol : IWeapon 
{
  void Shoot() 
  {
     // Shoot laser?
  }
}

// -------------------------------------

public class Player {

  IWeapon weapon; 

  void Start() 
  {
      this.weapon = new WaterGun();
      // later
      this.weapon = new LaserPistol();
  }

  IEnumerator Shoot() 
  {
     // player shoot logic here then weapon-specific logic ->

     this.weapon.Shoot();
  }
}

But if you simply want to keep a function in a variable, there are ways to do that too, for example:

Action shootFunction;
var waterGun = new WaterGun();
shootFunction = waterGun.Shoot; // assigning a reference to the function without executing the method

shootFunction(); // calls waterGun's Shoot() method

I think you need to detail what you have & what you want to achieve in order to get a good answer here.

CodePudding user response:

It looks like your question boils down to:

I want to define the shooting corouitines(sic) on the Weapon classes

Yeah, we can do that. Let's start by looking at the bits we'd need. In this scenario, it makes sense that we use an interface:

public interface IWeapon
{
    bool weaponFiring {get;}
    IEnumerator StartWeaponFire ( Player player );
}

Let's look at a sample weapon:

public class WaterPistol : IWeapon
{
    public bool weaponFiring { get; private set; }

    public IEnumerator StartWeaponFire ( Player player )
    {
        weaponFiring = true;

        Debug.Log ( "Squirt!" );

        // Do your weapon logic/animation/cooldown here ..
        yield return new WaitForSeconds ( 0.5f );

        // We can acccess the 'player' data because we've sent a reference as an argument.
        player.currentHealth -= 1;

        Debug.Log ( "..." );

        weaponFiring = false;
    }
}

Now, to run the StartWeaponFire is just as easy as if the coroutine were actually on the player, but it's on the IWeapon instead.

public class Player : MonoBehaviour
{
    // An example of data on this player class.
    public float currentHealth { get; set; }
    
    // A reference to the current weapon. Has the coroutine we want to start.
    public IWeapon currentWeapon { get; set; }

    // This can be used to manually stop a coroutine if needed.
    private Coroutine _weaponCoroutine;

    private void Update ( )
    {
        if ( Input.GetMouseButton ( 0 ) 
            && currentWeapon  != null 
            && !currentWeapon.weaponFiring )
        {
            _weaponCoroutine = StartCoroutine ( currentWeapon.StartWeaponFire ( this ) );
        }
    }
}

Notice we're starting a coroutine which has been defined on the currentWeapon, and we're sending through a reference to the Player class. The other method, the 'coroutine' in this case, can then call the public fields, properties and methods of the Player instance.

This is great way to enable an item to define a "coroutine" but allow a specified object to run that coroutine code. This scenario would allow you to have multiple 'players' be able to run the same coroutine, and you don't need to clutter your `Player' class with code for each individual weapon you might include in the game.

  • Related