![]() |
|
Spaces home Nathan Levesque - Develo...ProfileFriendsBlogMore ![]() | ![]() |
|
|
May 15 The Key is Back in the IgnitionSo to speak.
I've decided to separate XNA content back out to this blog again. Partly because I want separation of content and partly because the other blog is now being aggregated by sites that do not cater to XNA.
More to come.
Using the XNA 3.0 CTP. October 07 RelocationOK, so if you have wondered why this blog has been mostly inactive for a while that is for two reasons: (1) I simply haven't had the time to work with XNA that I wish I had and (2) I've been working on getting my personal site set up so I can begin posting there instead of here. So, turn your browsers to: nathanlevesque.com All content already here will remain and may be reposted on my site in a more formal tutorial format in the future. August 20 Scratch ThatOk, so after some of the interesting developments in XNA over the last few weeks I guess I just can't keep myself away from it. With the release of the new XSI Mod tool I have considered resuming my game development. The primary problem for me in the past was that there was no free 3d package that offered me everything I needed (working UVs, animations, and an easy to use UI). Also, the announcement of the networking APIs for the 360 has me excited as well. Although I don't presently own one, this may very well be the impetus (and excuse) I need to purchase one. However, that will come after the successful development of a PC game. So for now, I'm back with XNA, although I will still be doing ASP.NET and other general .NET stuff in addition to it. August 01 Change of CourseIt's been almost a month since the Dream-Build-Play contest ended and I regrettably was unable to finish my entry to a satisfactory quality in order to submit it on time. However, I would like to congratulate everyone who was able to get their entry in as I have seen many games shown over the last few weeks that I think show much of the effort and determination the XNA community has. Since then, I've had to make a difficult decision to change course on the subject of this blog. I am by trade a web designer/programmer but I like to sample other technologies such as XNA on occasion. I love what Microsoft has done and is continuing to do with the XNA platform but for me it is time to focus on more career-specific goals and this blog is not exempt. I simply do not have the time to focus on continuing to develop career skills and also participate in time-expensive hobbies such as XNA. However, I do not believe my time spent on XNA has been in vain. I have learned much more about game programming in the last few months than I have in the last few years. I have also been able to learn an entirely new programming language, C#, in a matter of 6 months, whereas it took me 6 years to develop my C++ skills to the same level. As a result I've taken on learning ASP .NET which has simply continued to amaze me as to the relative ease of development. My C# skills carry over to this and I am beginning to see my skills build upon each other and expand at an increasing rate. In summation, I'm going to be focusing primarily on ASP .NET news and information and showcasing some of my projects on that front. I will continue to keep an eye on the XNA community and occasionally post items of interest. I would like to return to XNA at some point in the future but at present its best for me to be an observer. I will keep previous posts here for continuity for the community. If at any point anyone has questions or comments about the XNA-related content on this blog don't hesitate to do so as I will continue to respond. Thanks to those who have supported me thus far. :) June 14 Back in the RunningOk, so I've taken the last week to get used to my new Vista computer. So far I love the new operating system and can't wait to get some DX10 games (played the DX10 PC demo of Lost Planet today and it was absolutely great). I'm getting excellent framerates on all of the games I already own too. In the meantime I'm working on yet another rewrite of my game engine. It's getting a little ridiculous to keep rewriting every three weeks or so but I think this is a very robust version. Today I coded my own implementation of the GameScreen idea and integrated it with a post processing batch class. My post processing framework has the ability to basically render any object that implements a interface that has only a Draw method. I'm not sure if I'm going to finish my game in time for the Dream-Build-Play contest deadline, but I'm going to try my best to at least have something remotely playable to submit. ;) June 02 UpdateOk, so at present I am waiting until Monday until the parts arrive for me to assemble a new Vista PC for me. This has been a long time coming and frankly I don't know how I'm going to make it through the weekend since UPS doesn't deliver on the weekend and the package will be sitting not an hour's drive away from here for the next two days! Since my development of my XNA game is on hold until that PC is up and running ( mostly cause I'm sick of developing on 6-year-old DX8 hardware), I've decided to make myself a little project for the weekend and that is the beginnings of a physics component. I've seen this requested on the XNA forums and my plans are that if I get this working and it is somewhere near publishable I will release both source and assemblies for the public to download. As such, I'm taking my time and trying to comment and document as much as I can while still making reasonable progress. So far what I've got going:
I hope to have a video demo up tomorrow night since I'm going to implement some simple BoundingBox collisions first and see how that goes. Keep an eye out for it ;) May 21 Matrix TutorialNot gonna post it in full here cause I'm lazy but I submitted an article at Ziggyware's Introduction to Matrices in XNA
Also I've been rather busy lately with my code, I've once again changed my mind on what I intend to do (I've been working on developing the basics of an engine so far, not worrying about content yet). I'm back to working on an RTS game since I don't feel like dealing with FPS code at the moment. April 26 XNA Refresh Trick #1: Autoformatting Multiple Lines of TextSo by now everyone is very happy I'm sure of the release of XNA Refresh. It comes with a slew of additions to the framework that everyone has been clamoring for. Particularly font, 3d audio, and Model vertex reading support. I've been putting off my GUI because I didn't want to redesign once the XNA team's font support came out, here's the first trick I created, to help myself with my GUI: autoformatting multiple lines of text. If you look into the documentation it says that the new text functionality will go the a new line with the text if the '\n' character is found. However, this makes for some static game design. What if I want the text block to be wider? Well, the way to do this is to add '\n' characters at runtime. Here's the little method I developed to do this: public static void SetTextWidth( ref string text, SpriteFont spriteFont, float width ) { // get a vector representing the size of our string Vector2 textSize = spriteFont.MeasureString( text ); // if text already fits, don't do anything if ( textSize.X < width ) return; // remove existing newline chars in case it has already been formatted text = text.Replace( "\n", "" ); // loop through all characters in string, if a character extends past our width float lineTotal = 0; float wordTotal = 0; int charCount = 0; int i = 0; do { // if we find whitespace, we're reached the end of a word if ( char.IsWhiteSpace( text, i ) ) { // measure the length of the word wordTotal = spriteFont.MeasureString( text.Substring( i - charCount, charCount ) ).X; // if the word extends past our width, we insert // a \n before the word to pop it to the next line if ( ( lineTotal + wordTotal ) > width && lineTotal != 0 ) { text = text.Insert( i - charCount, "\n" ); lineTotal = wordTotal; charCount = 0; } // otherwise the word fits on our current line else { lineTotal += wordTotal + 1; charCount = 0; i++; } } else { charCount++; i++; } } while ( i < text.Length ); } Now this method isn't entirely robust, for instance it won't hyphenate words that are too long to fit on a single line, instead it just prints the whole word out, extendeding past our designated width. Feel free to change this, but for my case I wasn't concerned about being able to print 30 character words correctly (and I hope, netiher are you for your gamer's sake ;) ). Here's a little preview of the results I can get with this method(single string used): April 24 XNA 1.0 Refresh Update Released!The XNA Team announced the release of their Refresh update for XNA today: http://blogs.msdn.com/xna/archive/2007/04/24/xna-game-studio-express-1-0-refresh-released.aspx I've only taken a cursory glance at the changes they've made, and needless to say I'm very pleased. I've already been able to make changes to my code that I've been waiting for this update to make. Particularly of interest to, and many others are the inclusion of text drawing and 3d audio! I'd also suggest taking a good look through the docs, there's a lot of new topics, particularly in the "Programming Guide" section. So, with the addition of the text drawing methods, I'm off to resume work on my GUI! Thank you XNA Team for all your hard work! April 16 A Better GetServiceOk, so recently there's been a lot of major discussion on the XNA forums about GameComponents. Now, I love the idea of having integrated components that automatically get get updated and also drawn in the case of DrawableGameComponent, however, when it comes to accessing the Game class's Services. I also have at issue being able to access said Services in a class that is not a GameComponent. I understand the XNA's team for making the services the way they are, however I don't want to have to derive from GameComponent and add it to the GameComponentCollection every time I want to check to have access to the ContentManager or whatever. For the most part, input components are the only issue that I have with the way Services are set up. This simple class helps both Component and non-Component classes alike. Now, what this code avoids is having to type code like this every time you want to access a Service: ContentManager manager = (ContentManager)Game.Services.GetService( typeof( ContentManager ) ) That can quickly become time consuming and can add to the illegibility of the code, not to mention either having multiple lines of code for one call or having to scroll horizontally a bit. So what I've decided to do is create a simple static class that stores the current game and has a generic method called GetService that functions similarly to Services.GetService(): public static class Component Now, what we do is call Component.SetGame(this); in the Initalize method of our derived game class (Game1 in a new project). Then every time we need a service in a non-component class, we simply call: ContentManager manager = Component.GetService<ContentManager>(); Now this might not be the most elegant solution, but it appears to work well enough in my code. April 12 XNA Octree TutorialThis tutorial may be a bit wordy, but I've tried to give a fair amount of detail as to what is going on in the code. If you're fairly familiar with XNA code, particularly BoundingBoxes, you can probably just skim the code itself and understand it just as quick if not quicker than I explain it. This is still very fresh code, not thoroughly tested, but I feel confident enough to share it. For everyone else, here we go! First of all, what exactly is an octree? An octree is a spatial partitioning system that divides a cube recursively into eight equally sized cubes until each cube contains a specified number of polygons or objects. This tree can then be used to quickly determine visibility or to quickly rule out objects for physics purposes. For the purposes of XNA, I've designed my system to be used on a per-object basis. Since this tutorial is being done with XNA in mind, we're going to try to use as much of XNA's built-in functionality to ease design time. First of all we need to define what the structure of the nodes or "leaves" in this tree. This will be similar to the structure you might see in a scene graph, however each node can represent multiple objects and will always either no child nodes or 8. public class OctreeLeaf { private const int maxobj = 8; private List<SceneObject> containedObjects; Here we've begun by defining our class, OctreeLeafwhich has the following fields:
For the purposes of this tutorial I am going to assume that the SceneObject has a property of type BoundingBox named BoundingBox Our Constructor is passed a BoundingBox that specifies its size and initializes fields accordingly. We don't know if we have any children yet, so we initialize childLeaves to null. I also added the following properties to the class: public List<Geometry> ContainedObjects { get { return containedObjects; } set { containedObjects = value; } } Next we need to provide some functionality to add 8 child leaves and size them so they are each exactly half the size of our current containerBox. This vector math is rather dirty, and I'm probably missing an easier way to do this, but as of now it does the job: protected void Split() { Vector3 half = ContainerBox.Max - ContainerBox.Min; Vector3 halfx = Vector3.UnitX * half; Vector3 halfy = Vector3.UnitY * half; Vector3 halfz = Vector3.UnitZ * half; ChildLeaves.Add( new OctreeLeaf( new BoundingBox( ContainerBox.Min, ContainerBox.Min + half ) ) ); ChildLeaves.Add( new OctreeLeaf( new BoundingBox( ContainerBox.Min + halfx, ContainerBox.Max - half + halfx ) ) ); ChildLeaves.Add( new OctreeLeaf( new BoundingBox( ContainerBox.Min + halfz, ContainerBox.Min + half + halfz ) ) ); ChildLeaves.Add( new OctreeLeaf( new BoundingBox( ContainerBox.Min + halfx + halfz, ContainerBox.Max - halfy ) ) ); ChildLeaves.Add( new OctreeLeaf( new BoundingBox( ContainerBox.Min + halfy, ContainerBox.Max - halfx - halfz ) ) ); ChildLeaves.Add( new OctreeLeaf( new BoundingBox( ContainerBox.Min + halfy + halfx, ContainerBox.Max - halfz ) ) ); ChildLeaves.Add( new OctreeLeaf( new BoundingBox( ContainerBox.Min + halfy + halfz, ContainerBox.Max - halfx ) ) ); ChildLeaves.Add( new OctreeLeaf( new BoundingBox( ContainerBox.Min + half, ContainerBox.Max ) ) ); } I made this a protected method because we never call this outside the class, only within our method that distributes the objects. This method grabs a Vector3 that represents the half size of the cube and then creates width, height and length vectors (halfx, halfy, and halfz, respectively) by multiplying by the three unit vectors. The rest is pretty straightforward, if a bit confusing. Basically I've hardcoded the creation of each half-sized box. Probably a better way, but for now it suffices. Now, we need to give our OctreeLeaf class the ability to distribute objects: public void Distribute() { if ( containedObjects.Count > maxobj ) { Split(); for ( int i = ContainedObjects.Count; i > 0; i-- ) { foreach ( OctreeLeaf leaf in ChildLeaves ) { if ( leaf.ContainerBox.Contains( ContainedObjects[i].BoundingBox ) == ContainmentType.Contains ) { leaf.ContainedObjects.Add( ContainedObjects[i] ); containedObjects.Remove( ContainedObjects[i] ); break; } } } foreach ( OctreeLeaf leaf in ChildLeaves ) { leaf.Distribute(); } } } Anyway, first the method checks to see if the number of objects the current leaf contains is more than the maximum allows. If it is, then we need to split this leaf by calling our Split() method. Next we loop through every item in the scene backwards. We do this because later we may call containedObjects.Remove() and we would end up trying access objects that are don't exist at the end of the list, and we would also skip the object after the one we remove. Going backwards through the list with a manual for loop avoids this. Then for each child leaf of the current one we check to see if the BoundingBox of only that leaf intersects the BoundingBox of the current object. If it does, then we add it to the ContainedObjects list of that leaf and remove it from the list of the current leaf. Then we break from the foreach loop since we've found a leaf that contains the object. Objects that intersect more than one child leaf will not be passed on to the children and instead stay in the current leaf so that we don't get any popping of visibility at the edges of the screen. Finally, we loop through every child leaf and call its Distribute() method. Now, we finally have our objects distributed throughout our scene. Now, we need some way to figure out how to determine whether the current leaf in within our view frustum. Well fortunately for us this is very simple code thanks to the efforts of the XNA team! We're going to use a nifty little class named BoundingFrustum. BoundingFrustum represents quite simply a frustum! Best yet, we can create one that represents the view frustum of our camera simply by passing the product of the view and projection matrices as follows: BoundingFrustum boundingFrustum = new BoundingFrustum( View * Projection ); I've created a Camera class with a property named BoundingFrustum that returns this very value. Keep in mind that boundingFrustum needs to get updated whenever either the view or project matrices change. Now, here's our method that determines draws our visible objects recursively: public void DrawVisible( GameTime gameTime, BoundingFrustum boundingFrustum ) { foreach ( SceneObject item in containedObjects ) { item.Draw( gameTime ); } foreach ( OctreeLeaf leaf in ChildLeaves ) { if ( leaf.ContainerBox.Intersects( boundingFrustum ) ) leaf.DrawVisible( gameTime, boundingFrustum ); } } What this method does first is it draws the objects in the current leaf. Then it checks each of the child leaves for intersection with the BroundingFrustum. If it does intersect, meaning that the child leaf is within our sight, we call its DrawVisible() method, otherwise the leaf and thus all its child leaves and all objects contained therein, are not visible to us so they never get drawn. Finally we have the basic functionality of object distribution and visiblity determination. Now all we have to do is create a Octree class to drive this tree: public class Octree : OctreeLeaf { public Octree() : base( new BoundingBox() ) { } public void Bounds() { foreach ( SceneObject item in ContainedObjects) { ContainerBox = BoundingBox.CreateMerged( ContainerBox, item.BoundingBox ); } } public void Distribute( ref List<SceneObject> scene ) { Pretty simple, huh? This derives from OctreeLeaf, because it is basically the root node of the tree, but we need some extra functionality in it. Lets look at the Bounds method. This method takes every object that the root node (Octree class) contains and uses BoundingBox.CreateMerged() to resize the current ContainerBox to include the BoundingBox of each object. What this does is define the initial size that our root BoundingBox needs to be in order to contain the entire scene. Next the Distribute method. Note this method overloads not overrides the Distribute method. This is because we need to pass our scene into the method. We then assign scene to ContainedObjects. Then we call Bounds and finally the base class OctreeLeaf's Distribute method. This sets into action the recursive distribution of our scene we set up earlier. Finally we have the DrawVisible method, another overload because we need to pass the current Camera. Then we call the base class's DrawVisible method and pass the camera's BoundingFrustum. That's pretty much it to a relatively simple implementation of an octree. It is optimized for a scene with static objects at the moment and has no support for adding objects. I will probably be adding support in the future, but for the sake of this tutorial, we have the basic functionality we sought. Hopefully you learned a little more about XNA through this tutorial as I did coding it. I would love to hear your comments, so please feel free to post them! UpdateOk, so its been a while since I've posted anything, but thats because I've been hard at work, here's a quick list of what I've done:
March 21 No More ScenegraphAs I mention previously, I decided to change my game engine over to a non-scenegraph scene implementation. Now, mostly the reason we would want to preserve scenegraph functionality is to have the ability to easily parent objects for pivot point or whatnot. However, we can still retain this functionality, with even greater flexibility and extendable. The implementation I have now is basically a SceneManager DrawableGameComponent that has a List<> of SceneItems in the scene. Each SceneItem is passed a reference to this manager so that it can access other items in the scene. For SceneItem I've gone ahead and defined properties that return the Scale, Rotation, Translation, and concatenated Local Matrix. I've also defined one that returns a reference to the SceneManager so that we can access this and thus access other SceneItem if we have a reference to an item. Now we have the basis of scene items being able to access each other and grab whatever Matrix they need. Now what needs to be implemented is a way of creating a relationship such as parenting. What I've done is created an interface that we will implement in each of our relationship classes (from here on I will refer to these relationships as "constraints"): public interface IConstraint The overridable method we see here that we will need to implement passes a reference to the item that is going to be parented, and the current GameTime, just in case we ever need it. So now what we do is add some code to our SceneItem class to support the IConstraint system of relationships: First, we add some members: protected List<IConstraint> _constraints = null; The List<> is fairly self-explanatory, its just a list of all the constraints this object has on it and the bool value makes sure that we only call our UpdateConstraints method once as seen below, in case we have a long chain of objects that are constrained: public virtual void UpdateConstraints( GameTime gameTime ) Now, this is one very important thing to note: UpdateConstraints should only be called after the local matrix has been computed for every item in the scene, which in my case I do in a plain old void Update(GameTime) method. The reason for this is that we need to make sure that if one object is parented to another object and that second object has been rotated, we want to make sure the rotation has been applied before we concatenate matrices. Finally we get to code our first constraint class. First we derive from Constraint and implement the Evaulate method. The way we implement for a parent constraint would be as follows:
public class ParentConstraint : IConstraint } Yup, that's it. What we're doing here is storing an index for the item we will parent to and a weight that determines how much we will apply the parenting. That's right, we can now ease in and out of parenting by simply ramping up or down the _weight value! See how this is much more flexible than what a ordinary scenegraph would have allowed us to do? Now, we have to make sure that we call the UpdateConstraints method of the item we're parented to before we do anything because if we don't, our first item may be positioned incorrectly as objects further up the chain may not have been updated yet. I hope that this has inspired some people to move away from the mess of scenegraphs and explore alternate avenues of storing scene data ingame. Further extensions to this constraint system you could do:
There's probably much more that you could do with this system and I'd love to hear from you if you March 18 UpdatesFirst off I updated the code in my last blog. The functionality hasn't changed, but I've changed it to a static class so that its easier to access instead of a GameComponent/Service. Second, I've changed the theme on the blog so the code should be easier to read now. :) March 17 Eureka! Keyboard Input!
I just finished rewriting my keyboard input component after I had a sudden epiphany while coding my game state code. Basically, what I had been working on achieving was a way to have events fire for a single key press so that classes throughout my game could create event handlers and handle only the specific key press or key release that they were interested in. This seems like a long way to go just for getting some input when I could have just used Keyboard.GetState();, but the advantage I see is that I only need to check once to see if a certain key has been pressed or released and then my code will call every event handler that has been assigned to that event. Plus it has the advantage of keeping my input logic completely separate from the rest of my game logic. Now someone may ask "isn't that going to be more trouble if you have to check for multiple keys?" The answer to that is an emphatic yes, which is why I've exposed the current KeyboardState with a property. However, most of the time I personally am going to be checking only one key, such as "is the player hitting the 'W' key so I can move the player forward?" So, basically what I finally figured out what to do was create a class called KeyEvents that contained keydown and keyup event and matching methods to fire those events and then create an Dictionary<Keys, KeyEvents>. Looking back on this its so simple I don't know why I didn't see it to begin with, probably the 20 hour days I've been spending with XNA this last week. Edit: I've updated the code to make this a static class, since its simple and it won't bother the game much to have an instance automatically created when the program loads. #region License March 16 UpdateSo I've been coding pretty hard the last week or so while I'm on spring break. So far I've managed to code:
March 09 Welcome!Greetings! I've started this blog as a place to showcase my work on my XNA game that I'm developing for the Dream Build Play Competition. The game is a multiplayer third person shooter game. I'll make some of the game features more readily apparent as time progresses (especially once it gets close to the competition deadline). For the time being I will be posting occasional screen captures, possibly videos, and share some of my code. |
|
|