XNA - 再談Xml
xml又來了!~這次講深入一點
前兩篇關於XML的文章都只做比較簡單的部份
但是真的遊戲要用XML設定的話,內容應該是很有變化的
接下來就講講我做過的一些用法
首先定義兩個Data物件
1: public class ImageData {
2: public string Name;
3: public string TexturePath;
4: public int DestWidth;
5: public int DestHeight;
6:
7: [ContentSerializerIgnore]
8: public Texture2D Texture2DImage;
9: }
10:
11: public class AnimationData : ImageData {
12: public bool IsLoop;
13: public List<Frame> Frames = new List<Frame>();
14:
15: }
16:
17: public class Frame {
18: public Rectangle FrameRect;
19: public int Time;
20:
21:
22: public class FrameReader : ContentTypeReader<Frame> {
23:
24: protected override Frame Read(ContentReader input, Frame existingInstance) {
25: Frame frame = existingInstance;
26: if (frame == null) {
27: frame = new Frame();
28: }
29:
30: frame.FrameRect = input.ReadObject<Rectangle>();
31: frame.Time = input.ReadInt32();
32:
33: return frame;
34: }
35: }
36: }
ImageData是用來放圖片資訊的,
AnimationData是放動畫資訊,
Frame是存放每一格畫面的顯示位置和時間,而我特別把Frame的Reader寫成巢狀類別,
這會影響到Writer的GetRuntimeReader內容,後面會說!
另外關於動畫,請參考這篇
很明顯的,動畫一定也是一張圖,只是他多了畫出的位置和每格的時間,所以這裡用繼承!
而xml就會編輯成下面的樣子
1: <?xml version="1.0" encoding="utf-8" ?>
2: <XnaContent>
3: <Asset Type="XMLLibrary.AnimationData">
4: <Name>小紅圈</Name>
5: <TexturePath>Texture\小紅圈</TexturePath>
6: <DestWidth>32</DestWidth>
7: <DestHeight>32</DestHeight>
8: <IsLoop>true</IsLoop>
9: <Frames>
10: <Item>
11: <FrameRect>0 0 32 32</FrameRect>
12: <Time>80</Time>
13: </Item>
14: <Item>
15: <FrameRect>33 0 32 32</FrameRect>
16: <Time>80</Time>
17: </Item>
18: <Item>
19: <FrameRect>66 0 32 32</FrameRect>
20: <Time>80</Time>
21: </Item>
22: <Item>
23: <FrameRect>99 0 32 32</FrameRect>
24: <Time>80</Time>
25: </Item>
26: <Item>
27: <FrameRect>132 0 32 32</FrameRect>
28: <Time>80</Time>
29: </Item>
30: <Item>
31: <FrameRect>165 0 32 32</FrameRect>
32: <Time>80</Time>
33: </Item>
34: <Item>
35: <FrameRect>198 0 32 32</FrameRect>
36: <Time>80</Time>
37: </Item>
38: <Item>
39: <FrameRect>231 0 32 32</FrameRect>
40: <Time>80</Time>
41: </Item>
42: <Item>
43: <FrameRect>262 0 32 32</FrameRect>
44: <Time>80</Time>
45: </Item>
46: </Frames>
47: </Asset>
48: </XnaContent>
再來就是重點的Writer和Reader了
首先從ImageData寫起
1:
2: [ContentTypeWriter]
3: public class ImageDataWriter : ContentTypeWriter<ImageData> {
4:
5: protected override void Write(ContentWriter output, ImageData value) {
6: output.Write(value.Name);
7: output.Write(value.TexturePath);
8: output.Write(value.DestWidth);
9: output.Write(value.DestHeight);
10: }
11:
12: public override string GetRuntimeReader(TargetPlatform targetPlatform) {
13: return "XMLLibrary.ImageDataReader, XMLLibrary";
14: }
15: }
16:
17: public class ImageDataReader : ContentTypeReader<ImageData> {
18:
19: protected override ImageData Read(ContentReader input, ImageData existingInstance) {
20: ImageData data = existingInstance;
21: if (data == null) {
22: data = new ImageData();
23: }
24:
25: data.Name = input.ReadString();
26: data.TexturePath = input.ReadString();
27: data.DestWidth = input.ReadInt32();
28: data.DestHeight = input.ReadInt32();
29:
30: data.Texture2DImage = input.ContentManager.Load<Texture2D>(data.TexturePath);
31:
32: return data;
33: }
34: }
Writer沒有什麼特別的,就不多說了
倒是Reader有在載入的時候順便把圖也載近來
所以用到30行的ContentManager
接著看看Reader
1:
2: [ContentTypeWriter]
3: public class ImageDataWriter : ContentTypeWriter<ImageData> {
4:
5: protected override void Write(ContentWriter output, ImageData value) {
6: output.Write(value.Name);
7: output.Write(value.TexturePath);
8: output.Write(value.DestWidth);
9: output.Write(value.DestHeight);
10: }
11:
12: public override string GetRuntimeReader(TargetPlatform targetPlatform) {
13: return "XMLLibrary.ImageDataReader, XMLLibrary";
14: }
15: }
16: [ContentTypeWriter]
17: public class AnimationDataWriter : ContentTypeWriter<AnimationData> {
18: ImageDataWriter imageDataWriter = null;
19:
20: protected override void Initialize(ContentCompiler compiler) {
21: imageDataWriter = compiler.GetTypeWriter(typeof(ImageData))
22: as ImageDataWriter;
23:
24: base.Initialize(compiler);
25: }
26:
27: protected override void Write(ContentWriter output, AnimationData value) {
28: output.WriteRawObject<ImageData>(value as ImageData, imageDataWriter);
29: output.Write(value.IsLoop);
30: output.WriteObject(value.Frames);
31: }
32:
33: public override string GetRuntimeReader(TargetPlatform targetPlatform) {
34: return "XMLLibrary.AnimationDataReader, XMLLibrary";
35: }
36: }
37:
38: [ContentTypeWriter]
39: public class FrameWriter : ContentTypeWriter<Frame> {
40:
41: protected override void Write(ContentWriter output, Frame value) {
42: output.WriteObject<Rectangle>(value.FrameRect);
43: output.Write(value.Time);
44: }
45:
46: public override string GetRuntimeReader(TargetPlatform targetPlatform) {
47: return "XMLLibrary.Frame+FrameReader, XMLLibrary";
48: }
49: }
來看看AnimationDataWriter,他裡面有一個ImageDataWriter,在初始函式取得ImageDataWriter物件,
在28行呼叫的WriteRawObject就需要用到他,因為我們的AnimationData是繼承ImageData,
在XML裡面就一定要把父類別的資料寫在前面,
WriteRawObject 會把接下來的內容當做ImageData來讀取。
再來是30和35行,讀進一個物件,不是基本型態的話就需要這樣讀,
最後要講的就是40行,GetRuntimeReader這個函式是要告訴電腦要執行哪一個reader
所以40行回傳的就是"命名空間.物件名稱+巢狀物件名稱, 組件名稱",
必須回傳類別的組件限定名稱,可參考這裡
最後範例程式並沒有什麼畫面可以看,請設定中斷點查看載入的物件內容吧!