我的游戏有IInput
类型的属性:
private IInput Input;
在游戏循环之前,我添加了一些像这样的键绑定:
protected override void Initialize()
{
input.BindKey( Keys.Escape, Exit );
// etc...
}
BindKey
方法将一个项添加到Input
类的键绑定字典中:
internal class Input : IInput
{
private readonly IDictionary<Keys, Action> keyBindings;
public void BindKey( Keys key, Action action )
{
keyBindings.Add( key, action );
}
public void Process()
{
// update keyboard state...
foreach ( var binding in keyBindings )
{
if ( keyboard.IsKeyDown( binding.Key )
{
binding.Value();
}
}
}
}
在游戏循环期间调用Process
方法。这很好用,但我想将一个键绑定到一个接受参数ala:
input.BindKey( Keys.W, Move( Directions.Up ) );
我该怎么做?我尝试更改keyBindings
类的Input
属性:
private readonly IDictionary<Keys, Delegate> keyBindings;
这要求我将原始绑定更改为:
input.BindKey( Keys.Escape, new Action( Exit ) );
但类似的方法不适用于带参数的绑定方法:
// compiler error: "Method name is expected"
input.BindKey( Keys.W, new Func<Directions>( Move( Directions.Up ) ) );
// compiler error: "Delegate constructor is invoked with 2 argument(s)"
input.BindKey( Keys.W, new Func<Directions>( Move, Directions.Up ) );
这也不起作用:
// compiler error: "Argument type 'lambda expression' is not assignable to parameter type 'System.Delegate'"
input.BindKey( Keys.W, x => Move( Vector2.Zero ) );
修改
我错误地使用了Func
。我想为方法提供方向,但我不关心它返回什么。我也没有走得太远:
// 1. Cannot use "void" as a type argument
// 2. Method name is expected
input.BindKey( Keys.W, new Func<Vector2, void>( Move( Directions.Up ) );
// Cannot apply operator ">" to operands of type "null" and "void"
input.BindKey( Keys.W, new Func<Vector2, null>( Move( Directions.Up ) );
即使我将Move
方法更改为返回true:
// Method name is expected
input.BindKey( Keys.W, new Func<Vector2, bool>( Move( Directions.Up ) );
答案 0 :(得分:2)
这里的关键概念是,使用委托,你只是指向一个接受输入参数的方法,因此它不会像你在代码中编写的那样工作,参数应该在调用期间传递!所以作为一种解决方法,你可以写st。像这样:
internal class Input : IInput
{
private readonly IDictionary<Keys, Tuple<Action<Directions>, Directions>> keyBindings;
public void BindKey( Keys key, Tuple<Action<Directions>, Directions> action)
{
keyBindings.Add( key, action );
}
public void Process()
{
// update keyboard state...
foreach ( var binding in keyBindings )
{
if ( keyboard.IsKeyDown( binding.Key )
{
binding.Value.Item1(binding.Value.Item2);
}
}
}
}
像这样使用input.BindKey
:
input.BindKey(Keys.W, Tuple.Create<Action<Directions>, Directions>(Move, Directions.Up));
修改强>
您甚至可以使用原始Input
类来执行此操作,而不是指向Move
方法,您可以创建一个委托来为您执行此操作(如评论中的@Magus所述),如下所示:
input.BindKey(Keys.W, () => Move(Directions.Up));
这样,在调用期间,将调用此delate,然后您可以看到它使用所需参数调用Move
方法。