Finally Starting First Game

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Finally Starting First Game

      I started reading this book back in 2012 and got busy and stopped. I recently played through Axiom Verge and absolutely loved it. I found that the game was created in MonoGame, which is done with C#. I decided I can't wait any longer and need to create a game now.

      I'm creating my game using MonoGame (XNA). I'm a C# dev by trade, so I know the language very well. I read through the book once and am reading through it a second time while writing code and making the engine as I go. Things aren't exactly lining up perfectly, but I've been able to translate most things so far. Destructors are a sticking point that I need to work around. I'm currently doing everything pretty much 1-to-1. I've though about just doing something even more basic and just adding things in, but my plan is to do it nearly identical, then refactor and delete things after.

      I'm mostly a retro gamer, so all the games I have planned are 2D, and probably tile based. I think I'm going to use the Tiled mapeditor.org format. This will allow me to use their editor to create tile maps, and if I want to (or have time), I can build it into my own level editor.

      I'm sure I'll have lots of questions in the next couple of years while working on this.
    • Nice! My biggest piece of advice is to not bite off more than you can chew. Most people fail at making their first game because they try to do too much. Do something incredibly simple, like Tetris. Cloning a classic game is a great way to learn since you are only concentrating on the tech.

      C# does have destructors:
      msdn.microsoft.com/en-us/library/66x5fx1b.aspx

      Of course, you have little control over when the destructor is actually called since it happens during garbage collection. On The Sims Medieval, we had explicit destruction for game objects. There was a virtual Destroy() method on game objects that could be overridden and would be called instantly when the object was removed from the object manager. We rarely (if ever) used destructors.

      You could do something similar. I know a lot of game engines have their own base class that's used as the ultimate base for every single class in their hierarchy. Some examples include UObjectBase in Unreal 4 and System.Object in .NET. If you followed this model, you could easily define it like so:

      Source Code

      1. public class BaseObject
      2. {
      3. public virtual Destroy()
      4. {
      5. // do nothing by default
      6. }
      7. }


      The trick is making sure that destroyed objects always call this method, so you can't have them just magically disappear. We definitely had this issue on The Sims Medieval. It was made worse because a Sim had a C++ game object as well as a C# game object. Destroying a Sim meant calling Destroy() on the C# object which would call Destroy() on the C++ object. That would disconnect the two, destroy the C++ object, and remove the C# reference in the object manager. This would (hopefully) cause the object to get collected. Of course, having a strong reference to it somewhere else would screw you over. I spent a good month tracking down memory leaks on that project.

      The Sims 4 was better. We made much better use of weak references.

      Anyway, feel free to post any questions you have. We're always happy to help. :)

      -Rez
    • Thanks Rez!

      C# destructors are referred to as finalizers, and you're not supposed to use them. There is a baked in pattern that is supposed to be used instead; IDisposable. there are lots of things in the framework that know how to work with that interface. The best practice handling a disposable object is to wrap it in a using block:

      Source Code

      1. using( var stream = new MemoryStream() )
      2. {
      3. // Use the stream.
      4. } // The stream is garbage collected as soon as possible here.


      Of course, if you create a disposable object in a constructor, you can't clean it up until later. This is when you'd want to implement IDisposable yourself, and clean that up.

      This is how IDisposable is supposed to be implemented. msdn.microsoft.com/en-us/library/fs2xkftw(v=vs.110).aspx

      As far as C++ goes, the destructor is automatically called when an object is deleted, right? And this will automatically happen when a shared_ptr is doing it's thing to? I guess my concern was that objects would be automatically deleted and the destructors called without explicitly deleting. This isn't really possible in .NET. .NET does do a good job of cleanup though. It even handles circular dependencies just fine.

      I figured I would probably have to manually make sure I call Dispose or a Destroy method. Hopefully I don't have a month of hunting down memory leaks. :)

      I'm thinking of creating a post with conversions from C++ to C# for others that don't know C++ too well. Just all the things I've been running into that aren't possible in .NET or the syntax is different, and how I dealt with them.

      I'm sure I'll have tons of questions for you guys in the future here.

      Thanks again Rez!
    • That all makes sense. I remember having to deal with the IDisposable interface, but it was many years ago so I've forgotten most of it by now. ;)Memory leaks are MUCH more common (and often more painful) in a language with managed memory because of how easy it is to forget about and accidentally hold onto references. We had more memory leaks in the C# layer than the C++ layer on The Sims Medieval. Same with The Sims 4. I tend to prefer C++ because it gives me more control, but I'm in the minority of developers. Then again, I did get a lot of cheers when I gave my talk at GDC about how scripting languages are overused.

      narshe wrote:


      As far as C++ goes, the destructor is automatically called when an object is deleted, right?

      Yes.

      And this will automatically happen when a shared_ptr is doing it's thing to?

      Yes, this happens synchronously when the ref count drops to zero. The memory is freed and the destructor is called.

      -Rez