我在两个脚本中具有相同的功能 - 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>
}
}
是的,在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);
}
}
如果我理解正确的话,你的 EnemyAnimator 和 PlayerAnimator 类都是从 Animator 类派生的。如果你想将 Attack 脚本与两个 Animators 一起使用,你需要添加一个通用的 Animator 对象作为参数:
public void Attack(Animator animator)
{
_animator.SetTrigger("Attack");
Collider2D[] hitEnemies =
Physics2D.OverlapCircleAll(_attackPoint.position, _attackRange,
_enemyLayer);
foreach (Collider2D enemy in hitEnemies)
{
enemy.GetComponent<animator>().TakeDamage(_attackDamage);
}
}
这样你就可以在调用函数时同时使用 EnemyAnimator 和 PlayerAnimator 作为参数。
不同班级的例子
如果你想使用另一种类型的脚本,你需要查找脚本派生自哪个类。例如,标准的 Unity 脚本源自类 MonoBehaviour。然后你只需要把前面例子中的 Animator 基类换成你的其他基类。
public class NewBehaviourScript : MonoBehaviour {
//Class name after ":" is the class your script is derived from.
那是 OOP 基础知识——在这种情况下,您主要有两个选择:
你应该有
一个接口,如果它只是关于具有相同的方法签名但完全不同的行为
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");
}
}
在这里,如果您不需要
EnemyAnimator
和 PlayerAnimator
之间的任何不同行为,那么答案很简单:那就坚持一个班级吧!
然后我会去
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)
}
}
}
你在这里有各种各样的答案可以帮助你学到很多东西,我已经开始写一个并从字面上解决你的问题,尽管在大多数情况下我会采用不同的方法。话虽如此:
要将
Type
作为参数传递,您可以让您的方法接受泛型类型并将其约束到您的基类。
public class AttackManager : MonoBehaviour
{
public void Attack<T>(float damage) where T : AnimatorBase
{
GetComponent<T>().TakeDamage(damage);
}
}
假设您的
PlayerAnimator
和 EnemyAnimator
来自基类,例如:
public class AnimatorBase : MonoBehaviour
{
public void TakeDamage(float damage)
{
//
}
}
public class PlayerAnimator : AnimatorBase
public class EnemyAnimator : AnimatorBase
现在您只需将函数称为:
AttackManager attackManager;
// Start is called before the first frame update
void AnyMethod()
{
attackManager.Attack<PlayerAnimator>(1f);
}
现在这就是您要传递类型的方式。尽管我没有看到我的示例是最佳方法的上下文。