在我的游戏中,我以编程方式为级别选择屏幕创建了一组按钮,我的目的是让他们的onClick触发一个带有与级别编号对应的参数的函数。
伪代码:
m = MyCrazyClass.new(id: 231, first_name: "Joe", last_name: "Smith", age: 38, salary: BigDecimal.new("125000"))
m.get_first_name() # returns Joe
serialized = Marshal::dump(m)
obj = Marshal::load(serialized)
obj.get_first_name() # returns Joe
但是,在这种情况下,当按下任何这些按钮时,控制台会显示数字10。
我如何实现我的目标?
答案 0 :(得分:1)
您应该了解JavaScript中的匿名函数如何捕获外部变量。
您正在for循环中创建10个匿名函数。所有这些函数都引用局部变量level
。但是,在首次调用它们之前,它们尚未为此变量创建自己的范围。这意味着,在实际调用第一个函数之前,没有10 level
个本地,但只有一个。{1}}。只有这样才能评估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
值。
工厂函数现在创建并返回您的匿名处理函数,即使它尚未创建自己的作用域,它也会引用封闭工厂函数的本地newLocalLevel
,它对每次迭代都有一个单独的作用域循环。