Lunar Engine - Sound System

There are a number of libraries out there that deal with sound. FMOD, Ogg Vorbis, etc. are all viable options for an engine and most of them already have decent .Net wrappers. In fact I was thinking about FMOD, but I'm just not interested in paying the $100 fee if I decide to sell a product using it when there is a free option out there: DirectAudio. There are a couple of issues though with using DirectSound/DirectMusic in a product though:

  1. DirectMusic isn't in the current version of the DirectX SDK (The August SDK has it though)
  2. Writing your own loaders for various sound files is a pain (although wav files aren't that bad actually)
  3. SlimDX doesn't seem to support it yet
  4. I'm not even going to talk about Managed DirectX, but suffice to say that writing your own wrapper might be the best choice

In fact I did that exact thing. I wrote my own wrapper for it:

Sound.zip (4.64 kb) 

It allows for 3D sound, wav files, midi, etc. And I'm currently writing code to record sound from a mic to send over a network. However that isn't in the current version yet. One thing you might want to keep in mind about this update is it was written in C++ unlike the rest of the engine. Other than that though, it's pretty straight forward.

Anyway, It has been a while since I've posted an update about the Lunar Engine. You can blame a couple of large projects at work for the delay. Also, sadly this update is rather boring but I should be getting into more interesting portions of the engine in the next installment. Also expect some more web development posts in the next couple of days. i have some interesting code with regard to Exchange servers to share. Anyway, download the code, review, comment, etc. I always appreciate feedback.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 3/12/2008 at 6:34 PM
Tags: , ,
Categories: Game Programming | Sound
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Lunar Engine - Input or "Action Mapping and You"

Back in DirectX 8.0 (or it might have been 9.0, I can never remember), Microsoft introduced a new feature into DirectInput called Action Mapping. In theory it was suppose to fix all of our problems when it came to interacting with the user. In reality it never really worked out and wasn't extremely popular, it was used just not nearly as popular as say HLSL.

The main problem with the implementation that Microsoft gave us was two fold. First, it wasn't that flexible and the second problem was that it simply wasn't that easy to use (much more complicated than it needed to be). However the concept as a whole is rather solid: We have events that we want to do when a specific state is reached (when a specific key or set of keys are down). Instead of constantly polling to see if that state is reached, we let the system do it. The system then calls the events for us. Basically it allows for an event driven architecture.

I've decided to use this concept, although tweaked, within the Lunar Engine. The input system is a little too large for me to post here on the page so I've added it as a zip file:

InputManager.zip (3.71 kb) 

I've commented the functions, etc. so you should be able to figure it out. I will note though that it does use the Lunar Engine's main object to initiate some things as well as hook itself up. Also note that for the backbone I'm using Mogre's version of OIS. It seems to work well and I didn't want to bother with wrapping my old DirectInput code. As I've gotten older I've noticed I've become a lot lazier in that regard.

To setup our own mappings we simply use code similar to the following:

//Create the list of keys we want to associate with the action
List<KeyCode> KeyCodes=new List<KeyCode>();
KeyCodes.Add(KeyCode.KC_ESCAPE);

//Create the action itself
ActionMapping EndProgramAction=new LunarEngine.Input.ActionMapping("EndProgram", //The name of the action
 KeyCodes,
 new EventHandler<LunarEngine.Input.InputEventArgs>(Escape_Event))  //The event to call

//Add the action to the list that the engine uses
Engine.Input.Mappings.Add(EndProgramAction);

And the engine takes care of the rest. Anyway, download the file and view the system. It's a very basic implementation that just matches up a set of keys (or mouse movement) to an event and that's about it but it does show you how to set up a similar system within your own game. There are more complicated implementations that I've seen including one here. However I've always felt that a simpler approach would work better. What about you, what are your experiences with action mapping? Suggestions for improvement?

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 3/2/2008 at 7:51 AM
Tags: , , ,
Categories: Game Programming | Input
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Lunar Engine Error Logging System

One of the main problems with working on any sort of project, whether it is a game or not, is how to detect and report bugs to the developers in an easy/straightforward manner.  In a previous post I talked a bit about various options out there and proposed using a database. Using a database for this sort of work has a number of advantages (some of which I mentioned previously and some that I didn't):

  • It's quick and designed specifically to store information
  • It is easy to search through and gather information from
  • It's easy to setup and get running

So with that in mind, I've decided to use this approach within the Lunar Engine. I also decided that I was going to use MySQL as the backend portion. And while I'm not going to go over setting it up (although there is a good tutorial here), I will go over the code and database itself:

The Table

The table that I'm using for saving the errors is rather straightforward and used the following statement to set it up

CREATE TABLE  errors (
  `ErrorID` int(10) unsigned NOT NULL auto_increment,
  `ErrorText` varchar(5000) NOT NULL,
  `ErrorType` int(10) unsigned NOT NULL,
  `File` varchar(1024) NOT NULL,
  `Line` int(10) unsigned NOT NULL,
  `StartTime` datetime NOT NULL,
  `Method` varchar(1024) NOT NULL,
  PRIMARY KEY  (`ErrorID`)
)

This allows us to store information about the error including the error message, error type (general, lost input device, etc.), file it occurred in, line it occurred on, time that the program was started, and the method in which the error occurred. There are a few other items that we could save, but this will do for our purposes. The next step is setting up the code:

The Code

 

using System;
using System.IO;

namespace LunarEngine
{
    public class ErrorLog
    {
        public ErrorLog()
        {
#if DEBUG
            try
            {
                string ConnectionString = "DRIVER={MySQL ODBC 3.51 Driver};" +
                          "SERVER=localhost;" +        //The server location should go here
                          "DATABASE=errorlog;" +     //The database name, in this case ErrorLog
                          "UID=user;" +                     //Whatever you've setup as the user name for the database
                          "PASSWORD=password;"+   //Whatever you've setup as the password for the database
                          "OPTION=3";

                Connection = new System.Data.Odbc.OdbcConnection(ConnectionString);
                Connection.Open();

                Run = DateTime.Now;
            }
            catch (Exception a)
            {
                throw a;
            }
#else
            File = new FileStream("./Logs/Errors.txt", FileMode.CreateNew,FileAccess.Write);
            Writer = new StreamWriter(File);
#endif
        }

        public void Write(string Message, ErrorType ErrorType)
        {
            try
            {
#if DEBUG
                System.Diagnostics.StackFrame CallStack = new System.Diagnostics.StackFrame(1, true);
                string File = CallStack.GetFileName().Replace("\\","\\\\");
                string Method = CallStack.GetMethod().Name;
                int Line = CallStack.GetFileLineNumber();


                System.Data.Odbc.OdbcCommand Command;
                string CommandString = "insert into errors(ErrorText,ErrorType,File,Line,StartTime,Method)"+

                         "values (\"" +
                         Message + "\"," + ((int)ErrorType).ToString() + ",\"" +
                         File + "\"," + Line.ToString() + ",\""+
                         Run.ToString("yyyy-MM-dd hh:mm:ss")+"\",\""+Method+"\");";
                Command = new System.Data.Odbc.OdbcCommand(CommandString, Connection);
                int LinesInserted = Command.ExecuteNonQuery();
#else
                Writer.Write(((int)ErrorType).ToString()+" "+Message);
#endif
            }
            catch (Exception a)
            {
                throw a;
            }
        }

        public void Cleanup()
        {
#if DEBUG
            if(Connection!=null)
            {


            if(Connection.State!=System.Data.ConnectionState.Closed)
            {
                Connection.Close();
            }


            }
#else
            Writer.Close();
            File.Close();
#endif
        }

        private System.Data.Odbc.OdbcConnection Connection;
        private FileStream File;
        private StreamWriter Writer;
        private DateTime Run;


        public enum ErrorType
        {
            General = 1
        };
    }
}

 

Final Word

There are a couple of areas where the code might confuse you:

Why am I not passing in the file, method, and line information to the function? 

Well in C# there is no __FILE__ or __LINE__ constants. The only way to really get that information is to use the StackFrame class. It's a bit awkward but it will let you know what you need. Also note though that it will not work in release mode as the debug information that it uses isn't available.

Why are you using this system only in debug builds?

The reasons for using a more traditional file system to record this information in release is two fold. First, we would have to setup the ODBC driver on the end user's machine. The second issue is that it could be just a bit too slow. While it is fast enough when the database is on the same machine as the application, the error message would have to be sent to the server, a response sent back, etc. if it were left in during release. To be honest that isn't really something we want to deal with. There are ways we could address that issue, run the error logging system in its own thread for example, but we should save those threads for items that would enhance our game.

This approach as you can see is easy to setup though and fast enough for our purposes when it comes to debugging the system. There's another advantage that I haven't talked much about yet, our ability to search through the information. We can easily setup a website to use the information to present it in a readable manner that can allow us to filter out the noise and get to the info we want. I will say that I've talked enough though and I'll go over this further in a future post.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 2/26/2008 at 4:19 PM
Tags: , ,
Categories: C# | Database | Game Programming | MySQL
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed