First of all to force an intermediate serializer work we need to create some class which will be a pattern. But we must understand that the XML files will be inside the content project so we need a reference from the content project to our pattern. But if we will make class (pattern) inside our main project which contains our Game.cs it will has a circular dependency because our main project already referenced to the content project. Thus we must to add a new XNA game library (library's name GameObject). After that we are going to make pattern (class) inside our library. It looks like following:
namespace GameObjects
{
public class GameSprite
{
public string Name { get; set; }
public Vector2 Position { get; set; }
public string TexturePath { get; set; }
}
}
Very simple class will contain all necessary data about future sprite. After that we must to make our XML file which will contain GameSprite data we put in the future into a field of type GameSprite. The XML file looks:
<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
<Asset Type="GameObjects.GameSprite">
<Name>Apple</Name>
<Position>320 160</Position>
<TexturePath>red_apple</TexturePath>
</Asset>
</XnaContent>
Now we are going to add reference to our XNA library which contains GameSprite class from our main project and content project as well. Then we add new class Sprite.cs which will serve as our final sprite with all logic and texture. For the example I added only Texture to that class and Draw method:
using GameObjects;
namespace WindowsGameHelp2
{
public class Sprite
{
public GameSprite Data { get; private set; }
public Texture2D Texture { get; private set; }
public Sprite(string path, ContentManager content)
{
// Here we are loading our XML file.
Data = content.Load<GameSprite>(path);
Texture = content.Load<Texture2D>(Data.TexturePath);
}
public void Draw(SpriteBatch sprite_batch)
{
sprite_batch.Draw(Texture, Data.Position, null, Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);
}
}
}
Finally how looks our Game.cs of a main project:
using GameObjects;
namespace WindowsGameHelp2
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Sprite apple;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
//@"Fruits\Apple" is a path to our XML file.
apple = new Sprite(@"Fruits\Apple", Content);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.White);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
apple.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
The output:

You can download my example here
EDIT:
Arrays can be serialized and deserialized as well. I added int[] Nutrients
to GameSprite as shown below:
namespace GameObjects
{
public class GameSprite
{
public string Name { get; set; }
public Vector2 Position { get; set; }
public int[] Nutrients { get; set; }
public string TexturePath { get; set; }
}
}
Then I added some new fruits, here is how look our XML files:
<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
<Asset Type="GameObjects.GameSprite">
<Name>Banana</Name>
<Position>160 160</Position>
<Nutrients>10 15 25 35 78</Nutrients>
<TexturePath>banana</TexturePath>
</Asset>
</XnaContent>
<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
<Asset Type="GameObjects.GameSprite">
<Name>Orange</Name>
<Position>480 160</Position>
<Nutrients>40 30 10 30 80</Nutrients>
<TexturePath>orange</TexturePath>
</Asset>
</XnaContent>
And you asked how would you use GameSprite[]
or List<GameSprite>
. Here is how:
namespace GameObjects
{
public class FruitShop
{
public List<GameSprite> Fruits { get; set; }
}
}
Above I made kinda new class which will contain all our fruits. I put it into our XNA game library and named it FruitShop. Thus I can show you now how it will look in our future XML:
<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
<Asset Type="GameObjects.FruitShop">
<Fruits>
<Item>
<Name>Orange</Name>
<Position>480 160</Position>
<Nutrients>40 30 10 30 80</Nutrients>
<TexturePath>orange</TexturePath>
</Item>
<Item>
<Name>Apple</Name>
<Position>320 160</Position>
<Nutrients>50 20 20 30 70</Nutrients>
<TexturePath>red_apple</TexturePath>
</Item>
<Item>
<Name>Banana</Name>
<Position>160 160</Position>
<Nutrients>10 15 25 35 78</Nutrients>
<TexturePath>banana</TexturePath>
</Item>
</Fruits>
</Asset>
</XnaContent>
Then I made some Shop.cs in our main XNA project which will consume our FruitShop.cs data:
using GameObjects;
namespace WindowsGameHelp2
{
public class Shop
{
private SpriteFont font;
public FruitShop Data { get; private set; }
public List<Texture2D> Texture { get; private set; }
public Shop(string path, ContentManager content)
{
font = content.Load<SpriteFont>(@"Fonts\Default");
Data = content.Load<FruitShop>(path);
Texture = new List<Texture2D>();
for (byte i = 0; i < Data.Fruits.Count; i++)
Texture.Add(content.Load<Texture2D>(Data.Fruits[i].TexturePath));
}
public void Draw(SpriteBatch sprite_batch)
{
for (byte i = 0; i < Data.Fruits.Count; i++)
{
sprite_batch.Draw(Texture[i], Data.Fruits[i].Position, null, Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);
sprite_batch.DrawString(font, "|Name: " + Data.Fruits[i].Name + "|", Data.Fruits[i].Position + new Vector2(6, 128), Color.Black, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);
for (byte x = 0; x < Data.Fruits[i].Nutrients.Length; x++)
sprite_batch.DrawString(font, "|Nutrient: " + Data.Fruits[i].Nutrients[x].ToString() + "|", Data.Fruits[i].Position + new Vector2(6, 128 + 20 * (x + 1)), Color.Black, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);
}
}
}
}
Finally how looks our Game.cs:
using GameObjects;
namespace WindowsGameHelp2
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Shop shop;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
shop = new Shop(@"Shops\FruitShop", Content);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.White);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
shop.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
And output:

You can download edited project WindowsGameHelp2 (edit1) here.
In addition if you want to know how to deserialize list of lists or list of dictionaries then this link might be helpful.