unity3d 在c# Unity中,脚本可以设置为函数的参数吗?

gc0ot86w  于 2023-03-09  发布在  C#
关注(0)|答案(4)|浏览(211)

我在两个脚本中有相同的函数- Attack(),我想从一个有这个函数的类继承它们。所以我的问题是,在c# Unity中,脚本可以被设置为函数的参数吗?

public void Attack()
{
    _animator.SetTrigger("Attack");

    Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(_attackPoint.position, _attackRange, _enemyLayer);
    foreach (Collider2D enemy in hitEnemies)
    {
        enemy.GetComponent<PlayerAnimator>().TakeDamage(_attackDamage);// in second script there is <EnemyAnimator>
    }
}
46scxncf

46scxncf1#

这是面向对象编程的基础-在这种情况下,您主要有两种选择:
你应该有

  • 如果接口只是具有相同的方法签名,但行为完全不同,那么它就是接口
public interface IDamageable
{
    void TakeDamage(float damage);
}

然后

public class PlayerAnimator : MonoBehaviour, IDamageable
{
    public void TakeDamage(float damage)
    {
        Debug.Log($"I'm a player and do a certain thing when I take {damage} amount of damage");
    }
}

public class EnemyAnimator : MonoBehaviour, IDamageable
{
    public void TakeDamage(float damage)
    {
        Debug.Log($"I'm an enmy and do something completely different when I take {damage} amount of damage");
    }
}
  • 通过继承并拥有一个已经实现了通用行为的通用父类,然后可以扩展-如果需要的话
// Careful with this naming in that case!
public class Damageable : MonoBehaviour
{
    virtual void TakeDamage(float damage)
    {
        Debug.Log("This is the common default behavior for my inheritors - except the overwrite or extend it");
    }
}

以及

public class PlayerAnimator : Damageable 
{
    public override void TakeDamage(float damage)
    {
        // First call the default implementation
        base.TakeDamage(damage);

        Debug.Log($"I'm a player and do some additional stuff");
    }
}

public class EnemyAnimator : Damageable 
{
    public override void TakeDamage(float damage)
    {
        Debug.Log($"I'm an enmy and decided to not do the default thing but something completely different");
    }
}

这里,如果您不需要EnemyAnimatorPlayerAnimator之间的任何不同行为,那么答案很简单:那就只上一门课吧!
然后我会去

public void Attack()
{
    _animator.SetTrigger("Attack");

    var hitEnemies = Physics2D.OverlapCircleAll(_attackPoint.position, _attackRange, _enemyLayer);

    foreach (Collider2D enemy in hitEnemies)
    {
        // OPTION A
        if(enemy.TryGetComponent<IDamagable>(out var damageable))
        // or OPTION B
        //if(enemy.TryGetComponent<Damagable>(out var damageable))
        {
            damageable.TakeDamage(_attackDamage)
        }
    }
}
5kgi1eie

5kgi1eie2#

是的,在unity c#中,脚本可以被设置为函数的参数。你所需要做的就是首先输入脚本的名称,然后输入你想要调用的名称。就像这样:

public void Attack(EnemyAnimator enemyAnimator)
{
    _animator.SetTrigger("Attack");

    Collider2D[] hitEnemies = 
    Physics2D.OverlapCircleAll(_attackPoint.position, _attackRange, 
    _enemyLayer);
    foreach (Collider2D enemy in hitEnemies)
    {
        enemy.GetComponent<PlayerAnimator>().TakeDamage(_attackDamage);
    }
}
fjaof16o

fjaof16o3#

从长远来看,这可能不是你想要的(检查关于OOP结构的答案),但这是你将脚本作为参数传递的方式。

EnemyAnimator和PlayerAnimator类可能都派生自Monobhavior类。

public class NewBehaviourScript : MonoBehaviour { 
//Class name after ":" is the class your script is derived from.

如果您希望将攻击功能用于两个Animator,则需要添加常规Monobehavior类型作为参数:

public void Attack(Monobehaviour animator)
{
    animator.SetTrigger("Attack");

    Collider2D[] hitEnemies = 
    Physics2D.OverlapCircleAll(_attackPoint.position, _attackRange, 
    _enemyLayer);
    foreach (Collider2D enemy in hitEnemies)
    {
        enemy.GetComponent<animator>().TakeDamage(_attackDamage);
    }
}

这样,您可以在调用函数时将EnemyAnimator和PlayerAnimator用作参数。

tsm1rwdh

tsm1rwdh4#

回答:
在c#Unity中脚本可以被设置为函数的参数吗?
答案是肯定的,但是有一些限制。如果你想使用GetComponent<ScriptParameter>(),你需要做一些类似generic method的事情:
要将Type作为参数传递,可以使方法接受泛型类型并将其约束到基类。

public static class AttackManager
{
    public static void Attack<T>(Animator attackerAnimator, Transform attacker, float attackRange, float damage, int targetLayer) where T : AnimatorBase
    {
        attackerAnimator.SetTrigger("Attack");

        Collider2D[] hitTargets = Physics2D.OverlapCircleAll(attacker.position, attackRange, targetLayer);
        foreach (Collider2D target in hitTargets)
        {
            target.GetComponent<T>().TakeDamage(damage);
        }
    }
}
  • 请注意,我将您的Attack()方法转换为一个接受攻击者和目标信息的泛型静态方法 *

该类型假定PlayerAnimatorEnemyAnimator派生自基类,例如:
x一个一个一个一个x一个一个二个一个x一个一个三个一个
现在,您只需将函数调用为:

AttackManager.Attack<PlayerAnimator>(attackerAnimator: animator,
                                     attacker: enemy,
                                     attackRange: range,
                                     damage: _attackDamage,
                                     targetLayer: LayerMask.GetMask("player"));

AttackManager.Attack<EnemyAnimator>(attackerAnimator: animator,
                                     attacker: player,
                                     attackRange: range,
                                     damage: _attackDamage,
                                     targetLayer: LayerMask.GetMask("enemy"));

相关问题