ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
在前文中,我们已经实现了加载复杂的3D模型并在空间中进行控制,通常在一个游戏程序中,这样的3D模型有很多,如果每一个都在场景中去绘制,那么Draw()方法就会很复杂了,而且也不利于代码的复用。更好的方式是把这艘飞船实现为GameComponent,而且是DrawableGameComponent。接下来我们就来构造飞船组件。 首先为项目中添加一个新元素,使用XNA中的GameComponent,在生成的代码中做如下修改: public class Ship :Microsoft.Xna.Framework.DrawableGameComponent 即将GameComponent改为DrawableGameComponent,然后加入Draw()方法。 public override void Draw(GameTimegameTime) 同样使用Model model;和Matrix[] modelTransforms;两个成员变量用于保存模型和骨骼数据。并在Initialize()方法中完成加载,代码见下:  ~~~ public override void Initialize() { model = Game.Content.Load<Model>(@"Models/wedge_player1"); modelTransforms = new Matrix[model.Bones.Count]; base.Initialize(); } ~~~ 但是经过这样的封装以后,使用者无法进行坐标变换的控制了,因此,还需要提供三个用于坐标变换的矩阵。加入成员变量:  ~~~ public Matrix worldMatrix {set;get;} public Matrix viewMatrix { set; get; } public Matrix projectionMatrix { set; get; } ~~~ 最后完成Draw()方法,代码如下:  ~~~ public override void Draw(GameTime gameTime) { //GraphicsDevice.Clear(Color.CornflowerBlue); model.CopyAbsoluteBoneTransformsTo(modelTransforms); foreach (ModelMesh mesh in model.Meshes) { foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.World = modelTransforms[mesh.ParentBone.Index] * worldMatrix; effect.View = viewMatrix; effect.Projection = projectionMatrix; } mesh.Draw(); } base.Draw(gameTime); } ~~~ 这样,这个Ship类就封装完成了,当在场景中使用时,需要创建一个ship对象: ship = new Ship(this); 然后将其加到Components中去: Components.Add(ship); 并在LoadContent()方法中为其指定变换参数:  ~~~ ship.projectionMatrix = camera.projection; ship.viewMatrix = camera.view * Matrix.CreateTranslation(new Vector3(4, 0, 10)); ship.worldMatrix = Matrix.CreateScale(-0.02f) * Matrix.CreateRotationZ(MathHelper.ToRadians(180))*Matrix.CreateTranslation(new Vector3(20,0,0)); ~~~ 当然也可以同样在Update()方法中更新ship.worldMatrix以对其进行旋转、平移、缩放的操作。如果需要有多艘飞船的编队,只要多创建几个ship对象,分别为其设定到不同的坐标即可。这样一来,通过继承自GameCompenent进行游戏组件的封装,可以在代码的可复用性上取得收益。 好了,我们已经有了更丰富的物体了,多生成几艘飞船试试,看看编队是否够壮观吧。 ![](https://box.kancloud.cn/2016-04-08_570727fb56965.gif) 附Ship类的源代码:  ~~~ public class Ship : Microsoft.Xna.Framework.DrawableGameComponent { public Matrix worldMatrix {set;get;} public Matrix viewMatrix { set; get; } public Matrix projectionMatrix { set; get; } Model model; Matrix[] modelTransforms; public Ship(Game game) : base(game) { worldMatrix = Matrix.Identity; viewMatrix = Matrix.Identity; projectionMatrix = Matrix.Identity; } /// <summary> /// Allows the game component to perform any initialization it needs to before starting /// to run. This is where it can query for any required services and load content. /// </summary> public override void Initialize() { model = Game.Content.Load<Model>(@"Models/wedge_player1"); modelTransforms = new Matrix[model.Bones.Count]; base.Initialize(); } /// <summary> /// Allows the game component to update itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> public override void Update(GameTime gameTime) { base.Update(gameTime); } public override void Draw(GameTime gameTime) { //GraphicsDevice.Clear(Color.CornflowerBlue); model.CopyAbsoluteBoneTransformsTo(modelTransforms); foreach (ModelMesh mesh in model.Meshes) { foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.World = modelTransforms[mesh.ParentBone.Index] * worldMatrix; effect.View = viewMatrix; effect.Projection = projectionMatrix; } mesh.Draw(); } base.Draw(gameTime); } } ~~~ ——欢迎转载,请注明出处 [http://blog.csdn.net/caowenbin](http://blog.csdn.net/caowenbin) ——