Oe nisra
Oe nisra

Reputation: 3

Call function by using GetComponent with name without knowing it's actually type

I have three types of balls(A, B, C) all inherit MotherBall, they all have thesame behavior only some setting is different.

There is an ObjectPool which I can get ball by balltype, then it will contain it's script(AScript, BScript or CScript)

The situation is I will randomly take ball from object pool, and I hope I can handle it in one function not separate. Is there any way to call the Setting function like below code? I'm thinking maybe generic or delegates can slove it, or I need to write three functions. Thanks, everyone. P.S sorry my English is poor, I can't accurate describe my problem.

public void OneBallFire(string ballType){
    GameObject ball = ballPool.GetObjectFromPool (ballType);

    //I can't cast AScript, BScript or Motherball.
    MotherBall ballScript = ball.transform.GetComponent (ballType) as MotherBall;
    ballScript.Setting ();
}

public class MotherBall : MonoBehaviour{
    public virtual void Setting() {
      //Do nothing
    }
}

public class AScript : MotherBall {
    public  void Setting(){
      Debug.Log("Do A plan");
    }
}

public class BScript : MotherBall {
    public  void Setting(){
      Debug.Log("Do B plan");
    }
}

OneBallFire( RandomGetAorBorC() );
string RandomGetAorBorC(){
    //random return "AScript, BScript or CString" string.
}

Upvotes: 0

Views: 176

Answers (3)

TimChang
TimChang

Reputation: 2417

Generic type is better solution for your case , And more Simply

public void OneBallFire<T>() where T : MotherBall
{
    GameObject ball = ballPool.GetObjectFromPool<T>(ballType);

    //I can't cast AScript, BScript or Motherball.
    T ballScript = ball.transform.GetComponent<T>();
    ballScript.Setting();
}

// BoolPool Todo This
public T GetObjectFromPool<T>()
{
    if(T is AScript)
       //Clone && Return a AScript Obj
    // Todo all type ....

    return null;
}

Upvotes: 0

Umair M
Umair M

Reputation: 10720

I am not sure if this will work in your scenario but I would go with classic is as to get the actual script:

var component = ball.transform.GetComponent(customScript);
if (component is AScript)
{
    (component as AScript).Setting();
}
else if (component is BScript)
{
    (component as BScript).Setting();
}
else
{
    (component as MotherBall).Setting();
}

UPDATE:

You need to update implementation of BallPool container in a way that you don't have to worry about sub-types and typecasting.

Here is a simple example:

I imagine you are storing ball gameObjects in a list. First thing I would do is use List<MotherBall> as container.

public class BallPool : Monobehaviour
{
    public List<MotherBall> ballPrefabs = new List<MotherBall>();
    ...
}

Add all kind of ball prefabs in this list from the inspector.

THen your method will look like this:

public MotherBall GetObjectFromPool()
{
    return Instantiate(ballPrefabs[Random.Range(0,ballPrefabs.Count));
}

Then in your other script:

public BallPool ballPool; // assign from the inspector

void Start() // or whatever other method
{
    var ball = ballPool.GetObjectFromPool();
    ball.Setting();
}

Now ball.Setting() will use the overridden method from either AScript or BScript depending on what object was selected and You don't need to worry about type as all the prefabs will have a script inherited from MotherBall so all must have Setting() if they don't have this method overridden then MotherBall.Setting() will be called.


Hope this helps :)

Upvotes: 0

BanksySan
BanksySan

Reputation: 28510

No, because you're overriding the method. If you need to have a method with the same signature as the base class's method you'll need to remove the override keyword and replace it with new. Now you'll have two methods that are totally unrelated to each other, you access the one on the Motherball object by casting to Motherball.

public class AScript : MotherBall {
    public new void Setting(){
      //Do something
    }
}

var _ball = new AScript();
_ball.Setting() // calls Setting on AScript
((MotherBall) _ball).Setting(); // Calls Setting on MotherBall

What I suspect you want to do though is invoke the base method when you call Setting() on the AScript class. You have two options here.

  1. Just remove the method in AScript completely, any call to AScript.Setting() will invoke the base class's Setting() method.
  2. Call the base class's Setting() method from the AScript classes method, to do this use the base keyword, e.g. base.Setting().

Upvotes: 1

Related Questions