【问题标题】:Pass a function as a parameter between classes在类之间传递函数作为参数
【发布时间】:2018-05-26 11:52:30
【问题描述】:

我有两个基于 Unity 的类,其中一个代表 Player 对象,另一个代表应该能够操纵玩家的 powerup。

我的想法是将播放器操作封装在一个可以传递给播放器对象的方法中,例如当玩家与通电发生碰撞时。

这些操作可以包括简单的字段和属性更改(健康点),还可能包括协程(自动射击或具有时间间隔的盾牌)。

目前,我的播放器类在其自身中包含所有与通电相关的操作,并根据碰撞时从通电对象传递的字符串调用它们:

PlayerController.cs

public class PlayerController : MonoBehaviour
{
    private Dictionary<string, UnityAction> powerupMethods;

    // ...

    public void ActivatePowerUp(string name)
    {
        Invoke(powerUpMethods[name]);
    }
}

Powerup.cs

public class Powerup : MonoBehaviour
{
   private string _name;

   // ...

   private void OnCollision2D(Collision col)
   {
       PlayerController p = col.collider.GetComponent<PlayerController>();
       if (p != null)
       {
           p.ActivatePowerup(_name);
       }
   }
}

我的愿望是从玩家对象中消除所有与通电相关的逻辑并将其保留在相应的通电中。

是否有技术上的可能性将此类操作包含在一个可以从 powerup 对象传递到 player 对象的方法中,像这样?最好的情况是玩家对象可以访问方法中的私有字段。

// Powerup.cs
public void Ability()
{
    // Do stuff with Player object, even private fields
    // e.g. player._health++;
    // But also activate self-based Coroutines
    // e.g. StartCoroutine(CoroutineMethod());
}

private IEnumerator CoroutineMethod()
{
    // e.g. auto fire for 5 seconds
}

private void OnCollision2D(Collision2D col)
{
    PlayerController p = col.collider.GetComponent<PlayerController>();
    if (p != null) p.Invoke(Ability());
}

【问题讨论】:

  • 您最后的示例代码令人困惑,您是否要将Player 对象传递给Powerup(作为参数 - 在这种情况下,这里有什么问题?)还是您想要将函数传递给另一个类(例如:作为回调)?
  • 我更新了我想要的代码。
  • 如果你真的想传递一个函数,那么你可以使用delegate,请参阅官方文档:docs.microsoft.com/en-us/dotnet/csharp/programming-guide/… - 至于“更好的建议”,这主要取决于你非常具体的场景,所以很难给出一般性建议(在许多情况下,将方法作为参数传递是一种可接受的选择)
  • 我不确定您为什么认为有问题 - 您是否有实际错误(如果有,请发布代码和确切的错误消息)?您可以将几乎任何东西作为参数传递,只需弄清楚参数类型需要是什么。
  • 我只会让电源在碰撞时操纵玩家统计数据,然后自行摧毁。对于枪支之类的东西,我会将它们添加到清单之类的列表中,并让列表根据当前内部的内容影响玩家

标签: c# function unity3d parameter-passing


【解决方案1】:

首先让我说我认为传递对方法的引用是这种情况下的错误解决方案。我只需将Player 的引用传递给Powerup 类中的方法。

话虽如此,使用委托是 .Net 编程的一个重要而强大的部分,所以我想我最好给你做一点介绍 - 所以这里是:

使用委托传递对方法的引用是可能的,甚至非常容易。从 .Net 2.0 版本开始,您可以为此使用 ActionFunc 预定义的系统委托。
它们有很多,从无参数到 16 个通用参数不等,这意味着您很少需要像我们在 .Net 1.1 中那样以老式方式编写委托。 (很久很久以前)

所有Action代表代表void方法,所有Func代表代表返回值的方法。创建一个接受ActionFunc 作为参数并调用它的方法非常容易(也是一种非常常见的做法) - .Net 框架的许多内置类和扩展方法都是这样做的,例如 List&lt;T&gt;.ForEach 和 linq 方法几乎完全基于 Func 委托。

我们以linq to objectAny()方法源码为例(因为简单):

public static bool Any<TSource>(this IEnumerable<TSource> source, 
                                Func<TSource, bool> predicate) {
    if (source == null) throw Error.ArgumentNull("source");
    if (predicate == null) throw Error.ArgumentNull("predicate");
    foreach (TSource element in source) {
        if (predicate(element)) return true;
    }
    return false;
}

如您所见,它接受 Func&lt;TSource, bool&gt; 并在 IEnumerable 中的每个项目上调用它,直到找到谓词返回 true 的项目,或者它到达 @987654340 的末尾@ 并返回 false

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多