2011-11-23 69 views
2

我正在用C#编写视频游戏,并且我想仅在我的游戏循环中的特定点处理某些事件(例如键盘/鼠标事件)。例如,是否有写类似以下的方式:如果在回路中的其他一些点发生的事件只在C#中的特定时间触发事件#

void gameLoop() 
{ 
    // do updates 
    handleAllEvents(); 
    render(); 
} 

,我想等到handleAllEvents()来处理它们。通过“活动”我的意思是标准的C#事件的系统,例如:

public event Action<object, KeyboardEventArgs> KeyPressed; 

请让我知道,如果问题不是很清楚。谢谢!

+2

是不是一个事件的整个点,你不同步处理它,即当达到特定的代码行?如果你的“事件”不是真正的“事件”,或许你应该探索一种不同的设计策略。另外,反应式扩展是处理事件的真正强大的框架 - http://msdn.microsoft.com/zh-cn/data/gg577609。一探究竟。 –

+0

作为发布事件答案的替代方案,请参阅[mine](http://stackoverflow.com/q/8249664/593627)了解游戏中更常用的方法(轮询)。 –

+0

@ Sean:游戏循环是游戏编程中很常见的模式。它不一定需要用这种方式来实现,但重点是在渲染每一帧之前完全处理输入和游戏逻辑。随机发生事件的可能性大大增加了游戏设计的复杂性。 – Groo

回答

5

删除对Application.Run()的呼叫,并建立自己的消息循环。例如像这样:

void GameLoop() 
{ 
     while (!exitSignal) 
     { 
      Application.DoEvents(); 
      render(); 
     } 
} 

然后你必须确保渲染不会停留那么久。

欲了解更多信息,我建议你学习Application类,特别是方法Run()DoEvents()

+0

这是一个很好的方式来做到这一点,但我认为没有理由重塑。 'OpenTK.GameWindow'类已经处理了这个和其他的东西,如vsyncing,时间分割,双缓冲等等。你可以检查它的源代码[here](http://www.opentk.com/files/doc/_game_window_8cs_source.html )看到它所做的所有事情。 – Groo

+0

我已经在使用GameWindow了。我想我的问题是,我不在乎什么时候发生某些事件(例如操作系统事件),以及我做的其他事件(例如,如果我可以等待处理按键直到完成每次按键操作,帧初始化)。这听起来合理吗?还是我应该考虑以其他方式来构建我的程序? – fyhuang

1

我相信在OpenTK中做到这一点的正确方法是继承GameWindow类,然后覆盖OnUpdateFrameOnRenderFrame。当您结帐时,包含QuickStart解决方案,请检查Game.cs文件。

[编辑]为了进一步阐明,OpenTK.GameWindow类提供一个Keyboard属性,它应内部OnUpdateFrame被读取(类型OpenTK.Input.KeyboardDevice的)。不需要单独处理键盘事件,因为这已经由基类处理过了。

/// <summary> 
/// Called when it is time to setup the next frame. Add you game logic here. 
/// </summary> 
protected override void OnUpdateFrame(FrameEventArgs e) 
{ 
    base.OnUpdateFrame(e); 
    TimeSlice(); 

    // handle keyboard here 
    if (Keyboard[Key.Escape]) 
    { 
     // escape key was pressed 
     Exit(); 
    } 
} 

另外,如需更详细的示例,请从其网页下载Yet another starter kit。该类应该是这个样子:

// Note: Taken from http://www.opentk.com 
// Yet Another Starter Kit by Hortus Longus 
// (http://www.opentk.com/project/Yask) 
partial class Game : GameWindow 
{   
    /// <summary>Init stuff.</summary> 
    public Game() 
     : base(800, 600, OpenTK.Graphics.GraphicsMode.Default, "My Game") 
    { VSync = VSyncMode.On; } 

    /// <summary>Load resources here.</summary> 
    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 
     // load stuff 
    } 

    /// <summary>Called when your window is resized. 
    /// Set your viewport/projection matrix here. 
    /// </summary> 
    protected override void OnResize(EventArgs e) 
    { 
     base.OnResize(e); 
     // do resize stuff 
    } 

    /// <summary> 
    /// Called when it is time to setup the next frame. Add you game logic here. 
    /// </summary> 
    protected override void OnUpdateFrame(FrameEventArgs e) 
    { 
     base.OnUpdateFrame(e); 
     TimeSlice(); 
     // handle keyboard here 
    } 

    /// <summary> 
    /// Called when it is time to render the next frame. Add your rendering code here. 
    /// </summary> 
    protected override void OnRenderFrame(FrameEventArgs e) 
    { 
     base.OnRenderFrame(e); 
     // do your rendering here 
    } 

    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main() 
    { 
     using (Game game = new Game()) 
     { 
      game.Run(30.0); 
     } 
    } 
} 

我会建议您下载Yask,并检查它是如何实现的存在。

+0

虽然这并不能告诉他如何处理输入,这是他所要求的。 –

+0

@George:我已经更新了答案。 – Groo

+0

+1。很好的答案。 –

1

如果您使用的是游戏循环,则通常不会处理事件,您需要时会轮询输入设备(即在您的handleAllEvents()方法中)。一些快速研究告诉我,在中,你可以在OpenTK.Input命名空间中找到这个东西,特别是KeyboardDevice类。

+0

感谢您的建议!尽管如此,处理某些输入作为“事件”不是更容易 - 例如,处理文本输入的按键?我可以理解对“连续”输入的轮询(如右键向右移动字符),但如果我遇到类似事件的模型似乎更合适的情况呢? – fyhuang

+0

如果你想要处理输入文本,那么是的,如果你想处理比较典型的游戏(移动角色),那么事件模型更好,然后通过轮询来完成。 –