`
andyjackson
  • 浏览: 58575 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

XNA学习笔记6-源码分析

阅读更多
ContentManage作为Game类的一个非常重要的助手,负责个所有Content的加载和管理工作。从Texture、SpritFont到Model、Effect都是通过该类的Load方法获得。Load方法的部分代码如下:
public virtual T Load<T>(string assetName){
   object obj2;
   if (this.loadedAssets.TryGetValue(assetName, out obj2)){
      if (!(obj2 is T)){
          throw new ContentLoadException("......");
       }
       return (T) obj2;
   }
   T local = this.ReadAsset<T>(assetName, null);
   this.loadedAssets.Add(assetName, local);
   return local;
}
首先检查loadedAssets的Dictionary中是否有key为assetName的元素。如果存在,说明之前已经加载进来了,只需要将该元素的值返回;否则,调用ReadAsset方法,从内容管道加载。
protected T ReadAsset<T>(
   string assetName,Action<IDisposable>recordDisposableObject){
   using (Stream stream = this.OpenStream(assetName)){
      using (ContentReader reader = 
        new ContentReader(this, stream, assetName, recordDisposableObject)){
          return reader.ReadAsset<T>();
      }
   }
}
调用OpenStream方法将二进制流从本地加载进来,然后调用ContentReader的ReadAsset方法,并返回其结果。
internal T ReadAsset<T>(){
   T local;
   try{
      int sharedResourceCount = this.ReadHeader();
      T local2 = this.ReadObject<T>();
      this.ReadSharedResources(sharedResourceCount);
      local = local2;
   }catch (IOException exception){
        throw this.CreateContentLoadException("....");
   }
   return local;
}
这段代码很容易读懂,首先调用ReadHeader方法,读取数据流的头部,然后调用ReadObject读取数据流实体,整个加载的关键就在这两个方法上(尤其是后一个方法)。

      msdn上是这样解释ContentReader类的"A worker object that implements most of ContentManager.Load."也就是说它完成了几乎所有的Load过程。ReadHeader方法结构看了一下:
    private int ReadHeader()
    {
      int typeCount = base.Read7BitEncodedInt();
      this.typeReaders = ContentTypeReaderManager.ReadTypeManifest(typeCount, this);
      int num2 = base.Read7BitEncodedInt();
      if (num2 > 0)
      {
        this.sharedResourceFixups = new List<Action<object>>[num2];
        for (int i = 0; i < num2; i++)
        {
          this.sharedResourceFixups[i] = new List<Action<object>>();
        }
      }
      return num2;
    }
ContentTypeReaderManager类是一个对ContentTypeReader管理的一个类,里面有3个Dictionary用于存放已加载进来的ContentTypeReader。这段代码主要是通过读取数据流检测当前数据流的ContentTypeReader,然后缓存等作用(即预处理的工作)。

      ReadObject<T>()方法最终调用的是自己类的InvokeReader<T>方法:
    private T InvokeReader<T>(ContentTypeReader reader, object existingInstance)
    {
      T local;
      ContentTypeReader<T> reader2 = reader as ContentTypeReader<T>;
      if (reader2 != null)
      {
        T local2 = (existingInstance == null) ? default(T) : ((T) existingInstance);
        local = reader2.Read(this, local2);
      }
      else
      {
        object obj2 = reader.Read(this, existingInstance);
        if (obj2 != null)
        {
          if (!(obj2 is T))
          {
            throw this.CreateContentLoadException(".......");
          }
          local = (T) obj2;
        }
        else
        {
          local = default(T);
        }
      }
      if (existingInstance != null)
      {
        if (!object.ReferenceEquals(existingInstance, local))
        {
          throw new InvalidOperationException(".......");
        }
        return local;
      }
      if (!reader.TargetIsValueType)
      {
        IDisposable disposable = local as IDisposable;
        if (disposable == null)
        {
          return local;
        }
        if (this.recordDisposableObject != null)
        {
          this.recordDisposableObject(disposable);
          return local;
        }
        this.contentManager.RecordDisposableObject(disposable);
      }
      return local;
    }
这段代码应该还是比较好看懂,首先的一个if分子说明,如果当前的ContentTypeReader对象是ContentTypeReader<T>类型的,那么不为空,执行if块,执行ContentTypeReader<T>的Read(ContentReader input, T existingInstance)方法,否则进入else快,执行ContentTypeReader的Read(ContentReader input, object existingInstance)方法。注意ContentTypeReader<T>类是ContentTypeReader的直接子类,他重写了父类的Read(ContentReader input, object existingInstance)方法:
  public abstract class ContentTypeReader<T> : ContentTypeReader
  {
    protected ContentTypeReader() : base(typeof(T)){}
    
    protected internal override object Read(ContentReader input, object existingInstance)
    {
      T local;
      if (existingInstance == null)
      {
        local = default(T);
      }
      else
      {
        if (!(existingInstance is T))
        {
          throw input.CreateContentLoadException(".....");
        }
        local = (T) existingInstance;
      }
      return this.Read(input, local);
    }
    
    protected internal abstract T Read(ContentReader input, T existingInstance);
  }
}
这段代码中,前面的方法,重写了父类对应的方法,但是最终返回的是this.Read(input, local),该方法是一个抽象的方法,由其子类完成。现在条理清楚了,关键就在于所有子类的此方法。下面仅仅列出几个关键的子类:
namespace Microsoft.Xna.Framework.Content
{
    using Microsoft.Xna.Framework.Graphics;
    using System;

    internal class EffectReader : ContentTypeReader<Effect>
    {
        private static Microsoft.Xna.Framework.Graphics.EffectPool sharedEffectPool;

        protected internal override Effect Read(ContentReader input, Effect existingInstance)
        {
            int count = input.ReadInt32();
            return new Effect(input.GraphicsDevice, input.ReadBytes(count), CompilerOptions.None, EffectPool);
        }

        internal static Microsoft.Xna.Framework.Graphics.EffectPool EffectPool
        {
            get
            {
                if (sharedEffectPool == null)
                {
                    sharedEffectPool = new Microsoft.Xna.Framework.Graphics.EffectPool();
                }
                return sharedEffectPool;
            }
        }
    }
}
namespace Microsoft.Xna.Framework.Content
{
    using Microsoft.Xna.Framework.Graphics;

    internal class TextureReader : ContentTypeReader<Texture>
    {
        protected internal override Texture Read(ContentReader input, Texture existingInstance)
        {
            return existingInstance;
        }
    }
}
namespace Microsoft.Xna.Framework.Content
{
    using Microsoft.Xna.Framework.Graphics;

    internal class ModelReader : ContentTypeReader<Model>
    {
        protected internal override Model Read(ContentReader input, Model existingInstance)
        {
            return Model.Read(input);
        }
    }
}

      看了这么多,不难发现用户也可以自定义自己的ContenTypeReader:
    public class TriangleTypeReader : ContentTypeReader<Triangle>
    {
        protected override Triangle Read(ContentReader input, Triangle existingInstance) 
        {
            Vector3 p0 = input.ReadObject<Vector3>(); 
            Vector3 p1 = input.ReadObject<Vector3>(); 
            Vector3 p2 = input.ReadObject<Vector3>(); 
            
            Triangle newTriangle = new Triangle(p0, p1, p2); 
            return newTriangle; 
        }
    }
具体解释呆讨论完ContentTypeWriter之后再讲~~~
分享到:
评论

相关推荐

    XNA4.0学习指南--源代码

    通过这个“XNA4.0学习指南--源代码”压缩包,学习者可以研究和分析各种示例代码,了解如何应用上述技术来构建实际游戏。实践中,你可以学习如何加载资源、处理用户输入、创建游戏循环、实现基本的物理系统,以及如何...

    XNA Collision Series 1 - 2D Rectangle Collision

    XNA Tutorial Collision Series 1 - 2D Rectangle Collision

    XNA游戏开发->国际象棋源码

    XNA利用C#编程语言,结合DirectX图形库,使得游戏开发更加容易上手,尤其对于初学者来说是个很好的学习平台。 【国际象棋】是一种双人对弈的策略棋类游戏,起源于6世纪的印度,后来在欧洲发展并逐渐演变成现代的...

    XNA学习资料-XNA入门指南2.0

    6. **声音和音乐**:XNA提供了处理音频的能力,可以播放音乐和音效,包括加载、控制音量、循环播放等。 7. **碰撞检测**:游戏中的交互往往需要进行碰撞检测,以判断物体是否相撞。XNA提供了基本的几何形状碰撞检测...

    XNA学习资料,XNA

    在XNA学习资料中,"XNA入门指南-第一章.pdf"可能涵盖了XNA的基础概念和环境搭建。这章通常会介绍以下几个知识点: 1. **XNA概述**:解释XNA的起源、目标和适用场景,以及与.NET Framework的关系,帮助初学者理解...

    XNA入门指南-第一章

    #### 三、学习XNA所需技能 - **C#编程基础**:虽然本书不是编程入门书籍,但对于C#有一定的了解是非常必要的。C#是XNA开发的主要语言,熟悉C#语法和编程技巧对于理解XNA框架至关重要。 - **数学基础知识**:游戏...

    XNA2版俄罗斯方块源码

    通过对XNA 2.0版俄罗斯方块源码的分析,我们不仅可以掌握这个游戏的实现细节,还能学习到游戏开发的基本原理和XNA框架的使用。虽然XNA已经不再得到官方支持,但它的设计理念和许多技术仍对现代游戏开发有所启发,是...

    XNA学习指南_中文_附源代码[XNA学习必备]

    **XNA学习指南详解** XNA,全称为Xbox Next Generation APIs,是由微软推出的一款用于游戏开发的框架,特别适合初学者和有经验的游戏开发者。它提供了完整的工具集,包括编程环境、图形库和音频处理功能,使得创建...

    《XNA4.0学习指南》书籍源码

    通过分析和运行这些源码,读者不仅可以了解XNA的基本用法,还能掌握游戏开发中的常用技巧和最佳实践。对于初学者,这是一次宝贵的学习机会,能够帮助他们快速上手并理解游戏开发的核心概念。对于有一定经验的开发者...

    xna3.0的一个源码

    【XNA 3.0 源码解析】 ...通过分析和学习XTank的源码,我们可以掌握XNA 3.0的基本使用,包括游戏对象的管理、用户输入处理、2D图形绘制、音效集成以及可能的简单网络通信。这将为后续更复杂的游戏开发打下坚实基础。

    xna4.0 中文 + 源码

    提供的压缩包文件包括一本名为《XNA4.0学习指南》的PDF教程,可能涵盖了上述各个知识点的详细讲解,以及一个名为`LearningXNA4.0.rar`的源码包,这将帮助读者通过实践深入理解XNA4.0的开发过程。阅读这些资源,...

    XNA实现Billboard示例源码

    通过分析和理解这个BillboardSample源码,开发者可以学习到如何在XNA框架中有效地实现面向摄像机的2D图像,这对于游戏开发和3D可视化应用都是一个非常实用的技术。此外,这个示例也可以作为进一步学习XNA图形编程、...

    xna_4.0 学习指南(xna learning)源码(全,45.9M)

    《XNA 4.0 学习指南》源码是一份详尽的教育资源,专为开发者提供关于微软XNA框架的深入理解与实践操作。XNA是Microsoft开发的一个游戏开发平台,它简化了游戏在Windows、Xbox 360和Zune等设备上的创建过程。这份源码...

    xna 爆炸效果 源码

    在游戏开发领域,XNA框架是一个非常受欢迎的工具,它为开发者提供了构建Windows、Xbox 360以及Zune平台游戏的能力。本资源聚焦于一个特定的技术点——使用XNA实现2D爆炸效果。2D爆炸效果在很多游戏场景中都非常常见...

    cocos2d-x for xna 2D游戏引擎源码

    cocos2d-x for xna 2D游戏引擎源码 xna cocos2d-x是一个用C#编写的2D游戏引擎,基于[cocos2d-x][1]和使用MIT 协议。 引擎由 [cocos2d-x][1] 和 [OpenXLive][2] 联合开发。 cocos2d-x for xna is a 2D game ...

    wp7 xna 投石车大战源码

    总的来说,"wp7 xna 投石车大战源码"是一个很好的学习资源,它不仅提供了实际的编程实践,而且覆盖了游戏开发中的多个关键概念,对于希望进入游戏开发领域的初学者来说,是非常有价值的。通过对这个游戏的代码进行...

    Direct 3D与XNA游戏开发源码

    6. **声音与音频**:XNA支持音频播放,源码可能涵盖如何添加背景音乐、音效,以及如何与游戏事件同步。 7. **输入管理**:游戏通常需要响应用户输入,如键盘、鼠标或游戏手柄。源码可能展示了如何使用XNA处理这些...

    xna Game studio 小游戏源码

    通过阅读和分析这些源码,我们可以深入理解如何在XNA中实现这些功能。 1. 游戏循环:每个游戏都有一个主循环,通常包括Update和Draw两个阶段。Update负责处理游戏逻辑,如物体移动、碰撞检测;Draw则负责渲染游戏...

Global site tag (gtag.js) - Google Analytics