英文:
Can a script be set as a parameter of a function in c# Unity?
问题
我有两个脚本中都有相同的函数 - 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);// 在第二个脚本中使用<EnemyAnimator>
}
}
英文:
I have the same function - Attack() in two scripts and i would like to inherit them from a class which has this function. So my question is can a script be set as a parameter of a function in 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>
}
}
答案1
得分: 1
以下是您要翻译的代码部分:
That's OOP basics - In such a case you have mainly two options:
You should have
- an interface if it is only about having the same method signatures but completely different behavior
public interface IDamageable
{
void TakeDamage(float damage);
}
And then
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");
}
}
- go through inheritance and have a common parent class which already implements common behavior and can then be extended - if needed at all
// 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 they overwrite or extend it");
}
}
and
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");
}
}
Here if you don't need any different behavior between `EnemyAnimator` and `PlayerAnimator` the answer would be easy: Just stick to a single class then!
And then I would go
public void Attack()
{
_animator.SetTrigger("Attack");
var hitEnemies = Physics2D.OverlapCircleAll(_attackPoint.position, _attackRange, _enemyLayer);
foreach (Collider2D enemy in hitEnemies)
{
// OPTION A
if(enemy.TryGetComponent<IDamageable>(out var damageable))
// or OPTION B
// if(enemy.TryGetComponent<Damageable>(out var damageable))
{
damageable.TakeDamage(_attackDamage)
}
}
}
英文:
That's OOP basics - In such a case you have mainly two options:
You should have
-
an interface if it is only about having the same method signatures but completely different behavior
public interface IDamageable { void TakeDamage(float damage); }
And then
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"); } }
-
go through inheritance and have a common parent class which already implements common behavior and can then be extended - if needed at all
// 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"); } }
and
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"); } }
Here if you don't need any different behavior between
EnemyAnimator
andPlayerAnimator
the answer would be easy: Just stick to a single class then!
And then I would go
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)
}
}
}
答案2
得分: 0
答案是是的,但有一些限制。如果您想要在C# Unity中将脚本设置为函数的参数,您需要像以下示例中所示执行一些操作:
要将一个“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()”方法转换为了一个接受攻击者和目标信息的泛型静态方法。
这个类型假设您的“PlayerAnimator”和“EnemyAnimator”都派生自一个基类,例如:
//我将其设为抽象类,您可以以其他方式做,如@derHugo的回答中所述
public abstract class AnimatorBase : MonoBehaviour
{
public abstract void TakeDamage(float damage);
}
public class PlayerAnimator : AnimatorBase
{
public override void TakeDamage(float damage)
{
Debug.Log("玩家受到伤害");
}
}
public class EnemyAnimator : AnimatorBase
{
public override void TakeDamage(float damage)
{
Debug.Log("敌人受到伤害");
}
}
现在,您可以像这样调用函数:
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"));
英文:
To answer:
> can a script be set as a parameter of a function in c# Unity?
The answer is yes, but with some constraints. If you want to use the GetComponent<ScriptParameter>()
you would need do do something like generic method:
To pass a Type
as a parameter you could make your method accept a generic type and constrain it to your base class.
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);
}
}
}
Notice I transformed your Attack()
method into a generic static method that takes attacker and target info
The type assumes your PlayerAnimator
and EnemyAnimator
derive from a base class for example:
//I made it abstract you could do it other ways, such as mentioned in @derHugo answer
public abstract class AnimatorBase : MonoBehaviour
{
public abstract void TakeDamage(float damage);
}
public class PlayerAnimator : AnimatorBase
{
public override void TakeDamage(float damage)
{
Debug.Log("player took damage");
}
}
public class EnemyAnimator : AnimatorBase
{
public override void TakeDamage(float damage)
{
Debug.Log("Enemy took damage");
}
}
Now you would just call the function as:
AttackManager.Attack<PlayerAnimator>(attackerAnimator: animator,
attacker: enemy,
attackRange: range,
damage: _attackDamage,
targetLayer: LayerMask.GetMask("player"));
or
AttackManager.Attack<EnemyAnimator>(attackerAnimator: animator,
attacker: player,
attackRange: range,
damage: _attackDamage,
targetLayer: LayerMask.GetMask("enemy"));
答案3
得分: -1
是的,可以将脚本设置为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);
}
}
英文:
Yes, a script can be set as a parameter of a function in unity c#. All you need to do is first of all the script's name, followed by what you want to call it. Like this :
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);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论