C# 带有代理的游戏控件绑定字典

C# 带有代理的游戏控件绑定字典,c#,dictionary,delegates,game-engine,key-bindings,C#,Dictionary,Delegates,Game Engine,Key Bindings,我的游戏的属性类型为IInput: private IInput Input; 在游戏循环之前,我添加了一些键绑定,如下所示: protected override void Initialize() { input.BindKey( Keys.Escape, Exit ); // etc... } internal class Input : IInput { private readonly IDictionary<Keys, Tuple<Action&l

我的游戏的属性类型为
IInput

private IInput Input;
在游戏循环之前,我添加了一些键绑定,如下所示:

protected override void Initialize()
{
    input.BindKey( Keys.Escape, Exit );
    // etc...
}
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(Keys.W, Tuple.Create<Action<Directions>, Directions>(Move, Directions.Up));
input.BindKey(Keys.W, () => Move(Directions.Up));
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();
            }
        }
    }
}
private readonly IDictionary<Keys, Delegate> keyBindings;
我该怎么做?我尝试更改
Input
类的
keyBindings
属性:

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();
            }
        }
    }
}
private readonly IDictionary<Keys, Delegate> keyBindings;
但类似的方法不适用于带参数的绑定方法:

// 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 ) );
编辑

我错误地使用了
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 ) );

这里的关键概念是,使用委托,您只是指向一个接受输入参数的方法,因此它不会像您在代码中编写的那样工作,参数应该在调用期间传递!因此,作为一种解决方法,您可以这样编写st:

protected override void Initialize()
{
    input.BindKey( Keys.Escape, Exit );
    // etc...
}
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(Keys.W, Tuple.Create<Action<Directions>, Directions>(Move, Directions.Up));
input.BindKey(Keys.W, () => Move(Directions.Up));
编辑: 您甚至可以使用原始的
Input
类执行此操作,而不是指向
Move
方法,您可以创建一个代理来为您执行此操作(s.t如@Magus在评论中所说),如下所示:

protected override void Initialize()
{
    input.BindKey( Keys.Escape, Exit );
    // etc...
}
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(Keys.W, Tuple.Create<Action<Directions>, Directions>(Move, Directions.Up));
input.BindKey(Keys.W, () => Move(Directions.Up));

这样,在调用过程中,将调用此delate,并依次调用带有必需参数的
Move
方法。

为什么要使用
Func
执行此操作?它会返回s.t吗?您在那里编写的
Func
,需要一个不带参数的方法,该方法返回一个
字典
!不幸的是,您在这方面不会有太多的运气,因为代理不能像那样动态地更改其参数数/返回值。我建议你让所谓的行动做任何任务。我和一位朋友实际上做了一些非常类似的事情,不过在一个额外的抽象层后面是标志枚举按钮,还有一个队列,它可以识别最近按下的按钮序列,并将它们与正确的委托进行匹配。请注意,如果您尝试这样做,这并不容易。@ArinGhazarian只是因为我认为我需要使用
Func
@davidkennedy85,如果是这样,那么您想要一个接受方法作为输入并返回方向的委托,对吗?基本上,您可以执行类似
Action Action=()=>\u ownerPositionVector=Move(Direction.Left)。该操作将根据调用move的方式在执行时分配字段。它并不比这样做的方法更危险,只是你可能不希望它发生。我个人认为这很酷。我的整个控制方案都是基于它的,它允许我通过简单地更改绑定来隐式地更改事物的状态,而不使用布尔标志。我认为他的主要问题是他有N个参数,可能返回也可能不返回任何内容。这
input.BindKey(Keys.W,()=>Move(Directions.Up))正是我要找的!