我有两个基于Unity的类,其中一个表示Player对象,另一个表示应该能够操作播放器的通电。
我的想法是将玩家操纵操作封装在可以传递给玩家对象的方法中,例如,当玩家与通电相撞时。
这些操作可以包括简单的场和属性变化(健康点),但也可能包括Coroutines(自动射击或具有时间间隔的盾牌)。
目前,我的播放器类本身包含所有与powerup相关的操作,并根据碰撞时从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相关的逻辑,并将其保存在各自的通电中。
是否有技术可能在一个可以从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());
}
答案 0 :(得分:3)
首先我想说,我认为传递方法的引用对于这种情况是错误的解决方案。我只是将Player
的引用传递给Powerup
类中的方法。
话虽如此,使用代理是.Net编程的一个重要而有力的部分,所以我想我最好给你一点介绍 - 所以这里有:
使用委托来传递对方法的引用是可能的,甚至很容易。自.Net 2.0版本起,您可以使用Action
和Func
预定义的系统代理。
它们中有很多,介于16个通用参数之间没有参数,这意味着你必须像我们在.Net 1.1中那样用旧的时尚方式编写委托。 (很久很久以前)
所有Action
个委托代表void
个方法,所有Func
个委托代表返回值的方法。创建一个接受Action
或Func
作为参数并调用它的方法(以及许多内置类和扩展方法)非常简单(也是一种非常常见的做法) .Net框架执行此操作,例如List<T>.ForEach
和linq方法几乎完全基于Func
个委托。
让我们以linq为对象Any()
方法源代码(因为它很简单):
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<TSource, bool>
并在IEnumerable
中的每个项目上调用它,直到它找到谓词返回true
的项目,或者它到达IEnumerable
的结尾并返回false
。