MonoGame 游戏开发框架日记 -05

第四章:封装纹理类,以及Sprite类

这篇文章会有许多代码需要理解,这节课的部分代码是可以部分复制的,我推荐大家还是按顺序敲一次增加印象,当然了现在所有的代码都是为了之后开发那个史莱姆游戏做准备,此章的主要内容是:把纹理类封装起来实现一些其他功能,包括切割等,OK不多说我们正式开始此篇文章的内容


图集,以及2D游戏的精灵:

图集:在游戏开发中通常会遇到以下几种情况:美术为了节约存储,优化结构通常会通过将所有素材都集中地放在一张图片上,那么我们该怎么处理这个图片呢,在知名游戏引擎Unity中他的精灵类素材可以通过切割,分割得到,这个时候我们就需要封装一个图集类,通过配置文件切割出重要的内容了。

2D精灵 :首先精灵就是渲染在窗口上地结果,我们通常通过切割得到的图片来充当精灵,但是我们为了更加方便渲染都会在Sprite类中封装许多功能,包括Unity中里面封装的功能都是很完善很强大的功能,毕竟是称霸一方的超级游戏引擎

OK,介绍完两个东西我们试一下将两个东西全部实现出来,分别是图集类,和精灵类

图集类创建完整流程:

第一步:创建TextureRegion类

为什么创建这个类呢?很简单因为原先MonoGame封装的Texture2D的类功能不能满足我们的需求,我们需要写出一些重载的方法增加渲染的方式,以及得到图集类切割得到的材质,OK我们正式开始
分为以下三个大步

  • 创建文件夹:在项目根目录中创建Graphics文件夹
  • 创建cs文件:在Graphics文件夹中创建TextureRegion.cs类
  • 编写TextureRegion类
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace SlimeGame.Graphics;


public class TextureRegion 
{

}

以上声明了纹理渲染类以及包含了必要的库,接下来书写必要的TextureRegion属性

	/// <summary>
    /// 取得所需的纹理文件
    /// </summary>
    public Texture2D texture { get; set; }

    /// <summary>
    /// 取得切割的长方形
    /// </summary>
    public Rectangle SourceRectangle { get; set; }

    /// <summary>
    /// 切割宽度
    /// </summary>
    public int Width => SourceRectangle.Width;

    /// <summary>
    /// 切割高度
    /// </summary>
    public int Height => SourceRectangle.Height;

    /// <summary>
    /// 获取该纹理区域的顶部标准化坐标.
    /// </summary>
    public float TopTextureCoordinate => SourceRectangle.Top / (float)texture.Height;

    /// <summary>
    /// 获取该纹理区域的底部标准化坐标.
    /// </summary>
    public float BottomTextureCoordinate => SourceRectangle.Bottom / (float)texture.Height;

    /// <summary>
    /// 获取该纹理区域的左侧标准化坐标.
    /// </summary>
    public float LeftTextureCoordinate => SourceRectangle.Left / (float)texture.Width;

    /// <summary>
    /// 获取该纹理区域的右侧标准化坐标.
    /// </summary>
    public float RightTextureCoordinate => SourceRectangle.Right / (float)texture.Width;

接下来书写构造函数

	/// <summary>
    /// 无参构造
    /// </summary>
    public TextureRegion() { }


    /// <summary>
    /// 有参构造
    /// </summary>
    /// <param name="texture">所需纹理</param>
    /// <param name="x">矩形位置的X轴坐标</param>
    /// <param name="y">矩形位置的Y轴坐标</param>
    /// <param name="width">矩形切割的宽度</param>
    /// <param name="height">矩形切割的高度</param>
    public TextureRegion(Texture2D texture, int x, int y, int width, int height)
    {
        this.texture = texture;
        SourceRectangle = new Rectangle(x, y, width, height);
    }

接下来写出,渲染函数的重载方法,能够实现切割后的图片的渲染从简到繁都有重载

	/// <summary>
    /// 绘制函数重写,极简版本
    /// </summary>
    /// <param name="spriteBatch">绘制组件</param>
    /// <param name="position">位置</param>
    /// <param name="color">颜色</param>
    public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color)
    {
        Draw(spriteBatch, position, color, 0.0f, Vector2.Zero, Vector2.One, SpriteEffects.None, 0.0f);
    }


    /// <summary>
    /// 绘制函数的重写简单版本
    /// </summary>
    /// <param name="spriteBatch">绘制函数所需组件</param>
    /// <param name="position">位置</param>
    /// <param name="color">眼色</param>
    /// <param name="rotation">旋转角度</param>
    /// <param name="origin">中心偏移量</param>
    /// <param name="scale">缩放比例</param>
    /// <param name="effects">翻转效果</param>
    /// <param name="layerDepth">深度效果</param>
    public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects effects, float layerDepth)
    {
        Draw(
            spriteBatch,
            position,
            color,
            rotation,
            origin,
            new Vector2(scale, scale),
            effects,
            layerDepth
        );
    }


    /// <summary>
    /// 绘制函数:所有详细参数
    /// </summary>
    /// <param name="spriteBatch">所需绘制精灵组件</param>
    /// <param name="position">绘制位置</param>
    /// <param name="color">颜色</param>
    /// <param name="rotation">旋转角度</param>
    /// <param name="origin">精灵中心偏移量</param>
    /// <param name="scale">缩放比例</param>
    /// <param name="effects">翻转效果</param>
    /// <param name="layerDepth">图层深度</param>
    public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
    {
        spriteBatch.Draw(
            texture,
            position,
            SourceRectangle,
            color,
            rotation,
            origin,
            scale,
            effects,
            layerDepth
        );
    }

自此所有的Texture2D的代码就全部写完了
我们下面给出完整的代码:
完整代码:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace SlimeGame.Graphics;

/// <summary>
/// 表示纹理中的矩形区域.
/// </summary>
public class TextureRegion
{
    /// <summary>
    /// 取得所需的纹理文件
    /// </summary>
    public Texture2D texture { get; set; }

    /// <summary>
    /// 取得切割的长方形
    /// </summary>
    public Rectangle SourceRectangle { get; set; }

    /// <summary>
    /// 切割宽度
    /// </summary>
    public int Width => SourceRectangle.Width;

    /// <summary>
    /// 切割高度
    /// </summary>
    public int Height => SourceRectangle.Height;

    /// <summary>
    /// 获取该纹理区域的顶部标准化坐标.
    /// </summary>
    public float TopTextureCoordinate => SourceRectangle.Top / (float)texture.Height;

    /// <summary>
    /// 获取该纹理区域的底部标准化坐标.
    /// </summary>
    public float BottomTextureCoordinate => SourceRectangle.Bottom / (float)texture.Height;

    /// <summary>
    /// 获取该纹理区域的左侧标准化坐标.
    /// </summary>
    public float LeftTextureCoordinate => SourceRectangle.Left / (float)texture.Width;

    /// <summary>
    /// 获取该纹理区域的右侧标准化坐标.
    /// </summary>
    public float RightTextureCoordinate => SourceRectangle.Right / (float)texture.Width;


    /// <summary>
    /// 无参构造
    /// </summary>
    public TextureRegion() { }


    /// <summary>
    /// 有参构造
    /// </summary>
    /// <param name="texture">所需纹理</param>
    /// <param name="x">矩形位置的X轴坐标</param>
    /// <param name="y">矩形位置的Y轴坐标</param>
    /// <param name="width">矩形切割的宽度</param>
    /// <param name="height">矩形切割的高度</param>
    public TextureRegion(Texture2D texture, int x, int y, int width, int height)
    {
        this.texture = texture;
        SourceRectangle = new Rectangle(x, y, width, height);
    }


    /// <summary>
    /// 绘制函数重写,极简版本
    /// </summary>
    /// <param name="spriteBatch">绘制组件</param>
    /// <param name="position">位置</param>
    /// <param name="color">颜色</param>
    public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color)
    {
        Draw(spriteBatch, position, color, 0.0f, Vector2.Zero, Vector2.One, SpriteEffects.None, 0.0f);
    }


    /// <summary>
    /// 绘制函数的重写简单版本
    /// </summary>
    /// <param name="spriteBatch">绘制函数所需组件</param>
    /// <param name="position">位置</param>
    /// <param name="color">眼色</param>
    /// <param name="rotation">旋转角度</param>
    /// <param name="origin">中心偏移量</param>
    /// <param name="scale">缩放比例</param>
    /// <param name="effects">翻转效果</param>
    /// <param name="layerDepth">深度效果</param>
    public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects effects, float layerDepth)
    {
        Draw(
            spriteBatch,
            position,
            color,
            rotation,
            origin,
            new Vector2(scale, scale),
            effects,
            layerDepth
        );
    }


    /// <summary>
    /// 绘制函数:所有详细参数
    /// </summary>
    /// <param name="spriteBatch">所需绘制精灵组件</param>
    /// <param name="position">绘制位置</param>
    /// <param name="color">颜色</param>
    /// <param name="rotation">旋转角度</param>
    /// <param name="origin">精灵中心偏移量</param>
    /// <param name="scale">缩放比例</param>
    /// <param name="effects">翻转效果</param>
    /// <param name="layerDepth">图层深度</param>
    public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
    {
        spriteBatch.Draw(
            texture,
            position,
            SourceRectangle,
            color,
            rotation,
            origin,
            scale,
            effects,
            layerDepth
        );
    }
}


第二步:创建TextureAtlas 类

OK,终于到重头戏了,这个是这篇文章最主要的功能代码实现切割代码,和返回切割玩的纹理

  • 创建cs文件:在Graphics文件夹中创建TextureRegion.cs类
  • 编写TextureRegion类
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace SlimeGame.Graphics;

public class TextureAtlas 
{

}

包含必要的库,创建图集类

	/// <summary>
    /// 存储每个纹理的字典
    /// </summary>
    private Dictionary<string, TextureRegion> Regions;

    

    /// <summary>
    /// 所需总体的纹理图片
    /// </summary>
    public Texture2D TotalTexture { get; set; }
	/// <summary>
    /// 无参构造
    /// </summary>
    public TextureAtlas()
    {
        Regions = new Dictionary<string, TextureRegion>();
       
    }

    /// <summary>
    /// 有参构造
    /// </summary>
    /// <param name="texture">所需总体纹理</param>
    public TextureAtlas(Texture2D texture)
    {
        TotalTexture = texture;
        Regions = new Dictionary<string, TextureRegion>();
        
    }

构造函数

	/// <summary>
    /// 在图集里增加纹理
    /// </summary>
    /// <param name="name">纹理对应名称/键</param>
    /// <param name="x">纹理切割X坐标</param>
    /// <param name="y">纹理切割Y坐标</param>
    /// <param name="width">纹理切割宽度</param>
    /// <param name="height">纹理切割高度</param>
    public void AddRegion(string name, int x, int y, int width, int height)
    {
        TextureRegion region = new TextureRegion(TotalTexture, x, y, width, height);
        Regions.Add(name, region);
    }
    /// <summary>
    /// 从字典中查询纹理
    /// </summary>
    /// <param name="name">对应字典名字/键</param>
    /// <returns>纹理</returns>
    public TextureRegion GetRegion(string name)
    {
        return Regions[name];
    }
    /// <summary>
    /// 从字典中移除纹理
    /// </summary>
    /// <param name="name">对应字典名字/键</param>
    /// <returns>是否删除</returns>
    public bool RemoveRegion(string name)
    {
        return Regions.Remove(name);
    }
    /// <summary>
    /// 清空此字典
    /// </summary>
    public void RegionsClear()
    {
        Regions.Clear();
    }
    /// <summary>
    /// 从文件中加载纹理
    /// </summary>
    /// <param name="content">文件资源管理</param>
    /// <param name="fileName">文件名称</param>
    /// <returns></returns>
    public static TextureAtlas FromFile(ContentManager content, string fileName)
    {
        TextureAtlas atlas = new TextureAtlas();

        // 合并文件名成完整项目路径
        string filePath = Path.Combine(content.RootDirectory, fileName);


        //文件流式存储
        using (Stream stream = TitleContainer.OpenStream(filePath))
        {
            // Xml读取器的获得
            using (XmlReader reader = XmlReader.Create(stream))
            {
                // 读XMl的文件内容
                XDocument doc = XDocument.Load(reader);
                XElement root = doc.Root;

                // <Texture> 该元素包含要加载的 Texture2D 的内容路径.
                // 因此,我们将检索该值,然后使用内容管理器加载纹理.
                string texturePath = root.Element("Texture").Value;
                atlas.TotalTexture = content.Load<Texture2D>(texturePath);

                // <Regions> 该元素包含单独的<Region>元素,每个元素描述
                // 图集中的其他纹理区域.  
                //
                // 例子:
                // <Regions>
                //      <Region name="spriteOne" x="0" y="0" width="32" height="32" />
                //      <Region name="spriteTwo" x="32" y="0" width="32" height="32" />
                // </Regions>
                //
                // 因此,我们检索所有<Region>元素,然后遍历每个元素,从中生成一个新的 TextureRegion 实例,并将其添加到此图集.
                var regions = root.Element("Regions")?.Elements("Region");

                if (regions != null)
                {
                    foreach (var region in regions)
                    {
                        string name = region.Attribute("name")?.Value;
                        int x = int.Parse(region.Attribute("x")?.Value ?? "0");
                        int y = int.Parse(region.Attribute("y")?.Value ?? "0");
                        int width = int.Parse(region.Attribute("width")?.Value ?? "0");
                        int height = int.Parse(region.Attribute("height")?.Value ?? "0");

                        if (!string.IsNullOrEmpty(name))
                        {
                            atlas.AddRegion(name, x, y, width, height);
                        }
                    }
                }
                return atlas;
            }
        }
    }

必要方法,OK我们atlas的代码就到这了,接下来我们声明以下完整代码:
完整代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace SlimeGame.Graphics;

public class TextureAtlas 
{
	/// <summary>
    /// 存储每个纹理的字典
    /// </summary>
    private Dictionary<string, TextureRegion> Regions;

    

    /// <summary>
    /// 所需总体的纹理图片
    /// </summary>
    public Texture2D TotalTexture { get; set; }
    /// <summary>
    /// 无参构造
    /// </summary>
    public TextureAtlas()
    {
        Regions = new Dictionary<string, TextureRegion>();
        
    }

    /// <summary>
    /// 有参构造
    /// </summary>
    /// <param name="texture">所需总体纹理</param>
    public TextureAtlas(Texture2D texture)
    {
        TotalTexture = texture;
        Regions = new Dictionary<string, TextureRegion>();
        
    }
    /// <summary>
    /// 在图集里增加纹理
    /// </summary>
    /// <param name="name">纹理对应名称/键</param>
    /// <param name="x">纹理切割X坐标</param>
    /// <param name="y">纹理切割Y坐标</param>
    /// <param name="width">纹理切割宽度</param>
    /// <param name="height">纹理切割高度</param>
    public void AddRegion(string name, int x, int y, int width, int height)
    {
        TextureRegion region = new TextureRegion(TotalTexture, x, y, width, height);
        Regions.Add(name, region);
    }
    /// <summary>
    /// 从字典中查询纹理
    /// </summary>
    /// <param name="name">对应字典名字/键</param>
    /// <returns>纹理</returns>
    public TextureRegion GetRegion(string name)
    {
        return Regions[name];
    }
    /// <summary>
    /// 从字典中移除纹理
    /// </summary>
    /// <param name="name">对应字典名字/键</param>
    /// <returns>是否删除</returns>
    public bool RemoveRegion(string name)
    {
        return Regions.Remove(name);
    }
    /// <summary>
    /// 清空此字典
    /// </summary>
    public void RegionsClear()
    {
        Regions.Clear();
    }
    /// <summary>
    /// 从文件中加载纹理
    /// </summary>
    /// <param name="content">文件资源管理</param>
    /// <param name="fileName">文件名称</param>
    /// <returns></returns>
    public static TextureAtlas FromFile(ContentManager content, string fileName)
    {
        TextureAtlas atlas = new TextureAtlas();

        // 合并文件名成完整项目路径
        string filePath = Path.Combine(content.RootDirectory, fileName);


        //文件流式存储
        using (Stream stream = TitleContainer.OpenStream(filePath))
        {
            // Xml读取器的获得
            using (XmlReader reader = XmlReader.Create(stream))
            {
                // 读XMl的文件内容
                XDocument doc = XDocument.Load(reader);
                XElement root = doc.Root;

                // <Texture> 该元素包含要加载的 Texture2D 的内容路径.
                // 因此,我们将检索该值,然后使用内容管理器加载纹理.
                string texturePath = root.Element("Texture").Value;
                atlas.TotalTexture = content.Load<Texture2D>(texturePath);

                // <Regions> 该元素包含单独的<Region>元素,每个元素描述
                // 图集中的其他纹理区域.  
                //
                // 例子:
                // <Regions>
                //      <Region name="spriteOne" x="0" y="0" width="32" height="32" />
                //      <Region name="spriteTwo" x="32" y="0" width="32" height="32" />
                // </Regions>
                //
                // 因此,我们检索所有<Region>元素,然后遍历每个元素,从中生成一个新的 TextureRegion 实例,并将其添加到此图集.
                var regions = root.Element("Regions")?.Elements("Region");

                if (regions != null)
                {
                    foreach (var region in regions)
                    {
                        string name = region.Attribute("name")?.Value;
                        int x = int.Parse(region.Attribute("x")?.Value ?? "0");
                        int y = int.Parse(region.Attribute("y")?.Value ?? "0");
                        int width = int.Parse(region.Attribute("width")?.Value ?? "0");
                        int height = int.Parse(region.Attribute("height")?.Value ?? "0");

                        if (!string.IsNullOrEmpty(name))
                        {
                            atlas.AddRegion(name, x, y, width, height);
                        }
                    }
                }
                return atlas;
            }
        }
    }
}


第三步:创建Sprite类:

OK,Sprite类是今天最后一步,渲染出来的关键代码

  • 创建cs文件:在Graphics文件夹中创建Sprite.cs类
  • 编写Sprite类
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace SlimeGame.Graphics;

/// <summary>
/// 精灵类,用于渲染2D精灵
/// </summary>
public class Sprite {}

包含必要库创建必须代码

	/// <summary>
    /// 该精灵类纹理
    /// </summary> 
    public TextureRegion Region { get; set; }

    /// <summary>
    /// 颜色系以及透明度
    /// </summary>
    public Color Color { get; set; } = Color.White;

    /// <summary>
    /// 旋转角度
    /// </summary>
    public float Rotation { get; set; } = 0.0f;

    /// <summary>
    /// 缩放比例
    /// </summary>
    public Vector2 Scale { get; set; } = Vector2.One;

    /// <summary>
    /// 中心偏移量
    /// </summary>
    public Vector2 Origin { get; set; } = Vector2.Zero;

    /// <summary>
    /// 是否翻转
    /// </summary>
    public SpriteEffects Effects { get; set; } = SpriteEffects.None;

    /// <summary>
    /// 图层深度
    /// </summary>
    public float LayerDepth { get; set; } = 0.0f;

    /// <summary>
    /// 宽度
    /// </summary>
    public float Width => Region.Width * Scale.X;
    /// <summary>
    /// 高度
    /// </summary>
    public float Height => Region.Height * Scale.Y;

Sprite类的必要属性

	/// <summary>
    /// 无参构造
    /// </summary>
    public Sprite() { }
    /// <summary>
    /// 有参构造
    /// </summary>
    /// <param name="region">材质</param>
    public Sprite(TextureRegion region)
    {
        Region = region;
    }

构造函数

	/// <summary>
    /// 使得Origin为材质的中心
    /// </summary>
    public void CenterOrigin()
    {
        Origin = new Vector2(Region.Width, Region.Height) * 0.5f;
    }


    /// <summary>
    /// 渲染函数,在窗口中绘制函数
    /// </summary>
    /// <param name="spriteBatch">精灵渲染组件</param>
    /// <param name="position">渲染位置</param>
    public void Draw(SpriteBatch spriteBatch, Vector2 position)
    {
        Region.Draw(spriteBatch, position, Color, Rotation, Origin, Scale, Effects, LayerDepth);
    }

功能函数 OK,Sprite类也编写完成了,我们接下来声明以下完整代码
完整代码

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace SlimeGame.Graphics;

/// <summary>
/// 精灵类,用于渲染2D精灵
/// </summary>
public class Sprite
{
    /// <summary>
    /// 该精灵类纹理
    /// </summary> 
    public TextureRegion Region { get; set; }

    /// <summary>
    /// 颜色系以及透明度
    /// </summary>
    public Color Color { get; set; } = Color.White;

    /// <summary>
    /// 旋转角度
    /// </summary>
    public float Rotation { get; set; } = 0.0f;

    /// <summary>
    /// 缩放比例
    /// </summary>
    public Vector2 Scale { get; set; } = Vector2.One;

    /// <summary>
    /// 中心偏移量
    /// </summary>
    public Vector2 Origin { get; set; } = Vector2.Zero;

    /// <summary>
    /// 是否翻转
    /// </summary>
    public SpriteEffects Effects { get; set; } = SpriteEffects.None;

    /// <summary>
    /// 图层深度
    /// </summary>
    public float LayerDepth { get; set; } = 0.0f;

    /// <summary>
    /// 宽度
    /// </summary>
    public float Width => Region.Width * Scale.X;
    /// <summary>
    /// 高度
    /// </summary>
    public float Height => Region.Height * Scale.Y;

    /// <summary>
    /// 无参构造
    /// </summary>
    public Sprite() { }
    /// <summary>
    /// 有参构造
    /// </summary>
    /// <param name="region">材质</param>
    public Sprite(TextureRegion region)
    {
        Region = region;
    }

    /// <summary>
    /// 使得Origin为材质的中心
    /// </summary>
    public void CenterOrigin()
    {
        Origin = new Vector2(Region.Width, Region.Height) * 0.5f;
    }


    /// <summary>
    /// 渲染函数,在窗口中绘制函数
    /// </summary>
    /// <param name="spriteBatch">精灵渲染组件</param>
    /// <param name="position">渲染位置</param>
    public void Draw(SpriteBatch spriteBatch, Vector2 position)
    {
        Region.Draw(spriteBatch, position, Color, Rotation, Origin, Scale, Effects, LayerDepth);
    }
}

使用图集类,精灵类

到了这一步,我们就已经把所有代码全部创建好了,代码量很大,今天大家得多花一些时间来学习,我写的注释都已经标好所有函数,成员的功能了,大家记得要注意看注释,接下来我会教会大家如何使用

主要分为下面几步

  • 创建文件夹
  • 创建xml配置文件
  • 修改配置文件属性
  • 编写xml
  • 编写MainGame代码

在这里插入图片描述

得到的效果应该是如上面的效果:

第一步:打开MonoGame内容管道
在这里插入图片描述
第二步:创建文件夹configs
在这里插入图片描述

在这里插入图片描述
第三步:创建新的item并确定为xml文件且取名为atlas_slice.xml(当然这个名字随便取自己记得就好)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第四步:修改xml构建方式改为Copy,当你点击xml文件后看Properties方框的时候就会发现BuildAction为Build,将他改为Copy
在这里插入图片描述
第五步:编写代码
此处我们需要打开VSCode进行编辑代码为什么?很简单因为MonoGame的内容管道并不支持直接编写,我们需要在Content/configs文件夹中找到文件并开始编写,OK我们开始直接编写,编写方法:我在编写Atlas类的时候注释已经明确说明了编写方法,不知道我接下来的xml配置文件啥意思的回去看看
在这里插入图片描述
完整代码:(直接覆盖原本自动生成的代码

<?xml version="1.0" encoding="utf-8"?>
<TextureAtlas>
    <Texture>images/atlas</Texture>
    <Regions>
        <Region name="slime-1" x="340" y="0" width="20" height="20" />
        <Region name="slime-2" x="340" y="20" width="20" height="20" />
        <Region name="bat-1" x="340" y="40" width="20" height="20" />
        <Region name="bat-2" x="340" y="60" width="20" height="20" />
        <Region name="bat-3" x="360" y="0" width="20" height="20" />
        <Region name="unfocused-button" x="259" y="80" width="65" height="14" />
        <Region name="focused-button-1" x="259" y="94" width="65" height="14" />
        <Region name="focused-button-2" x="259" y="109" width="65" height="14" />
        <Region name="panel-background" x="324" y="97" width="15" height="15" />
        <Region name="slider-off-background" x="341" y="96" width="11" height="10" />
        <Region name="slider-middle-background" x="345" y="81" width="3" height="3" />
        <Region name="slider-max-background" x="354" y="96" width="11" height="10" />
    </Regions>
</TextureAtlas>

这里有一点需要注意一下就是在代码第3行中的文件路径根据你前两章的时候定义的为准,不要以我的为准

OK 我们最后修改一下MainGame的代码,如果你前面都看懂了,那么MainGame部分的代码就一定看得懂我们直接上代码

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SlimeGame.Graphics;
using SlimeGameLibrary;

namespace SlimeGame;

public class GameMain : Core
{
	// 声明Sprite类
    private Sprite bat;
    private Sprite slime;
    public GameMain() : base("SlimeGame", 1280, 720, false)
    {

    }

    protected override void Initialize()
    {
        // TODO: 增加你的初始化逻辑

        base.Initialize();
    }

    protected override void LoadContent()
    {
       // 加载图集类,此处以自己的路径为准
        TextureAtlas atlas = TextureAtlas.FromFile(Content, "configs/atlas_slice.xml");
        // 此处的名称以自己xml文件中的名称为准
        slime = atlas.CreateSprite("slime-1");
        slime.Scale = new Vector2(4.0f, 4.0f);

         // 此处的名称以自己xml文件中的名称为准
        bat = atlas.CreateSprite("bat-1");
        bat.Scale = new Vector2(4.0f, 4.0f);
    }

    protected override void Update(GameTime gameTime)
    {
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
            Exit(); // 退出游戏:按下Esc键或是手柄上的一个啥键

        // TODO: 在此处增加你的游戏主循环逻辑

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
		// 像素化渲染
        SpriteBatch.Begin(samplerState: SamplerState.PointClamp);

     	// Sprite的渲染方式
        slime.Draw(SpriteBatch, Vector2.One);

       
        bat.Draw(SpriteBatch, new Vector2(slime.Width + 10, 0));

       
        SpriteBatch.End();

        base.Draw(gameTime);
    }
}

OK。接下来的我们直接dotnet run 运行一下试试看,大家记得好好加油运行结果我再放一次吧!
在这里插入图片描述

结语

今天的文章就到此结束了,我又想要搞一个新项目了,我这边想开一个Unity类银河恶魔城游戏开发的教程,但是手头还有三四个项目还没搞完,又要考驾照,早上起来又要写文章写个三四个小时,这个教程我项目调Bug调了好久,才开始写,看一下吧,要是时间够的话我会在B站录视频,这个银河恶魔城项目主要是教大家编程模式的:主要是一些常用单例模式,有限状态机,行为树等,跑题了,大家今天的代码好好看看,就算复制也好好看看这些注释,MonoGame官方写的就是有东西
好现在我照例问大家几个问题:

什么是Atlas?
如何实现Atlas?
什么是Sprite?
如何实现Sprite?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值