Unity 5.3 onClick 参数问题
Unity 5.3 onClick with parameters issue
在我的游戏中,我以编程方式为关卡 select 屏幕创建了一堆按钮,我的目的是让它们的 onClick 触发一个函数,其参数对应于关卡编号。
伪代码:
public class UIManager extends MonoBehaviour {
public var button : Transform;
public function Start() {
for(var i : int = 0; i < 10; i++) {
var level : int = i + 1;
var b : Transform = Instantiate(button);
b.GetComponent(UI.Button).onClick.AddListener(function(){
StartGame(level);
});
}
}
public function StartGame(level : int) {
Debug.Log(level);
}
}
但是,在这种情况下,当按下这些按钮中的任何一个时,控制台会显示数字 10。
我怎样才能实现我的目标?
您应该看看 JavaScript 中的匿名函数如何捕获外部变量。
您正在 for-loop 中创建 10 个匿名函数。所有这些函数都引用局部变量level
。但是,在第一次调用它们之前,它们还没有为此变量创建自己的范围。这意味着,没有 10 level
个局部变量,只有一个,直到第一个函数被实际调用。只有这样才会评估 level
的当前值。这将是最后分配的值:10.
要解决这个问题,您必须在循环的每次迭代期间强制创建一个新范围:
public class UIManager extends MonoBehaviour
{
public var button : Transform;
public function Start()
{
for(var i : int = 0; i < 10; i++)
{
var level : int = i + 1;
var b : Transform = Instantiate(button);
b.GetComponent(UI.Button).onClick.AddListener
(
(function(newLocalLevel)
{
return function()
{
StartGame(newLocalLevel);
};
}) (level)
);
}
}
public function StartGame(level : int)
{
Debug.Log(level);
}
}
我将您对匿名处理程序函数的直接分配更改为工厂函数调用,它将 level
的当前 (!) 值作为参数。当它被立即执行时,工厂函数创建了自己的作用域,有一个名为 newLocalLevel
的局部作用域,其中包含 level
.
的正确值
工厂函数现在创建并 returns 您的匿名处理程序函数,即使它尚未创建自己的作用域,它也引用封闭工厂函数的局部 newLocalLevel
,它具有循环的每次迭代都有一个单独的范围。
在我的游戏中,我以编程方式为关卡 select 屏幕创建了一堆按钮,我的目的是让它们的 onClick 触发一个函数,其参数对应于关卡编号。
伪代码:
public class UIManager extends MonoBehaviour {
public var button : Transform;
public function Start() {
for(var i : int = 0; i < 10; i++) {
var level : int = i + 1;
var b : Transform = Instantiate(button);
b.GetComponent(UI.Button).onClick.AddListener(function(){
StartGame(level);
});
}
}
public function StartGame(level : int) {
Debug.Log(level);
}
}
但是,在这种情况下,当按下这些按钮中的任何一个时,控制台会显示数字 10。
我怎样才能实现我的目标?
您应该看看 JavaScript 中的匿名函数如何捕获外部变量。
您正在 for-loop 中创建 10 个匿名函数。所有这些函数都引用局部变量level
。但是,在第一次调用它们之前,它们还没有为此变量创建自己的范围。这意味着,没有 10 level
个局部变量,只有一个,直到第一个函数被实际调用。只有这样才会评估 level
的当前值。这将是最后分配的值:10.
要解决这个问题,您必须在循环的每次迭代期间强制创建一个新范围:
public class UIManager extends MonoBehaviour
{
public var button : Transform;
public function Start()
{
for(var i : int = 0; i < 10; i++)
{
var level : int = i + 1;
var b : Transform = Instantiate(button);
b.GetComponent(UI.Button).onClick.AddListener
(
(function(newLocalLevel)
{
return function()
{
StartGame(newLocalLevel);
};
}) (level)
);
}
}
public function StartGame(level : int)
{
Debug.Log(level);
}
}
我将您对匿名处理程序函数的直接分配更改为工厂函数调用,它将 level
的当前 (!) 值作为参数。当它被立即执行时,工厂函数创建了自己的作用域,有一个名为 newLocalLevel
的局部作用域,其中包含 level
.
工厂函数现在创建并 returns 您的匿名处理程序函数,即使它尚未创建自己的作用域,它也引用封闭工厂函数的局部 newLocalLevel
,它具有循环的每次迭代都有一个单独的范围。