-
|
|
Noob content pipeline stuff... :: Updated and Solved woot
|
UPDATED: new problem at the bottom
Ok. I just started with my first endeavor into content pipeline work, anyways, I have a few problems/questions about these things.
First, the compiler said anything I load through the content pipeline needs to have a parameterless constructor, can I still overload the constructor?
Second, the xml keeps wanting me to put in a bunch of extra variables that I don't need/want to put in for all my public get/set methods. Should I just remove the get/set methods I have that seem to be what it's asking for, or is there a way to have the public methods without needing to include them in the xml?
Here's the majority of the code.
Object (just added the constructors... the rest is how it was when I tested it, and it worked somewhat):
| public class WorldObject |
| { |
| Vector2 position; |
| int objSize; |
| int width; |
| int height = 20; |
| Rectangle hitBox; |
| Rectangle spriteRect = new Rectangle(0, 0, 25, 20); |
| |
| public WorldObject() |
| { |
| |
| } |
| |
| public WorldObject(Vector2 posit, int size) |
| { |
| position = posit; |
| objSize = size; |
| width = 20 * objSize; |
| height = 20; |
| hitBox = new Rectangle((int)position.X, (int)position.Y, |
| objSize * 20, 20); |
| } |
| |
| public Vector2 Position |
| { |
| get{ return position; } |
| set { position = value;} |
| } |
| |
| public int ObjSize |
| { |
| get{ return objSize; } |
| set{ |
| objSize = value; |
| width = 20 * objSize; |
| height = 20; |
| hitBox = new Rectangle((int)position.X, (int)position.Y, |
| objSize * 20, 20); |
| } |
| } |
| |
| public int Width |
| { |
| get{ return width; } |
| set{ width = value; } |
| } |
| |
| public int Height |
| { |
| get { return height; } |
| set { height = value; } |
| } |
| |
| public Rectangle HitBox |
| { |
| get { return hitBox; } |
| set { hitBox = value; } |
| } |
| } |
The Writer (the commented out "WriteObject"s in the write method were in the code that worked somewhat):
| [ContentTypeWriter] |
| public class WorldObjectWriter : ContentTypeWriter<WorldObject> |
| { |
| protected override void Write(ContentWriter output, WorldObject value) |
| { |
| output.WriteObject<Vector2>(value.Position); |
| output.WriteObject<int>(value.ObjSize); |
| /**output.WriteObject<int>(value.Width); |
| output.WriteObject<int>(value.Height); |
| output.WriteObject<Rectangle>(value.HitBox);*/ |
| |
| } |
| |
| public override string GetRuntimeReader(TargetPlatform targetPlatform) |
| { |
| // TODO: change this to the name of your ContentTypeReader |
| // class which will be used to load this data. |
| return "WorldRuntimeWindows.WorldObjectReader, WorldRuntimeWindows"; |
| } |
| |
| /** public override string GetRuntimeType(TargetPlatform targetPlatform) |
| { |
| return typeof(WorldObject).AssemblyQualifiedName; |
| }*/ |
| } |
| } |
| |
The Reader (commented out bits were in the code that worked):
| public class WorldObjectReader : ContentTypeReader<WorldObject> |
| { |
| protected override WorldObject Read(ContentReader input, WorldObject existingInstance) |
| { |
| WorldObject obj = new WorldObject(); |
| |
| obj.Position = input.ReadObject<Vector2>(); |
| obj.ObjSize = input.ReadObject<int>(); |
| |
| |
| /** obj.Width = 20 * obj.ObjSize; |
| obj.Height = 20; |
| obj.HitBox = new Rectangle((int)obj.Position.X, (int)obj.Position.Y, |
| obj.ObjSize * 20, 20);*/ |
| |
| return obj; |
| } |
| } |
| } |
| |
XML:
| <?xml version="1.0" encoding="utf-8" ?> |
| <XnaContent> |
| <Asset Type="WorldRuntimeWindows.WorldObject"> |
| <Position>400 500</Position> |
| <ObjSize>15</ObjSize> |
| <Width>1</Width> |
| <Height>1</Height> |
| <HitBox>1 1 1 1</HitBox> |
| </Asset> |
| </XnaContent> |
| |
If anyone could check it over and give some tips on what would fix my problems, or just general tips about how I did it, it would be greatly apreciated. I want to get the content pipeline working before I do any more work on the game.
Thanks much! If anyone needs more code, let me know!
|
|
-
-
- (72)
-
premium membership
-
Posts
48
|
Re: Noob content pipeline stuff...
|
Hi there,
First question: you can overload the constructor but the XML deserializer will only ever use the default constructor.
Second question: if you don't want a property to be serialized, just add [ContentSerializerIgnore] above the property definition:
| [ContentSerializerIgnore] |
| public Vector2 Position |
| { |
| get{ return position; } |
| set { position = value;} |
| } |
There are loads of other options available and Shawn has written some pretty excellent blog entries on the IntermediateSerializer which you can find here.
Cheers,
Rod
|
|
-
|
|
Re: Noob content pipeline stuff...
|
I think that covers everything!
does the code itself look decent otherwise?
|
|
-
-
- (72)
-
premium membership
-
Posts
48
|
Re: Noob content pipeline stuff...
|
Hi Michael,
Code looks fine to me although I personally would use the overloaded Write methods of ContentWriter and the corresponding read method of ContentReader for reading & writing the C# built-in & other supported types. Makes the code a bit easier to read and there's less typing of course ;-)
For example:
| // Writer |
| output.WriteObject<Vector2>(value.Position); |
| output.WriteObject<int>(value.ObjSize); |
| // equivalent to |
| output.Write(value.Position); |
| output.Write(value.ObjSize) |
| |
| // Reader |
| obj.Position = input.ReadObject<Vector2>(); |
| obj.ObjSize = input.ReadObject<int>(); |
| // equivalent to |
| obj.Position = input.ReadVector2(); |
| obj.ObjSize = input.ReadInt32(); |
Cheers,
Rod
|
|
-
|
|
Re: Noob content pipeline stuff...
|
I did not even know those existed. Do they function pretty much the same either way?
|
|
-
-
- (72)
-
premium membership
-
Posts
48
|
Re: Noob content pipeline stuff...
|
I don't know the exact internal workings but I would expect that the various Write methods are more efficient than WriteObject as WriteObject will need to instantiate a ContentWriter first of all which then does the writing. WriteObject also writes out a type identifier before handing over to the ContentWriter so this will not work as expected:
| // Writer |
| output.WriteObject<int>(value.ObjSize); |
| |
| // Reader |
obj.ObjSize = input.ReadInt32(); // will read type identifier, not value
|
To sum up, use the overloaded Write methods when you can and WriteObject for all other cases.
Hope that makes sense!
Cheers,
Rod
|
|
-
|
|
Re: Noob content pipeline stuff...
|
that sounds good, but what do you mean by " will read type identifier, not value" about the input.readint32().?
that's the only thing I didn't get.
|
|
-
-
- (72)
-
premium membership
-
Posts
48
|
Re: Noob content pipeline stuff...
|
Hi Michael,
When you use WriteObject, it writes out an extra 4-byte type identifier first to the .XNB file before writing the actual content. So when you use WriteObject<int>(value.IntValue) you will get T1 T2 T3 T4 V1 V2 V3 V4 written out to the .XNB file where Tx is each byte of the type identifier and Vx is each byte of the int value we are writing.
On the other hand, using the overloaded Write method that takes an int as a parameter e.g. Write(value.IntValue) we only get the V1 V2 V3 V4 bytes written out to the .XNB file - no type identifier is written out.
Going back to my previous example:
| // Writer |
| output.WriteObject<int>(value.ObjSize); |
| // .XNB file now contains T1 T2 T3 T4 V1 V2 V3 V4 |
| |
| // Reader |
| // ReadInt32 dodesn't require type information and only reads 4 bytes - which will be the type identifier, not the value |
| obj.ObjSize = input.ReadInt32(); |
| |
Hope that clears up any confusion.
Cheers,
Rod
|
|
-
|
|
Re: Noob content pipeline stuff...
|
Alright, new problem. I got the content writers and readers working the way I want them to, but now I want to load a subclass of that class, and I put the readers/writers in the same file as the other readers/writers. When I tried to run it, it tells me it can't find the reader I set up for the subclass. Anyways, here's the code. Any help would be great. If you need any other code, just ask.
| public class VerticalObjectReader : ContentTypeReader<VerticalObject> |
| { |
| protected override VerticalObject Read(ContentReader input, VerticalObject existingInstance) |
| { |
| VerticalObject obj = new VerticalObject(); |
| |
| obj.Position = input.ReadVector2(); |
| obj.ObjSize = input.ReadInt32(); |
| //obj.Width = input.ReadObject<int>(); |
| //obj.Height = input.ReadObject<int>(); |
| //obj.HitBox = input.ReadObject<Rectangle>(); |
| |
| |
| /** obj.Width = 20 * obj.ObjSize; |
| obj.Height = 20; |
| obj.HitBox = new Rectangle((int)obj.Position.X, (int)obj.Position.Y, |
| obj.ObjSize * 20, 20);*/ |
| |
| return obj; |
| } |
| } |
| |
| public class WorldObjectReader : ContentTypeReader<WorldObject> |
| { |
| protected override WorldObject Read(ContentReader input, WorldObject existingInstance) |
| { |
| WorldObject obj = new WorldObject(); |
| |
| obj.Position = input.ReadVector2(); |
| obj.ObjSize = input.ReadInt32(); |
| //obj.Width = input.ReadObject<int>(); |
| //obj.Height = input.ReadObject<int>(); |
| //obj.HitBox = input.ReadObject<Rectangle>(); |
| |
| |
| /** obj.Width = 20 * obj.ObjSize; |
| obj.Height = 20; |
| obj.HitBox = new Rectangle((int)obj.Position.X, (int)obj.Position.Y, |
| obj.ObjSize * 20, 20);*/ |
| |
| return obj; |
| } |
| } |
Any help would be great.
|
|
-
-
- (10483)
-
Team XNA
-
Posts
7,929
|
Re: Noob content pipeline stuff...
|
Not enough info to diagnose problem. What exactly is the exception message? What is the exception callstack?
XNA Framework Developer -
blog - homepage
|
|
-
|
|
Re: Noob content pipeline stuff...
|
Shawn Hargreaves:Not enough info to diagnose problem. What exactly is the exception message? What is the exception callstack?
I have the exception all pulled up. Is there a way to get a text version of the exception to copy here or tell me which spots in the Exception snapshot you need?
edit: found it... It was right out in the open... :-/
Microsoft.Xna.Framework.Content.ContentLoadException was unhandled Message="Error loading \"Levels\\\\Level1\". Cannot find ContentTypeReader for WorldRuntimeWindows.VerticalObject." Source="Microsoft.Xna.Framework" StackTrace: at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.GetTypeReader(Type targetType, ContentReader contentReader) at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.GetTypeReader(Type targetType) at Microsoft.Xna.Framework.Content.ListReader`1.Initialize(ContentTypeReaderManager manager) at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.ReadTypeManifest(Int32 typeCount, ContentReader contentReader) at Microsoft.Xna.Framework.Content.ContentReader.ReadHeader() at Microsoft.Xna.Framework.Content.ContentReader.ReadAsset[T]() at Microsoft.Xna.Framework.Content.ContentManager.ReadAsset[T](String assetName, Action`1 recordDisposableObject) at Microsoft.Xna.Framework.Content.ContentManager.Load[T](String assetName) at Game.Game1.LoadContent() in D:\Student Data\Downloads\Documents\Visual Studio 2005\Projects\WindowsGame1\WindowsGame1\Game1.cs:line 80 at Microsoft.Xna.Framework.Game.Initialize() at Game.Game1.Initialize() in D:\Student Data\Downloads\Documents\Visual Studio 2005\Projects\WindowsGame1\WindowsGame1\Game1.cs:line 59 at Microsoft.Xna.Framework.Game.Run() at Game.Program.Main(String[] args) in D:\Student Data\Downloads\Documents\Visual Studio 2005\Projects\WindowsGame1\WindowsGame1\Program.cs:line 14
I hope that makes sense to someone else :S
|
|
-
-
- (10483)
-
Team XNA
-
Posts
7,929
|
Re: Noob content pipeline stuff...
|
Can I see more code, in particular your writers?
it looks like these objects are stored in a list? Can I also see the class (and reader+writer) that contains this list?
XNA Framework Developer -
blog - homepage
|
|
-
|
|
Re: Noob content pipeline stuff...
|
Sure thing.
Here's the writer:
| [ContentTypeWriter] |
| public class WorldObjectWriter : ContentTypeWriter<WorldObject> |
| { |
| protected override void Write(ContentWriter output, WorldObject value) |
| { |
| output.Write(value.Position); |
| output.Write(value.ObjSize); |
| /**output.WriteObject<int>(value.Width); |
| output.WriteObject<int>(value.Height); |
| output.WriteObject<Rectangle>(value.HitBox);*/ |
| |
| } |
| |
| public override string GetRuntimeReader(TargetPlatform targetPlatform) |
| { |
| // TODO: change this to the name of your ContentTypeReader |
| // class which will be used to load this data. |
| return "WorldRuntimeWindows.WorldObjectReader, WorldRuntimeWindows"; |
| } |
| |
| /** public override string GetRuntimeType(TargetPlatform targetPlatform) |
| { |
| return typeof(WorldObject).AssemblyQualifiedName; |
| }*/ |
| } |
| |
| [ContentTypeWriter] |
| public class VerticalObjectWriter : ContentTypeWriter<VerticalObject> |
| { |
| protected override void Write(ContentWriter output, VerticalObject value) |
| { |
| output.Write(value.Position); |
| output.Write(value.ObjSize); |
| /**output.WriteObject<int>(value.Width); |
| output.WriteObject<int>(value.Height); |
| output.WriteObject<Rectangle>(value.HitBox);*/ |
| |
| } |
| |
| public override string GetRuntimeReader(TargetPlatform targetPlatform) |
| { |
| // TODO: change this to the name of your ContentTypeReader |
| // class which will be used to load this data. |
| return "WorldRuntimeWindows.WorldObjectReader, WorldRuntimeWindows"; |
| } |
| |
| /** public override string GetRuntimeType(TargetPlatform targetPlatform) |
| { |
| return typeof(WorldObject).AssemblyQualifiedName; |
| }*/ |
| } |
I'm really sorry if this comes down to me just missing something stupid.
Here's the code that loads the list (stuff in between cut out)
Declaration of list: List<WorldObject> Platforms = new List<WorldObject>();
Loading in "LoadContent" method: Platforms = Content.Load < List<WorldObject>>("Levels//Level1");
WorldObject Class (I have no problems loading this):
| using System; |
| using System.Collections.Generic; |
| using Microsoft.Xna.Framework; |
| using Microsoft.Xna.Framework.Audio; |
| using Microsoft.Xna.Framework.Content; |
| using Microsoft.Xna.Framework.GamerServices; |
| using Microsoft.Xna.Framework.Graphics; |
| using Microsoft.Xna.Framework.Input; |
| using Microsoft.Xna.Framework.Net; |
| using Microsoft.Xna.Framework.Storage; |
| |
| namespace WorldRuntimeWindows |
| { |
| public class WorldObject |
| { |
| protected Vector2 position; |
| protected int objSize; |
| protected int width; |
| protected int height = 20; |
| protected Rectangle spriteRect = new Rectangle(0, 0, 25, 20); |
| protected Rectangle hitBox; |
| |
| public WorldObject() |
| { |
| width = 20 * objSize; |
| height = 20; |
| hitBox = new Rectangle((int)position.X, (int)position.Y, |
| objSize * 20, 20); |
| } |
| |
| public WorldObject(Vector2 posit, int size) |
| { |
| position = posit; |
| objSize = size; |
| width = 20 * objSize; |
| height = 20; |
| hitBox = new Rectangle((int)position.X, (int)position.Y, |
| objSize * 20, 20); |
| } |
| |
| public Vector2 Position |
| { |
| get{ return position; } |
| set { position = value;} |
| } |
| |
| public virtual int ObjSize |
| { |
| get{ return objSize; } |
| set{ |
| objSize = value; |
| width = 20 * objSize; |
| height = 20; |
| hitBox = new Rectangle((int)position.X, (int)position.Y, |
| objSize * 20, 20); |
| } |
| } |
| |
| [ContentSerializerIgnoreAttribute] |
| public int Width |
| { |
| get{ return width; } |
| set{ width = value; } |
| } |
| |
| [ContentSerializerIgnoreAttribute] |
| public int Height |
| { |
| get { return height; } |
| set { height = value; } |
| } |
| |
| [ContentSerializerIgnoreAttribute] |
| public Rectangle HitBox |
| { |
| get { return hitBox; } |
| set { hitBox = value; } |
| } |
| } |
| } |
| |
VerticalObject:
| using System; |
| using System.Collections.Generic; |
| using Microsoft.Xna.Framework; |
| using Microsoft.Xna.Framework.Audio; |
| using Microsoft.Xna.Framework.Content; |
| using Microsoft.Xna.Framework.GamerServices; |
| using Microsoft.Xna.Framework.Graphics; |
| using Microsoft.Xna.Framework.Input; |
| using Microsoft.Xna.Framework.Net; |
| using Microsoft.Xna.Framework.Storage; |
| |
| namespace WorldRuntimeWindows |
| { |
| public class VerticalObject : WorldObject |
| { |
| public VerticalObject() |
| { |
| width = 20 * objSize; |
| height = 20; |
| hitBox = new Rectangle((int)position.X, (int)position.Y, |
| 20, objSize * 20); |
| } |
| |
| public VerticalObject(Vector2 posit, int size) |
| { |
| position = posit; |
| objSize = size; |
| width = 20 * objSize; |
| height = 20; |
| hitBox = new Rectangle((int)position.X, (int)position.Y, |
| 20, objSize * 20); |
| } |
| |
| override public int ObjSize |
| { |
| get { return objSize; } |
| set |
| { |
| objSize = value; |
| width = 20 * objSize; |
| height = 20; |
| hitBox = new Rectangle((int)position.X, (int)position.Y, |
| 20, objSize * 20); |
| } |
| } |
| } |
| } |
| |
|
|
-
-
- (10252)
-
premium membership
MVP
-
Posts
6,495
|
Re: Noob content pipeline stuff...
|
Umm, take a look at the GetRuntimeReader for VerticalObject.
Jim Perry - Microsoft XNA MVP If people spent a minute searching the forums and reading the FAQs before posting I'd be out of a job. Got some XNA Game Studio/XNA Framework development info to share with the community? Put it on the XNA Wiki. Please mark posts as Answers or Good Feedback when appropriate.
|
|
-
|
|
Re: Noob content pipeline stuff...
|
Jim Perry:Umm, take a look at the GetRuntimeReader for VerticalObject.
told you it was something stupid! thanks much.
BLAHHHHHH! I spent hours looking through that code :(
such is the life of a computer programmer :(
|
|
|