How exact is exact? What is a good level of adherence to standards?

July 3, 2008

When at work the other day, I had a conversation with a colleague about some of the stuff I was doing outside of work.  He was surprised that I was actually more exacting on the code that I do in my spare time than the code at work.  It was an interesting conversation as he is what we call a “cowboy coder”.  Don’t get me wrong, the industry needs cowboy coders as much as they need a lot of other types of coders.

From my experience, a cowboy coder is someone who gets in there, minimally gets the job done and gets on to the next problem to solve.  A positive to this is that they get things fixed quickly.  There are a number of bad things though, that need to be mentioned.  Usually, a cowboy coder will try and find the minimal set of exit criteria and then aggressively work towards that solution.  This means that things such as coding standards and running tools such as CodeStyle and FxCop are not done, or ignored, as they “do not add anything to the code itself”.  It is often very difficult to convert a cowboy coder to a coder that believes in spending some extra time on quality, as they perceive quality differently.

Myself, I am of the opposite spectrum, but willing to work on some middle ground.  I perceive quality as something that can be qualitatively measured using accepted tools and practices.   Exit criteria are not meaningful unless the business owners understand the trade offs involved in each solution.  Best practices are followed as much as possible as they are… well… best practices.  If a number of people in the industry have put their heads together and decided that something is a best practice, it sounds like a really good idea to follow it unless there is a good reason not to.

Let’s apply this to my Asteroids project.  While I could have posted the code up here already, I am running it through some rules and FxCop, some written by me and some written by experts.  The ones I wrote are usually codifications of my style or of practices that others have looked at.

The two that usually get me are a high McCabe Cyclomatic Complexity index and a method having too many instructions.  The Cyclomatic Complexity, or CC, measures the number of branching points that you have within an object.  Hence, a method with a single statement would have a CC of 1, one with a single statement inside of an if or while statement would have a CC of 2, and so on.

According to best practices, the CC for the methods, according to best practices, should not exceed 10(for warning, 20 for error) for a method, and 120 and 240 for a class.  If you have something that exceeds these limits, you are writing something that is getting far too complex to test properly.  Personally, I think this is a good best practice, as it generates better code that you can have a better handle on how it is tested, so I wrote a rule for FxCop that measures it.

Similarly, the number of instructions is a good indication of complexity of a method.  If the number of instructions exceeds 150 for warning or 300 for error, then you have a method that is doing far too much work.  At this point, its a best practice to break that method down into two or more methods, refactoring the code to make it more readable, maintainable, and reusable.  Once again, this seems like a good best practice to follow, so I wrote another rule.

Now, the stuff I write at home is more prone to experiments than the stuff I write at work, but I still use the same rules plus some extra ones to measure how good my code is.  When talking with my friend at work, its an uphill battle.  In a number of cases, he has written a method that has a single switch statement with over 30 cases in it.  Even he knows it is not very maintainable, but he doesn’t think its bad because he wrote a 25 line documentation block at the top that explains how to make modifications.  Sigh.

Well, asteroids v0.9 is close to being “clean”, at which time I will post the code.

Back from out of the weeds…

June 15, 2008

Ever have one of those couple of weeks where it was hard to poke your head above the din and figure out what is going on?  Welcome to my last 2 weeks and job hunting.  I just thought I would update this blog today, as it is father’s day.

 

On the asteroids game, it is still going through some testing.  Recently I have noticed that every so often it gets a weird error when processing the sprite information, and I have been trying to figure that out.   No dice so far, but I think I am narrowing down on it.

 

Also, I did some work on the FxDeputy project and made sure that it was a bit cleaner, as I wanted to use it as a code sample for prospective employers.  This seemed to work, and it has benefited the project.  For the most part it was just cleaning things up, but was a good mind-numbing exercise for the end of a long day.

 

Between debugging and running FxCop on both projects, noticed that a couple of the rules that I had written had some problems when using nested classes.  This is proving useful in understanding how FxCop digs down into the code and analyses it.

 

Given some time in the next couple of days, hoping to add hyperspace to the asteroids game, and will detail that.

The stuff that asteroids and stars are made of…

May 30, 2008

Taking a look at my list from last time, I decided to make a dig at coming up with better asteroids and stars.  The stars were pretty easy.  I looked at a couple of games and noticed that most of the stars looked like a small circle with a pair of lines through it.  Thus, I created a sprite that was like that, made it yellow.  Then, I moved the "clearing the sprite collection" method into its own method and made sure that I added between 5 and 15 stars to the screen at random locations where the screen was cleared.  Pretty simple.

 

The asteroids were a bit more of a problem.  How to come up with a "realistic" looking asteroid that would be enticing without too much effort to render, thus slowing down the rendering speed.  At the moment, a square asteroid isn’t too convincing, but it sure is easy to debug.  So the first thing I did is to make sure that if I have the debug mode enabled, the square asteroids would remain.

 

Now for rest of the block.  A nice empty block with this at the top.

//TODO: Make the asteroids more realistic looking.

Now its time for the thinking cap.  What makes the asteroids from the original game interesting to look at?  After I looked at a couple, it was the small variations that made it interesting to me.  I thought it was the big craters at first, but it was more of the "snowflake" approach.  By that, I mean that no two snowflakes are the same, so I would want to make sure there was a low chance that two asteroids were the same.

On doing some closer looking, I noticed that this may be accomplished by picking a random degree, add it to the current position, and set a point a random amount away from the center at that angle from the last position.  In the square case, this would have been 90 degree increments at a fixed distance away from the center.  It would have to be more than that.

It took quite a bit of fiddling, but what I came up with is as follows:

// The outer bound for our asteroids are asteroidSize, so pick an inner number to
// use that allows us to have interesting looking asteroids.
int otherSize = (75 * AsteroidSize) / 100;

// Pick a starting angle and set the first point.  Not that sin(0 deg) = 0 and cos(0 deg) = 1,
// so we can take a quick short cut for this first one.
int startDegree = 0;
int distanceOfRadius = AbstractGameForm.Singleton.RandomGenerator.Next(otherSize, AsteroidSize);
_asteroidPolygon.AddPoint( distanceOfRadius, 0.0f );

// Keep on going until we get to close to the start, in which case, just end it.
while (startDegree < 345)
{
    // Pick a number of degrees and add that to our total, and pick a length from the
    // center to draw it.
    startDegree += AbstractGameForm.Singleton.RandomGenerator.Next(15, 30);
    distanceOfRadius = AbstractGameForm.Singleton.RandomGenerator.Next(otherSize, AsteroidSize);

    // Figure out the next point, at the specified distance from the middle and the specified angle.
    float angleOfArc = FloatingPolygon.RadiansPer * startDegree;
    _asteroidPolygon.AddPoint(
        (float)(distanceOfRadius * Math.Cos(angleOfArc)),
        (float)(distanceOfRadius * Math.Sin(angleOfArc))
        );
}

This works in the following way.  Pick a minimum distance away from the center, and use that with the "size" to determine the ranges for our distance from center.  Our first point is at 0 deg, which means that X will be that random distance and Y will be 0.  Then, as long as we don’t have a full range of degrees, iterate through picking a new angle to add and a new distance away from the midpoint, creating a vertex of our polygon at each point.

The numbers were pure fiddling.  For some reason, 75% seems to work for my eyes and the minimum distance, and 15-30 degree increments seem to produce a smooth enough gradient that looked "natural".  At least to me.  I played around with little bits here and there until I came up with those numbers.  Feel free to try the same thing and suggest other numbers.

Running it a couple of times, I was pleased with the asteroid shapes, but there was a bit of a problem when it got to the edge of the screen.  As it approached the edges, it was fine.  However, once one of the polygons points crossed over, it disappeared until the center crossed, at which point half of the asteroid appeared on the other side.  Some simple calculations with boundaries took care of that, making it so that the asteroids appear as soon as any point crosses over.

This was not that difficult to overcome, a bit of simple math with the bounding circle and the polygon center to see if it crosses any boundary.  Pretty quick work of that and then the asteroids seamlessly transition across the boundaries without a jump.  Two checks for the upper and lower boundaries, and two checks for the left and right boundaries… well, actually three.  We also need to account for the case where something crosses both the horizontal and vertical at the same time.  Individually, these were taken care of, but that only redrew them at 2 places, leaving the 3rd corner mysteriously vacant.  Easy change, and it was now covered.

Running the game with the asteroids set to 0 with no velocity proved interesting.  For some reason, the bullets were not registering on any of the corners… so I will be checking into that next, and trying to figure out why that is happening.

Realistic explosions, well, kind of…

May 25, 2008

Well, the kids are having a fun time play testing the asteroids game as I develop it. My son in particular likes being able to blow up the asteroids, though he doesn’t seem to get that this game doesn’t have good guys and bad guys.

The game is pretty playable, with 3 lives, scores for the asteroids, full collision detection. Things that were still missing:

  • ufos and satellites – these will be added later as I think these don’t add a lot
  • realistic shaped asteroids – high up on the list, but square polygons are easier to debug
  • hyperspace and/or shields – need to do a bit of thinking on this one
  • stars on the backdrop – a little piece of fluff
  • sounds for the actions – this will enhance the game, but I will wait with this
  • extra lives – variations included extra lives when hitting milestones
  • better restarting of level – right now, I restart the entire level if the ship is destroyed
  • high score – some simple way to keep track of the high scores
  • explosions for the asteroids and the ship – this one I decided to tackle

There are probably more on the list, but this is a good list for now. The explosions were a bit of work, so decided to tackle them last.

Explosions are something that add a bit of fun to the game, but trying to figure out how to do it was a bit of research. How should I make the polygons explode when something hits them? Looking at a couple of implementations out there, the best way seemed to be some spinning thing with each of the edges of the polygon.

How to do this? Once again, back to high school math. What we really want to do is to take the edge and move it away from the center of the explosions, and spin the edges and have them die out after a number of iterations. For debugging, it is really good that we still have our asteroids as squares, as it will make it easy to debug. To start with, no aging or spinning, just edges.

High school math to the rescue. It shames me to admit, but I was looking at this problem for a while, and it was when I was in the car doing an errand that the formula hit me. I had half of the answer right, as I was taking the average of both the delta X and delta Y, which got me the mid point in one axis, but the other was way off. When I used my debugging mode to find the bounding circles, it was way off, sometimes off the screen.

Then it hit me… I do want to use the average for the delta Y, which would give me an established point, but then I needed to solve for the delta X. When I was taking both averages, I was picking a “random” point that was definitely not going to be on the line. What I needed was something that would tell me how many X to add for my selected Y. What I really wanted was to find the slope of the given line… and slope = rise / run.

Plugging that in, there were still a couple of problems. As the squares are in use, there is a deltaX == 0 and deltaY == 0 case that appear when the square it oriented normally. Those are easy cases to figure out as you just need to take the midpoint of the non-zero delta. The other edge is simply deltaY * slope, which gives us a midpoint. I might want to change this later to pick someplace close to the midpoint to make it more interesting, but this works for now.

Testing this out, the explosions starts to work, the edges show up and stay there. Forgot to add in a velocity component. Not a big thing… set the velocity to the normalized vector from the middle of the exploding object to the midpoint that we selected. If we don’t normalize the vector, the bigger the object, the faster it goes, which is not what we want. Normalizing is finding out the magnitude of the vector (square root of the combined square of the x and y components) and multiplying both x and y components by the inverse of that magnitude.

Testing yet again produced edges that would travel slowly away from the object and eventually die when they left the screen. Easy solution here, give some sprites a maximum age and when they hit that age, they die out. On top of that, we add a rotation element to each and make sure it has a good spin to it.

After a bit of testing and fiddling, got it in place. Seems to be working pretty well, and my kids are loving it so far. Looking for a good place to post the code as it evolves, so hopefully that will be up somewhere soon.

More fun with Asteroids

May 22, 2008

With my son egging me on, I put an effort forth tonight to finish it up enough that I can let him play it. Something about having a 5 year old cheering squad just doesn’t sound right.

So, with the collision detection done last night for the missiles, adding in the collision for the ships and asteroids was pretty easy. But then there was a decision point to be made. I had a way of detecting that ships/asteroids and missile/asteroid collided, but how to do the plumbing to do the bookkeeping that goes along with those items being involved in a collision and then removed.

To the rescue comes the C# delegates. This is an interesting construct in C#. For those not familiar with it, its kind of like an interface on a method level, in that it defines a contract for a method, rather than a class. With this, I retooled my sprite collection interface and providers to allow the delegate to be set, and then called it when an item was being removed from the given collection. This kept everything working cleanly, and the main form was the only thing that needed changing.

That being done, repurposed the FPS indicator to a scoreboard/indicator and added a status indicator on the right side of the screen. This allows communication of the current game state and all that useful information. Keeping things simple was pretty key, so I made simple transitions between the various states.

One little thing I am having problems with is that it seems like the space key (fire button) is not always being detected, in spite of me surrounding it in a locked section. Some more investigation needed there.

A funny thing happened on the way to the collision…

May 21, 2008

First off, as promised, I will talk about collision detection. However, on the way there, I encountered some other fun things.

The first one is wonderment at how efficient my algorithms are. Here I am wanting to write something that will work well with the user, and I wanted to check to see what the fps (frames per second) rate was. This turned out to be pretty easy, and the bulk of it is as follows:

///
/// Note that a frame has passed and do any math that we need to.
///
public void NoteFrameOccurence()
{
// Take the measurement every 1000ms or 1s.
if ((Environment.TickCount - _lastTick) >= 1000)
{
// Keep the count that we achieved here.
LastMeasurement = _frameCount;
_numberOfSamples++;
_totalFrameCount += _frameCount;

// Reset the count and measurement.
_frameCount = 0;
_lastTick = Environment.TickCount;
}
_frameCount++;
}

Basically, keep track of how many frames we see before 1000ms or 1s passed. If we hit that time, stop collection for that section, remember the last one and add the data to our major sample counters, so we can reflect what the average across our application’s run time.

That being said, I had initially implemented the sprite engine as having a collection of GameSprite objects. Now that I had some way of measuring it, I wanted to see if using an array would be more efficient. With some refactoring, tuning and stuff, I was able to get an array provider that was able to get between 60 and 66 fps with the number usually around 62 or 63. The collection on was usually between 59 and 64 with 61 being the sweet spot. Thus, the array provider seems to work slightly better for now.

On to collision detection. Collision detection is primarily about geometry. The first two types of detection are pretty simple: bounding boxes and bounding circles. The basis for both is pretty much the same: what is the smallest entity of that type that can fit around all of the points in the geometric object in the sprite. These are both used for first pass detection as you can handle both of them pretty easily and quickly. Mileage may vary.

For my first pass I use a bounding circle which can easily be computed at the beginning of the sprite’s life. All I do is check to see what the maximum distance is from the centroid of the sprite to each vertex. This works really well in this case because we are doing a lot of rotations and the bounding circle doesn’t change based on orientation. And for those who need some reminders… distance = sqrt(( a.x – b.x )^2 + (a.y – b.y)^2).

A bounding rectangle would pretty much work the same way, compute the tightest rectangle that completely surrounds the object in question. In our case, we would have to compute it for our sprite after every change in orientation, but could cache that and apply the current position to that. I’ll probably check it out later, but for now, the bounding circle is working just fine.

That leaves us to the more detailed checking. For our purposes, we want to check to see if any point in one sprite is within the bounds of the other sprite. After doing a bunch of searching, I came across this useful article [need to add link here] that explained the math. Okay, I remembered all of the math he is talking about, but didn’t think to apply it in this way. There are some algorithms that he pulls form Graphic Gems IV as well that proved useful.

The one in particular that I liked had to do with a simple way of figuring out if the point is in the polygon. The neat part is that it works for concave and convex polygons, which is useful. I tried it out with a couple of polygons on paper, so if you want to do the same thing, I recommend it… its neat. Draw out your polygon and then pick a point on the inside or outside. Draw the X and Y axis so that the origin is at your test point. Now, pick any point as the start. Add one to a total if you cross one of the axis lines going clockwise and minus one if you cross it counterclockwise. When you reach your starting point, if your total is 4 or -4, your point is inside of the polygon. Neat?!

The code for it is pretty simple as well, the bulk of it being in the case where you cross 2 different axes with the same line. As long as you can figure out which section the vertex point is in, you can figure out (through subtraction) whether or not you have crossed a boundary, and in which direction. Once you have all that put together, it works pretty neatly.

Sprites and stuff… Asteroids redux

May 19, 2008

My daughter, having seen an old game of Asteroids, wondered how it was done… and so did I. I did a bit of research and it really wasn’t that difficult itself, it was just putting a lot of pieces together. So, I started putting those pieces together.

The first part was a sprite engine. Nothing really that difficult, just lists of objects and methods to move those objects and draw those objects. For the sake of ease, I stayed with simple polygons. However, the standard point class didn’t work for floats, so I created a FloatingPoint class and a FloatingPolygon class that dealt with polygons constructed from floats.

Wiring up and engine with that wasn’t bad. Each of the sprites has a position, a velocity, and an id. I set up a form that continuous repainted using double buffering, and each time it paints it moves each sprite then paints each sprite. When moving, some other things can happen, but we will get to that later. Sprites also get to decided if they are going to destruct and return themselves to the pool, or create other sprites.

Movement, now that was where the fun begins. There are two types of movement in the game, angular and vector. Angular was the easiest one to test, so I started with that one. Remembering some high school trigonometry, it was easy to search the net (I love wikipedia) and came up with a simple 2d rotation formula:

newX = oldX * cos( theta ) – oldY * sin( theta )
newY = oldX * sin( theta ) – oldY * cos( theta )

where theta is the angle in radians (Pi / 2) and starts at the classic “90 degree” position rather than the 0/360 position. With this applied to the polygons, we can rotate them and present them to the user. That being done, we now have a way to orient our objects. Next, a way to make them move.

Movement isn’t that bad, we just supply a delta X and a delta Y which will be applied to the object, and with some hints on how to handle the boundary conditions, we are done, right? Nope. Constant movement is that simple, but the trick lies in calculating the correct values. If we use a simplified form of the above equation we get:

velocity-x = size * cos ( theta )
velocity-y = size * sin ( theta )

Basically, if you are oriented at theta radians and you want to move, you need to accelerate. If you add the above components to your velocity components, you will get direction heading in the direction that you are pointed.

More next time on collision detection.

Options for Animations using C# Attributes, Delegates, and Reflection

May 12, 2008

You would think I would be proud of my success yesterday and stopped there… and you would be wrong. Once I got the BooleanAnimationOptionAttribute done, I wanted to convert the rest of the options classes for the three animations to the new format. I created a RangedIntegerAnimationOptionAttribute which allows you to specify a default and a min/max which was useful, and then I created a StringCollectionAnimationOptionAttribute to allow me to load in a list of strings (for browser) and then subclasses that using a delegate to provide one StringCollection that would make sure they were valid Urls.

Now, the base of the screensaver class is built from the ground up to support multiple monitors, mostly so I can use it at work and see it if I have one of my monitors switched away to another system. There, delegates are used to communicate between the individual forms and the controller to make sure that if one stops, they all stop. That was pretty much piecing things together from scraps thanks to Google. This was pretty much copied and changed when I needed a way for the panels to talk to the configuration form and let it know that something in the panel had changed and we should show the apply/reset buttons. This time, I simply called it a ValidateSettingString and wired it into the XmlSettings class so that I could provide a validation method when loading the settings from the settings file. Worked pretty much off the bat.

Based on what I have seen so far, I like delegates. Essentially they are interfaces at the method level, and they define a contract that you can pass into a specific method. That is very useful in some cases. Also, creating anonymous methods to pass in as delegate parameters is occasionally useful, but I still prefer to pass in a normal method from a class to make sure I can check it out nicely and document it.

Up to this point, it was pretty easy and I had almost everything in the screensaver translated over to the new way, and it is slick. What was ugly before, declaration in one place, loading in another, and saving in a third, is now.


///
/// Size of the cells that we are representing.
///
[RangedIntegerAnimationOption(30, MinimumCellSize, MaximumCellSize)]
public int SizeOfCells { get; set; }

The nice part about this is that it keeps all of the pertinent information in one place. I placed the minimum and maximum for the ranged integers as public constants so the forms can pick up that information and use them for the numeric up/down controls. I have toyed with eliminating that and figuring out some way to grab the min/max from the declaration itself, but no dice so far.

Now, the final thing left was to handle the array of PerScreenOptions for the Swarm animation, as I had it set up to work per screen and each screen configurable separately. This is where the headaches began and the research started back up. Before, I had nice solid information about the types and default values and it was relatively easy. Now, I have to figure out how many items, store them, load them, and default them. The big piece: given an array of a given class, how do I figure out what item are in there and deal with the array itself.

The first part was easy: create a new NestedArrayAnimationOptionAttribute and assign it to the array I wanted to serialize to the settings file. In both my AutoLoadOptions and AutoSaveOptions, if I encounter that attribute, I need to go to a new method that is specifically going to be written to deal with arrays.

So dealing with the save first, I need to get a handle on the array to interrogate it: This proved simple:

// Figure out which array to deal with. Once we do that,
FieldInfo memberAsField = nextDiscovery.MemberAttachedTo as FieldInfo;
System.Array arrayToProcess = (System.Array)memberAsField.GetValue(this);

This was possible as all arrays in C# are descended from the System.Array class and it provides a useful manner in which to deal with the arrays disregarding type. After getting that, its a simple loop to go through each of the elements of the array to interrogate each one. System.Array has a nice GetValue method to let you grab the element at a given point in the array, and after that its pretty simple, reusing the exploration that we had in the first place, but providing the instance of the array element instead of the class in which the array is.

Now that we have a way of looking at all of the elements, just have to do some bookkeeping to update the elements in the settings file. After doing some quick experimentation, it was easier to remove all of the array elements than trying to get other permutations right, so the first thing in the method is to call the XmlSettings class to do just that. Then when we are going through each element in the array, make a call down to a new method in XmlSettings to make sure we have a node set up to contain the settings for that element. That required some reworking in the lower levels, but nothing really serious. After that, we pass the node for the element to the ApplySettings routines, and we are done. For all of that, we end up with a nicely organized array indexed class representation.


<Swarm>
<Item Name="MultipleDistinctScreens" Value="True" />
<Array Name="_screenOptions">
<Item Index="0">
<Item Name="SwarmsToShow" Value="3" />
<Item Name="InitialVelocity" Value="9" />
<Item Name="ColorCycleInSeconds" Value="1" />
<Item Name="BeeCount" Value="49" />
<Item Name="GlitterActive" Value="True" />
</Item>
</Array>
</Swarm>

Now on to the load. I knew this would be the hard one from the beginning. For the save, we had an established set of information that we wanted to persist. For the load, we have XML and we need to change it from data in the XML to fields and properties in the element of the array. This was bound to be at least a bit more difficult.

The first part was pretty easy… come up with an instance of the element we are trying to create:

// Figure out what the object we are creating is, and make sure we have a constructor for it.
String typeName = memberAsField.FieldType.FullName;
typeName = typeName.Substring(0, typeName.Length - 2);
Type arrayObjectType = Type.GetType(typeName);
Type[] noParameters = new Type[0];
ConstructorInfo arrayObjectConstructor = arrayObjectType.GetConstructor(noParameters);

We already have the information on the name of the item we want to load, and we take off the final [] to get the root instance. After that, a bit of magic to use reflection to get the object’s constructor. While it is true I could stand to have a bit more error checking around this, its okay for now.


List listOfObjects = new List();
Object nextItem = arrayObjectConstructor.Invoke(noParameters);
List listOfAttributes =
AttributeHelper.SearchForFieldsWithAttribute
(nextItem);
listOfAttributes.AddRange(AttributeHelper.searchForPropertiesWithAttribute
(nextItem));

Basically, create a list of objects that we will later put into our array and then create a sample object. We need this sample object as our routines for discovering our attributes rely on having an instance and its easier to do this than to rewrite for a type and maintaining two paths.

From here, its mostly the same as before. Given the list from above, we go through it and assign values from the XML into the objects one at a time in a loop. One difference is that we have a minimum number of objects we want to see in the array. Once we are done loading, we just fill up the array until it has the minimum number of objects using a DefaultValueFromAttribute method. This method is virtually identical to the one to fetch from the XML, minus the fetching from the XML. Once that is done, we create an array using System.Array.CreateInstance and dump all of the objects in our collection into the array and we are done.

Testing was pretty simple, and I am going to have to write some good unit tests around it, but they shouldn’t be too bad. The data translation is complicated in places, but pretty straightforward when you think about it from a big picture point of view. From a usability point of view, it makes the creation and maintenance of the options classes for the animations a lot easier and a lot less error prone.

Left to do now, add a bit of validation to make sure we are not applying a OptionAttribute to a type where it is obviously going to blow up. Also, good unit tests around the routine.

Using C# Attributes

May 10, 2008

We have all done it before. As part of some program, we need to load a series of values. In the TNG Screensaver project, for the three base screensavers, I had the following:
SizeOfCells = AnimationSettings.FetchSetting(AnimationName, "SizeOfCells", 30);
ShowMazeGeneration = AnimationSettings.FetchSetting(AnimationName, "ShowMazeGeneration", false);
ShowMazeSolution = AnimationSettings.FetchSetting(AnimationName, "ShowMazeSolution", true);

Pretty basic, but pretty error prone. If I decide to add another option, say the pause time between parts of the animation, I would have to remember to add in the line as above, and another one where I save the options. Is there a better way? In c#, there is… its called an attribute.

To accomplish this, I created a base class for all of the types called AnimationOptionAttribute which is descended from Attribute and defines a single property OptionName to allow us to override the name of the option that we are settings or getting. I then created a new class BooleanAnimationOptionAttribute
which looks as follows:
/// <summary>
/// Class to represent a decorator attribute for boolean animation options.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple=false )]
class BooleanAnimationOptionAttribute : AnimationOptionAttribute
{
/// <summary>
/// Keep track of the default value for this attribute.
/// </summary>
public Boolean DefaultValue { get; set; }

/// <summary>
/// Create an attribute as directed by the user.
/// </summary>
/// <param name="optionName">Name of the option we are representing.</param>
/// <param name="defaultValue">Default Boolean value for this item.</param>
public BooleanAnimationOptionAttribute(Boolean defaultValue)
: base()
{
DefaultValue = defaultValue;
}
}

As you can see, this simply defines the attribute, allowing for a default value. This is a good start, but now we have to figure out how to search for that. Luckily, after a google search or two, I stumbled across two separate pages for attributes and reflection. To find the information we need, we are going to have to use reflection to scan an instance of an object for particular entities, in our case fields and properties, and look for any of them that contain one of our attributes. As we will be compiling a list, we need something to store them in.
/// <summary>
/// Data class to hold on to attributes that we have been asked to discover.
/// </summary>
public class DiscoveredAttributes
{
/// <summary>
/// Attribute that we found.
/// </summary>
public Attribute AttributeFound { get; set; }

/// <summary>
/// Member that the attribute was found attached to.
/// </summary>
public MemberInfo MemberAttachedTo { get; set; }
/// <summary>
/// Simple constructor.
/// </summary>
/// <param name="attributeDiscovered">Atttribute that we discovered.</param>
/// <param name="attachedMember">Member it was attached to.</param>
public DiscoveredAttributes(Attribute attributeDiscovered, MemberInfo attachedMember)
{
AttributeFound = attributeDiscovered;
MemberAttachedTo = attachedMember;
}
}

This data class will accomplish our needs, as all we need is what was found and what it was attached to. Now on to our method to discover fields. First, the method.
/// <summary>
/// Search for any fields that have one of the attributes we are looking for attached to it.
/// </summary>
/// <param name="objectToSearch">Object to search for attributes.</param>
/// <returns>List of discovered attributes.</returns>
public static List<DiscoveredAttributes> SearchForFieldsWithAttribute<T>(Object objectToSearch) where T : System.Attribute
{
// We will always return a list, possibly containing only 0 elements.
List<DiscoveredAttributes> returnCode = new List<DiscoveredAttributes>();

// Look for all of the fields within the object, and for each of them look for all of the custom
// properties that match our type and add them to our list.
FieldInfo[] fieldMemberInfos = objectToSearch.GetType().GetFields();
foreach (FieldInfo nextFieldInfo in fieldMemberInfos)
{
foreach (Attribute nextAttribute in nextFieldInfo.GetCustomAttributes(typeof(T), false))
{
DiscoveredAttributes newDiscovery = new DiscoveredAttributes(nextAttribute, nextFieldInfo);
returnCode.Add(newDiscovery);
}
}
return returnCode;
}

When you look at it, a number of things will pop out. The first is that I have chosen to use generics for the method declaration, and I am restricting the type. This is a useful feature of generics that I like about c#. In this case, we only want to use this for Attributes, so I add the restricting that T must be an Attribute. Then we use discovery to find out all of the fields for the object that was passed in. When we find a field, we check the custom attributes for one of the attributes that we are looking for, and if we find it, we add it to the list. I also coded one for properties, as I like using the C# 3.0 automated properties feature, and it is pretty much the same as above.

Now we can see the finish line… we have a way to tag the fields and properties we want to load, we have a way of creating a list of matching attributes, so all we need to do is to apply the information we have collected.
/// <summary>
/// Try and automatically load as many of the options as is possible.
/// </summary>
protected void AutoLoadOptions()
{
// Get a list of all of the attributes that we can find.
List<AttributeHelper.DiscoveredAttributes> listOfAttributes =
AttributeHelper.SearchForFieldsWithAttribute <AnimationOptionAttribute>(this);
listOfAttributes.AddRange( AttributeHelper.SearchForPropertiesWithAttribute<AnimationOptionAttribute>(this));

// Go through our list looking for the fields and properties that we need to fetch the values for.
foreach (AttributeHelper.DiscoveredAttributes nextDiscovery in listOfAttributes)
{
// Assume we have a boolean value for now, and grab the value.
BooleanAnimationOptionAttribute booleanOption = nextDiscovery.AttributeFound as BooleanAnimationOptionAttribute;
Boolean optionValue = AnimationSettings.FetchSetting(AnimationName, nextDiscovery.MemberAttachedTo.Name, booleanOption.DefaultValue);

// figure out if we need to set this to a property or a field.
PropertyInfo memberProperty = nextDiscovery.MemberAttachedTo as PropertyInfo;
if (memberProperty != null)
{
memberProperty.SetValue(this, optionValue,null);
}
FieldInfo memberField = nextDiscovery.MemberAttachedTo as FieldInfo;
if (memberField != null)
{
memberField.SetValue(this, optionValue);
}
}
}

This is currently set up for the Boolean attribute we defined early, but you should get the idea. We go through our list, and figure out what type of an attribute we have. We then grab the default value and use it to grab the information from our lower level routine to fetch our settings. Once we have the value, we can then figure out whether we have a property or a field and set the value into that.

Is this a lot of work? Somewhat. But it simplifies the fetching of the data and makes it so that we tie to location of the field/property to its setting location where it is defined, eliminating the chance that we will forget to load it. Saving the value is pretty similar, and adding should be simple to. This code is part of the TNG screensaver project, so check it out to see how it evolves.

Creating screen animations

May 10, 2008

So, with the first checkins of the TNG screensavers completed, I thought I would start describing how things work.

The base of all of the screensavers is a simple engine that is able to relieve the developer from actually having to implement anything other than the animation and the configuration for the animation.  Right now, there are three Amazing, Browser, and Swarm.

Amazing paints a grid and then creates a one path maze using an algorithm I found through google, and then solves the maze using the same algorithm.  This type of screen saver uses a single bitmap and draws directly to the screen, without any need for double buffering.

Browser takes a really simple concept and brings it to life.  For a project me and my daughter are doing, we needed to display a web page on the screen.  Doing this as a screen saver was a logical extension as the screen saver would be there when we weren’t using the computer, which would be the normal mode of operation.  One of my coworkers asked for a bit of an enhancement, so I made it cycle through a list of sites, enabling him to enter a number of sites that he wants to keep up with.  This is interesting in that the screen is completely covered by a normal windows control that displays the web page, and nothing on the actual screen saver form itself.

Finally, Swarm takes an established algorithm that can be seen on many a linux/unix X windows program.  This animation has a wasp that is followed by a number of bees.  This is an interesting animation in that we totally redraw the screen each time.  While doing this with the Amazing causes flashing, this animation uses that to make sure we have a clear screen each time, meaning that we don’t have to clear the screen each time.  This is a good use of the double buffering routines.

ScreensaverApplication is the base class that gets invoked when the program is run.  This takes care of the command line and makes sure that either the ScreensaverController or the ConfigurationForm is called as needed. The ScreensaverManager is used to contain information about configuration for the program and for each specific animation.

The ScreensaverController is used as an interface to control the multiple monitors that might be encountered for the screensaver.  Depending on the settings in the animation, the controller will either paste together multiple screens and treat them like one, or screen a form for each individual screen.  This information is kept simple for the screensaver, and it gets past the right information for the animation it has requested.  The ScreensaverForm is the base of the actual screensaver itself.  Rather than wiring in a specific implementation, the form uses an interface to animations that provides it with the information it needs.  Anything that is typically tied to the display of the screensaver is handled and abstracted here.

The ConfigurationForm is used to present the user with information on the screensavers in general, and to provide a method to configure the individual animations themselves.  It features a larger preview area than the standard windows preview, and provides a simple panel in which the animations can allow the user to configure them.  This is achieved by providing a panel space in the animation that replaces the panel in the ConfigurationForm.  This seems to work pretty seamlessly and has few problems.


Follow

Get every new post delivered to your Inbox.