2

I am writing a video game in C#, and I would like to handle certain events (e.g. keyboard/mouse events) only at a specific point in my game loop. For example, is there a way to write something like the following:

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

If an event occurs at some other point in the loop, I would like to wait until handleAllEvents() to handle them. By "events" I mean the standard C# event system, for example:

public event Action<object, KeyboardEventArgs> KeyPressed;

Please let me know if the question is not phrased clearly. Thanks!

fyhuang
  • 2,147
  • 5
  • 21
  • 24
  • 2
    Isn't the whole point of an event that you don't handle it synchronously ie when a specific line of code is reached? Perhaps there is a different design strategy you should be exploring if you're 'events' aren't really 'events'. Also, reactive extensions is a really powerful framework for dealing with events -- http://msdn.microsoft.com/en-us/data/gg577609. Check it out. – Sean Thoman Nov 23 '11 at 21:52
  • As an alternative to the events answers posted, see [mine](http://stackoverflow.com/q/8249664/593627) for the approach more generally used in games (polling). – George Duckett Nov 23 '11 at 22:04
  • @Sean: Game loop is a pretty common pattern in game programming. It doesn't necessarily need to be implemented this way, but the point is to handle input and game logic completely before rendering each frame. Having a possibility of events being fired randomly significantly complicates game design. – vgru Nov 23 '11 at 22:10
  • @Groo, I understand your point, but I think the OP was misunderstanding what exactly an 'event' really is -- when you run a game loop and handle input processing at a specific time (ie before rendering), you aren't delaying the handling of the event you are delaying the processing of the arguments that the event produced. In fact you handle the event immediately, passing its arguments onto another object. In standard .NET there is no way to delay the handling of an event, that would defy precisely what an event is. Its a subtle difference I suppose but an important one nonetheless. – Sean Thoman Nov 23 '11 at 22:15

3 Answers3

5

Remove the call to Application.Run(), and build up your own message loop. For example like this:

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

You must then ensure, that render will not stay there for so long.

For more info I suggest you to study the Application class, especially methods Run() and DoEvents().

Zoka
  • 2,312
  • 4
  • 23
  • 33
  • This is a fine way to do it, but I see no reason to reinvent. `OpenTK.GameWindow` class already handles this and other things like vsyncing, time slicing, double buffering, etc. You can check its source code [here](http://www.opentk.com/files/doc/_game_window_8cs_source.html) to see all the stuff it does under the hood. – vgru Nov 23 '11 at 22:31
  • I am already using GameWindow, actually. I suppose my issue is that I don't care when some events (e.g. OS events) occur, and some other ones I do (e.g. it would be nice if I could wait to handle a key press until after I have finished the per-frame initialization). Does that sound reasonable or should I be thinking of some other way to structure my program? – fyhuang Nov 25 '11 at 07:26
1

I believe the proper way to do it in OpenTK would be to inherit from the GameWindow class, and then override OnUpdateFrame and OnRenderFrame. There is a QuickStart solution included when you checkout the trunk, check the Game.cs file.

[Edit] To clarify further, OpenTK.GameWindow class provides a Keyboard property (of type OpenTK.Input.KeyboardDevice), which should be read inside OnUpdateFrame. There is no need to handle keyboard events separately, as this is already handled by the base class.

/// <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();
    }
}

Also, for a more elaborate example, download Yet another starter kit from their webpage. The class should look something like this:

// 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);
        }
    }
}

I would recommend that you download Yask and check how it's implemented there.

vgru
  • 49,838
  • 16
  • 120
  • 201
1

If you're using a game loop you generally wouldn't handle events, you'd poll input devices when you need them (i.e. in your handleAllEvents() method). Some quick researched told me that in you can find this stuff in the OpenTK.Input namespace and in particular the KeyboardDevice class.

George Duckett
  • 31,770
  • 9
  • 95
  • 162
  • Thanks for your suggestion! Shouldn't it be easier to handle some sorts of input as "events" though--for example, handling keypresses for text input? I can understand polling for "continuous" input (like hold right arrow to move the character to the right), but what if I have some situation where an event-like model seems more appropriate? – fyhuang Nov 25 '11 at 07:24
  • If you want to handle typing text then yes, an event model is better, if you want to handle things more typical in games (moving a character right) then do it with polling. – George Duckett Nov 25 '11 at 08:07