Implementing a Timer and Callback System in MonoGame ToddMitchell, October 23, 2023July 11, 2024 Build it, set it, and forget it As I discussed in my recent case for MonoGame in modern times, the MonoGame framework gives you nearly total freedom to build your game your way. The other side of that: it gives you little else. In this post, I aim to walk through one of the first big features I couldn’t find anywhere else, and how I went about making up for it. One of the projects I started to relearn MonoGame–I worked my way through an XNA book more than a decade ago while my wife and I were still dating–is a collection of pencil and paper games inspired by my childhood kitchen table gaming sessions with my grandpa. The first game was Tic Tac Toe. Tic Tac Toe against the computer feels weird if the computer opponent takes its turn milliseconds after you take yours in the next drawn frame. To make it feel like the computer is thinking about it for a moment, I needed some kind of timer or callback. I was surprised to discover MonoGame doesn’t seem to have any appointed method for this. The consensus is that you have the GameTime object in your Update method, so you should be able to do anything you need to do. Searches online seem to bring back discussion of different ways to perform a delay with a simple variable or what kind of additional libraries you can add to your project to gain this functionality. Forums also included a lot of muddled theories about how to do the callback portion. Some are still unresolved. I ended up building my own little system for this that allows you to create one or multiple concurrent timers, each with their own callback method that fires as soon as time is up. Here’s how it works: The Timer Class Yes, we’re creating our own custom class for this to keep the code from cluttering up Game1.cs, although you could do this in that file too if you must. // Timer.cs using System; using Microsoft.Xna.Framework; namespace YourProject; public class Timer{ public Timer(float seconds, Action callbackMethod){ TotalTime = seconds; CallbackMethod = callbackMethod; } public float ElapsedTime{get;set;} private float TotalTime{get;} public Action CallbackMethod{get;} public bool isDone = false; public void Update(GameTime gameTime){ ElapsedTime += (float)gameTime.ElapsedGameTime.TotalSeconds; if(ElapsedTime >= TotalTime){ CallbackMethod(); isDone = true; } } } Nothing extraordinary here. 20ish lines of code depending how you space it. You’ll need to include Microsoft.Xna.Framework so you can work with the GameTime object when the Game1 class throws it to you during the Update method. System allows you to use Actions which we’ll touch on in a moment. The constructor accepts (and requires) the duration for the timer in seconds and the callback method you want to execute when time is up. The key to executing a callback method is the Action delegate. C# has two delegate keywords: Func lets you refer to methods that can accept parameters and returns a value, and Action can accept parameters but returns void. Why does it work this way? That’s a serious question. I have no idea. Nevertheless, if we pass our callback method into the constructor as an action, we’ll be able to execute it later. We have member variables to track elapsed time, total time, the callback method, and a bool indicating whether the timer is done. You could optionally simplify by using one time variable and subtracting from it each cycle instead of adding to a second variable, but this gives me the option to implement a timer reset later because I’ll still have the original value. The update method adds the time since the last cycle to the elapsed time variable, and checks to see if we’ve met or exceeded the timer’s total intended duration. If so, we call our callback method and set the done bool to true. How to use a Timer in the Game class Here’s what to add to Game1.cs to make your game march in the Debug Console. // in the Game1 member variables: List<Timer> timers; // in LoadContent() for(int i = 0; i< 10; i++){ if(i % 2 == 0){ timers.add(new Timer(i,PrintLeft)); }else{ timers.add(new Timer(i,PrintRight)); } } // in Update() UpdateTimers(gameTime); // add this to update timers protected void UpdateTimers(GameTime gameTime){ for(int i = 0; i < timers.Count; i++){ var timer = timers[i]; timer.Update(gameTime); if(timer.isDone){ timers.Remove(timer); } } } // here's your PrintLeft method protected void PrintLeft(){ Console.WriteLine("Left"); } // here's your PrintRight method protected void PrintRight(){ Console.WriteLine("Right"); } When this game runs, your game should output “Left,” then “Right,” one second apart for ten steps. Each is the result of a timer expiring and calling its designated callback method. There you have it: a reliable but lightweight timer and callback system that’s hopefully ready for just about anything. Did you solve this problem some other way? By all means, shout it out in the comments. Share this:FacebookXLike this:Like Loading... Game Development AsyncDelayGameDevmonogametutorial
Game Development Let’s Make a Nintendo Game November 26, 2020July 11, 2024 In continuing our console development basics series, we look at what it takes to develop an indie game for Nintendo’s latest game console, the Switch. If you like more options, we’ll look at a way you can make a limited Switch game with no permission from Nintendo whatsoever. Finally, we’ll… Share this:FacebookXLike this:Like Loading... Read More
Culture Author David L. Craddock April 15, 2019July 11, 2024 If you don’t think you’ve read or at least seen any of David L. Craddock’s phenomenal books on the game industry and game development, check again, you probably have. Some of the greatest stories of the development space have been captured in David’s phenomenal pages, including Blizzard’s early history with… Share this:FacebookXLike this:Like Loading... Read More
Game Development A Tale of Tutorials December 2, 2019July 11, 2024 Welcome back! This time on GameDev Breakdown we’re discussing the finer points of tutorials in games, and yes, whether or not they even have a rightful place in them. That idea may surprise you, unless you spend any time talking about development on Twitter where it’s become oddly commonplace. Share this:FacebookXLike this:Like Loading... Read More