Nez 圆角矩形边框组件源码实现

Nez 圆角矩形边框组件源码实现

一、效果

图片如下

对应使用该组件的场景如下:

using FanaticGene.Test.Components;
using Microsoft.Xna.Framework;
using Nez;

namespace FanaticGene.Test.Scenes;

public class TestScene : Scene
{
    public override void Initialize()
    {
        base.Initialize();
        ClearColor = Color.White;
        var entity = CreateEntity("111");
        entity
            .AddComponent<BorderPrototypeSpriteComponent>()
            .SetHeight(300)
            .SetWidth(200)
            .SetBorderThickness(3)
            .SetBorderColor(Color.Red)
            .SetColor(Color.Black);

        entity.SetPosition(new Vector2(400, 300));
    }
}

二、代码

using Microsoft.Xna.Framework;
using Nez;
using Nez.Sprites;
using Microsoft.Xna.Framework.Graphics;
using Nez.Textures;

namespace FanaticGene.Test.Components;

public class BorderPrototypeSpriteComponent : SpriteRenderer
{
    public override float Width => _width;
    public override float Height => _height;

    public int Radius => _radius;
    private int _radius = 12;

    public Color BorderColor => _borderColor;
    private Color _borderColor = Color.Red;
    public int BorderThickness => _borderThickness;
    private int _borderThickness = 3;

    public override RectangleF Bounds
    {
        get
        {
            if (_areBoundsDirty)
            {
                _bounds.CalculateBounds(Entity.Transform.Position, _localOffset, _origin, Entity.Transform.Scale,
                    Entity.Transform.Rotation, _width, _height);
                _areBoundsDirty = false;
            }

            return _bounds;
        }
    }

    public float SkewTopX;
    public float SkewBottomX;
    public float SkewLeftY;
    public float SkewRightY;

    float _width, _height;


    public BorderPrototypeSpriteComponent() : this(50, 50)
    {
        OnPropertyChanged(new Vector2(50, 50));
    }

    public BorderPrototypeSpriteComponent(float width, float height) : base(Graphics.Instance.PixelTexture)
    {
        _width = width;
        _height = height;
        OnPropertyChanged(new Vector2(width, height));
    }

    /// <summary>
    /// sets the width of the sprite
    /// </summary>
    /// <returns>The width.</returns>
    /// <param name="width">Width.</param>
    public BorderPrototypeSpriteComponent SetWidth(float width)
    {
        _width = width;
        OnPropertyChanged(new Vector2(_width, _height));
        return this;
    }

    /// <summary>
    /// sets the height of the sprite
    /// </summary>
    /// <returns>The height.</returns>
    /// <param name="height">Height.</param>
    public BorderPrototypeSpriteComponent SetHeight(float height)
    {
        _height = height;
        OnPropertyChanged(new Vector2(_width, _height));
        return this;
    }

    private void OnPropertyChanged(Vector2 size, bool isForced = false)
    {
        var width = (int)size.X;
        var height = (int)size.Y;

        if (isForced == false)
        {
            if (_sprite.Texture2D.Width == width && _sprite.Texture2D.Height == height) return;
        }

 

        var texture2d = new Texture2D(Nez.Core.GraphicsDevice, width, height);
        var colors = new Color[width * height];

        var radius = _radius;

        void SetPoint(Color color, int x, int y)
        {
            colors[y * width + x] = color;
        }

        Color GetPoint(int x, int y)
        {
            return colors[y * width + x];
        }

        void SetRectangle(Color color, int x, int y, int width, int height)
        {
            for (int i = 0; i < width; i++)
            {
                var offsetX = i + x;
                for (int j = 0; j < height; j++)
                {
                    var offsetY = j + y;
                    SetPoint(color, offsetX, offsetY);
                }
            }
        }


        //_sprite = new Sprite();
        void SetRadius(Color color, int cwidth, int cheight, int startX, int startY, Vector2 center)
        {
            for (int i = 0; i < cwidth; i++)
            {
                for (int j = 0; j < cheight; j++)
                {
                    var offsetX = i + startX;
                    var offsetY = j + startY;
                    var point = new Vector2(offsetX, offsetY);
                    var distance = Vector2.Distance(center, point);
                    if (distance <= radius)
                        SetPoint(color, offsetX, offsetY);
                }
            }
        }

        void SetRadiusBorder(Color color, int cwidth, int cheight, int startX, int startY, Vector2 center)
        {
            for (int i = 0; i < cwidth; i++)
            {
                for (int j = 0; j < cheight; j++)
                {
                    var offsetX = i + startX;
                    var offsetY = j + startY;
                    var point = new Vector2(offsetX, offsetY);
                    var distance = Vector2.Distance(center, point);
                    if (distance <= radius && (radius - distance) <= BorderThickness)
                        SetPoint(color, offsetX, offsetY);
                }
            }
        }

        // 水平
        {
            var startX = radius;
            var startY = 0;
            var cwidth = width - 2 * radius;
            var cheight = radius;
            SetRectangle(Color, startX, startY, cwidth, cheight);
        }

        // 水平
        {
            var startX = radius;
            var startY = height - radius;
            var cwidth = width - 2 * radius;
            var cheight = radius;
            SetRectangle(Color, startX, startY, cwidth, cheight);
        }

        // 内容
        {
            var startX = 0;
            var startY = radius;
            var cwidth = width;
            var cheight = height - 2 * radius;
            SetRectangle(Color, startX, startY, cwidth, cheight);
        }

        // 左上角
        {
            var startX = 0;
            var startY = 0;
            var cwidth = radius;
            var cheight = radius;
            var center = new Vector2(radius, radius);
            SetRadius(Color, cwidth, cheight, startX, startY, center);
        }

        // 右上角
        {
            var startX = width - radius;
            var startY = 0;
            var cwidth = radius;
            var cheight = radius;
            var center = new Vector2(width - radius, radius);
            SetRadius(Color, cwidth, cheight, startX, startY, center);
        }

        // 左下角
        {
            var startX = 0;
            var startY = height - radius;
            var cwidth = radius;
            var cheight = radius;
            var center = new Vector2(radius, height - radius);
            SetRadius(Color, cwidth, cheight, startX, startY, center);
        }

        // 右下角
        {
            var startX = width - radius;
            var startY = height - radius;
            var cwidth = radius;
            var cheight = radius;
            var center = new Vector2(width - radius, height - radius);
            SetRadius(Color, cwidth, cheight, startX, startY, center);
        }

        // 边框
        {
            var startX = radius;
            var startY = 0;
            var cwidth = width - 2 * radius;
            var cheight = BorderThickness;
            SetRectangle(BorderColor, startX, startY, cwidth, cheight);
        }

        // 边框
        {
            var startX = radius;
            var startY = height - BorderThickness;
            var cwidth = width - 2 * radius;
            var cheight = BorderThickness;
            SetRectangle(BorderColor, startX, startY, cwidth, cheight);
        }

        // 边框
        {
            var startX = 0;
            var startY = radius;
            var cwidth = BorderThickness;
            var cheight = height - 2 * radius;
            SetRectangle(BorderColor, startX, startY, cwidth, cheight);
        }

        // 边框
        {
            var startX = width - BorderThickness;
            var startY = radius;
            var cwidth = BorderThickness;
            var cheight = height - 2 * radius;
            SetRectangle(BorderColor, startX, startY, cwidth, cheight);
        }

        // 左上角
        {
            var startX = 0;
            var startY = 0;
            var cwidth = radius;
            var cheight = radius;
            var center = new Vector2(radius, radius);
            SetRadiusBorder(BorderColor, cwidth, cheight, startX, startY, center);
        }


        // 右上角
        {
            var startX = width - radius;
            var startY = 0;
            var cwidth = radius;
            var cheight = radius;
            var center = new Vector2(width - radius, radius);
            SetRadiusBorder(BorderColor, cwidth, cheight, startX, startY, center);
        }

        // 左下角
        {
            var startX = 0;
            var startY = height - radius;
            var cwidth = radius;
            var cheight = radius;
            var center = new Vector2(radius, height - radius);
            SetRadiusBorder(BorderColor, cwidth, cheight, startX, startY, center);
        }

        // 右下角
        {
            var startX = width - radius;
            var startY = height - radius;
            var cwidth = radius;
            var cheight = radius;
            var center = new Vector2(width - radius, height - radius);
            SetRadiusBorder(BorderColor, cwidth, cheight, startX, startY, center);
        }

        texture2d.SetData(colors);
        _sprite = new Sprite(texture2d);
    }

    /// <summary>
    /// sets the skew values for the sprite
    /// </summary>
    /// <returns>The skew.</returns>
    /// <param name="skewTopX">Skew top x.</param>
    /// <param name="skewBottomX">Skew bottom x.</param>
    /// <param name="skewLeftY">Skew left y.</param>
    /// <param name="skewRightY">Skew right y.</param>
    public BorderPrototypeSpriteComponent SetSkew(float skewTopX, float skewBottomX, float skewLeftY, float skewRightY)
    {
        SkewTopX = skewTopX;
        SkewBottomX = skewBottomX;
        SkewLeftY = skewLeftY;
        SkewRightY = skewRightY;
        return this;
    }

    public BorderPrototypeSpriteComponent SetRadius(int radius)
    {
        _radius = radius;
        OnPropertyChanged(new Vector2(_width, _height), true);
        return this;
    }

    public BorderPrototypeSpriteComponent SetBorderColor(Color color)
    {
        if (color == BorderColor) return this;
        _borderColor = color;
        OnPropertyChanged(new Vector2(_width, _height), true);
        return this;
    }

    public BorderPrototypeSpriteComponent SetBorderThickness(int value)
    {
        if (value == BorderThickness) return this;
        _borderThickness = value;
        OnPropertyChanged(new Vector2(_width, _height), true);
        return this;
    }

    public new RenderableComponent SetColor(Color color)
    {
        if (color == Color) return this;
        Color = color;
        OnPropertyChanged(new Vector2(_width, _height), true);
        return this;
    }
    
    public override void OnAddedToEntity()
    {
        OriginNormalized = Vector2Ext.HalfVector();
        //Origin = 
    }

    public override void Render(Batcher batcher, Camera camera)
    {
        //var pos = (Entity.Transform.Position - (Origin * Entity.Transform.Scale) + LocalOffset);
        //var size = new Point((int)(_width * Entity.Transform.Scale.X), (int)(_height * Entity.Transform.Scale.Y));
        //var destRect = new Rectangle((int)pos.X, (int)pos.Y, size.X, size.Y);
        //batcher.Draw(_sprite, destRect, _sprite.SourceRect, Color.White, Entity.Transform.Rotation,
        //    SpriteEffects.None, LayerDepth, SkewTopX, SkewBottomX, SkewLeftY, SkewRightY);

        batcher.Draw(_sprite, Entity.Transform.Position + LocalOffset, Color.White,
                     Entity.Transform.Rotation, Origin, Entity.Transform.Scale, SpriteEffects, _layerDepth);
    }
}
posted @ 2025-04-05 23:35  fanbal  阅读(40)  评论(0)    收藏  举报