XNA Creators Club Online
Page 1 of 1 (8 items)
Sort Posts: Previous Next

Content and build/runtime pairs of classes

Last post 05-07-2008 4:10 PM by Tinibou. 7 replies.
  • 05-05-2008 4:19 PM

    Content and build/runtime pairs of classes

    Hello everyone, I wanted to have a little more information concerning this post  by Shawn in one of the topic :


    PreachingLlama:
    My first issue is that I would need a "SpriteNode" that holds a reference to TextureContent for the import/processing, then one holds a reference to Texture2D when I load the scene content.


    Yes, that's a common pattern when using the Content Pipeline. You'll see that a lot of our samples on this site have pairs of related classes, one for use at build time and another runtime version shaped basically the same, but with some of the member types changed. The framework itself does the same thing, providing pairs of types eg. ModelContent/Model, VertexBufferContent/VertexBuffer, etc.

    If you have many such types and want to share code between the build and runtime versions, you can implement them as a generics and then just specialize with either T=Texture2DContent or T=Texture2D.

    Partial classes can also be a big help here. You can write the bulk of your class into a single .cs file that is shared between your pipeline assembly and runtime game assembly, then add extra game-only methods in a second .cs file that is only added on the game side.


    I'm having exactly the same problem. I'm trying to have something called a SpriteManager (something that reads a XML content file that contains a list of Sprite) and then something called an EntityManager that will follow the same system to store all the entities objects I can place in a future map object...

    And I try to get everything running with XML content, ContentReaders and so on. Well, I quickly faced several problems that I solved on my own and then I got to the solution of having differents classes such as SpriteContent and Sprite, Entity and EntityContent...

    But I must have missed something to get all the things running because XNA wants me to define a SpriteContentReader (quite logic, because my XML file have SpriteContent nodes). Well, can I not define SpriteContent nodes and have a SpriteReader to get Sprite objects instead of SpriteContent objects ?

    Well, if you have a few minutes to help me :) Thanks.
  • 05-05-2008 6:07 PM In reply to

    Re: Content and build/runtime pairs of classes

    Would it be the role of the ContentProcessor ? I thought it was useless in my case because I'm using classic files (XML) but it seems I was wrong ?

    The ContentProcessor is the one which will get my XXXContent into a XXX object ? But ContentProcessor is dedicated to an entire file, huh because it is associated to the XML file in the Property Dialog ? Hooonn... :S
  • 05-05-2008 7:24 PM In reply to

    Re: Content and build/runtime pairs of classes

    What do your ContentTypeWriter objects look like for your classes? If you're using the pattern where buildtime/runtime objects are split up, you will need to override the ContentTypeWriter's GetRuntimeType and GetContentReader properties. (iirc, can't remember the names off the top of my head)  These properties tell the content pipeline what type the file should be loaded as, and what reader should be used to load.
    Eli Tayrien - XNA Framework Developer
  • 05-06-2008 2:50 AM In reply to

    Re: Content and build/runtime pairs of classes

    My ContentTypeWriter looks like this :
    [ContentTypeWriter]
    public class Sprite2DWriter : ContentTypeWriter<Sprite2DContent>
    {
    protected override void Write(
    ContentWriter output,
    Sprite2DContent value)
    {
    output.Write(value.TextureName);
    output.WriteObject<Nullable<Rectangle>>(value.SpriteRectangle);
    }

    public override string GetRuntimeReader(
    TargetPlatform targetPlatform)
    {
    return typeof(Sprite2DReader).AssemblyQualifiedName;
    }
    }

    I tried to replace the last line with typeof() with a string containing the type of my reader and so on (following examples found on the forum) but it did not change anything. A Sprite2DContent reader is expected at runtime.

    My reader is :
    public class Sprite2DReader : ContentTypeReader<Sprite2D>
    {
    protected override Sprite2D Read(ContentReader input,
    Sprite2D existingInstance)
    {
    return new Sprite2D(input);
    }
    }


    And I try to get my XML infos with :
    Content.Load<Dictionary<string, Sprite2D>>(assetName);


    Hope it'll help :)
  • 05-06-2008 3:31 AM In reply to

    Re: Content and build/runtime pairs of classes

    It seems I got all the stuff working :) I did not pay attention to each word of your message and then I finally noticed my Sprite2DWriter lacked the override of the GetRuntimeType method.

    So I have the following classes :
    • XXX
    • XXXContent
    • XXXWriter : ContentTypeWriter<XXXContent>
    • XXXReader : ContentTypeReader<XXX>
    Does it seem correct for you ?

    You also said that "if I wanted to use this pattern (...)" does it mean that this is not the only way to do it (I know that I could sequentially read my XML) ? Which is the best way ? Using pairs of classes each time ? Shawn also mentionned partial classes but I can't see where it helps because you must have two object types here ?

    And another question if I may ask :) Is there a way to define classes attributes as optional in the reading/writing process ? I mean, I know the [ContentSerializerIgnore] tag but can I write my XML so that I could "omit" a tag and the class attribute would be null ? And if the tag exists, the value is correctly retrieved ?
  • 05-06-2008 3:41 PM In reply to

    Re: Content and build/runtime pairs of classes

    Tinibou:

    So I have the following classes :
    • XXX
    • XXXContent
    • XXXWriter : ContentTypeWriter<XXXContent>
    • XXXReader : ContentTypeReader<XXX>
    Does it seem correct for you ?


    Looks right to me.

    Tinibou:

    You also said that "if I wanted to use this pattern (...)" does it mean that this is not the only way to do it (I know that I could sequentially read my XML) ? Which is the best way ? Using pairs of classes each time ?


    Sorry, I didn't mean to imply that there was a better way :) As with most coding problems, there is probably another way to do what you're doing. The pattern of runtime/design-time class pairs is pretty tried and true in the content pipeline. I'd recommend sticking with it.

    Tinibou:

    Shawn also mentionned partial classes but I can't see where it helps because you must have two object types here ?


    What Shawn suggests is that you could have a partial class defined in both the content pipeline and in your main game assembly. Let's say thats in Foo.cs. Then, you could have Foo's run-time specific stuff in a file called FooRuntime.cs, which would add additional functionality. If necessary, design-time specific stuff could be in a file called FooDesigntime.cs, which is only added to the content pipeline assembly. This may not be the best pattern for your game, though - you'll have to decide that for yourself.

    Tinibou:

    And another question if I may ask :) Is there a way to define classes attributes as optional in the reading/writing process ? I mean, I know the [ContentSerializerIgnore] tag but can I write my XML so that I could "omit" a tag and the class attribute would be null ? And if the tag exists, the value is correctly retrieved ?


    I'm not sure what you're trying to do. Could you be more specific? Are you trying to change the way your XML is read into the content pipeline during a build, or are you trying to change the way the final binary asset is written and loaded?

    Eli Tayrien - XNA Framework Developer
  • 05-06-2008 5:13 PM In reply to

    Re: Content and build/runtime pairs of classes

    Well, to be more specific, I have in fact an EntityManager that stores Entities (basic and common informations about them). My idea would be to define then a XML map file where I define an Entity node with a string child node for the entity ID (to retrieve the object in the EntityManager) and other nodes to parameterize the entity.

    For example, in the map file :

    <Value Type="Entity">
    <EntityID>5</EntityID>
    <Parameters>(...)</Parameters>
    </Value>

    And in the XML that defines the Entities Library for the Manager :

    <Value Type="Entity">
    <States>
    <State>
    <ID>5</ID>
    <AnimationInfos>(...)</AnimationInfos>
    </State>
    (...)
    </States>
    </Value>


    So I have two ways to create an Entity object. One for the EntityManager and another one when reading the map. Well, I think I can do it with two different content class and the appropriate readers/writers.

    Anyway, since my last post, I went on and I now have problems at runtime. I think there's something I did not understand... When you have a XXX class and a XXXContent class for example, both classes must have the same type attributes ? I mean, can't I have a class which would store a list of sprites IDs and another one which would store a concrete sprites list ? Can't I say when XNA reads a given node to read the node with another type ? Well I'm not very clear here... But I thought it was the way the pattern worked ?


    The only thing that worked until now is a Sprite2D class, with a Sprite2DContent class and a XML file that contains a list of  Sprite2DContent nodes that define both TextureName and Rectangle attributes of the class.  But the classes share the same type of attributes (that is to say a string and a Rectangle). What if my real class Sprite would contain only a Texture2D and a Rectangle ? When must I have to tell that the TextureName will be change to a loaded Texture2D ? (that's only an example).  
  • 05-07-2008 4:10 PM In reply to

    Re: Content and build/runtime pairs of classes

    It's finally OK. The problem was mainly a misunderstanding of how the ContentReaders and ContentWriters exactly work and how I can use them in my case :)

    Thanks.
Page 1 of 1 (8 items) Previous Next
var gDomain='m.webtrends.com'; var gDcsId='dcschd84w10000w4lw9hcqmsz_8n3x'; var gTrackEvents=1; var gFpc='WT_FPC'; /*<\/scr"+"ipt>");} /*]]>*/
DCSIMG