0

我试图让一些原语适用于 XNA,包括制作可以旋转的轮廓矩形的能力。这非常有用,因为您可以用它创建一些甜蜜的动态内容,以及它用于调试目的。

我遇到的问题可以在这里看到

本质上,正在发生的事情是,当绘制一个轮廓矩形并将线条的粗细超过一个时,构成矩形的线条会越来越远。

这很奇怪,但我 90% 确定问题出在根源上。我希望有人可以看看并发现我的错误。

我通过将线的原点设置为矩形的中心来绘制旋转线来渲染矩形。为了实现矩形的底部和右侧部分,我将顶部和左侧的线复制并旋转 180 度。(如果你在弧度范围内工作,我就是 Pi)

最大的怪异之处在于,当我调试Draw方法时,我发现值都完全符合预期!

这是矩形类,继承的类也在下面,以备不时之需。

public class Rectangle : Primitive
    {
        public float X { get { return Body.X; } set { Body.X = value; } }
        public float Y { get { return Body.Y; } set { Body.Y = value; } }
        public float Width { get { return Body.Width; } set { Body.Width = value; } }
        public float Height { get { return Body.Height; } set { Body.Height = value; } }
        public float Angle { get { return Body.Angle; } set { Body.Angle = value; } }


        public override Vector2 Bounds { get { return new Vector2((Width) * Scale.X, (Height) * Scale.Y);}}

        public override Microsoft.Xna.Framework.Rectangle DrawRect
        {
            get
            {
                return new Microsoft.Xna.Framework.Rectangle((int) (X - Thickness/2), (int) (Y - Thickness/2),
                                                             (int) ((X + Width + Thickness) * Scale.X),
                                                             (int) ((Y + Height + Thickness)* Scale.Y));
            }
        }

        public bool Fill;

        public Rectangle(Entity parent, string name, float x, float y, float width, float height, bool fill = false)
            : base(parent, name)
        {
            X = x;
            Y = y;
            Width = width;
            Height = height;
            Fill = fill;

            Origin = new Vector2(.5f,.5f);
        }

        public Rectangle(IComponent parent, string name, Body body, bool fill) : base(parent, name, body)
        {
            Fill = fill;
            Origin = new Vector2(.5f, .5f);
        }

        public override void Draw(SpriteBatch sb)
        {
            base.Draw(sb);
            if (!Fill)
            {
                float minx = X + (Thickness/2) + Origin.X;
                float miny = Y + (Thickness/2) +Origin.Y;
                //TODO: Fix origin issue
                //Draw our top line
                sb.Draw(Assets.Pixel,
                        new Vector2(minx, miny), null, Color * Alpha, Angle, new Vector2(Origin.X, Origin.Y * Bounds.Y), new Vector2(Bounds.X, Thickness * Scale.Y), Flip, Layer);

                //Left line
                sb.Draw(Assets.Pixel,
                        new Vector2(minx, miny), null, Color * Alpha, Angle, new Vector2(Origin.X * Bounds.X, Origin.Y), new Vector2(Thickness * Scale.X, Bounds.Y), Flip, Layer);


                //Essentially these are the same as the top and bottom just rotated 180 degrees
                //I have to do it this way instead of setting the origin to a negative value because XNA
                //seems to ignore origins when they are negative
                //Right Line
                sb.Draw(Assets.Pixel,
                        new Vector2(minx + 1, miny), null, Color * Alpha, Angle + MathHelper.Pi, new Vector2(Origin.X * Bounds.X, Origin.Y), new Vector2(Thickness * Scale.X, Bounds.Y), Flip, Layer);

                //Bottom Line
                sb.Draw(Assets.Pixel,
                        new Vector2(minx, miny + 1), null, Color * Alpha, Angle + MathHelper.Pi, new Vector2(Origin.X, Origin.Y * Bounds.Y), new Vector2(Bounds.X, Thickness * Scale.Y), Flip, Layer);

            }
            else
            {
                sb.Draw(Assets.Pixel, new Vector2(X + Origin.X*Width, Y + Origin.Y*Height), null, Color * Alpha, Angle, Origin, Bounds - new Vector2(Thickness), Flip, Layer);
            }
        }

Primitive

public abstract class Primitive : Render
    {
        public Body Body;

        public float Thickness = 1;

        protected Primitive(IComponent parent, string name) : base(parent, name)
        {
            Body = new Body(this, "Primitive.Body");   
        }

        protected Primitive(IComponent parent, string name, Vector2 pos)
            : base(parent, name)
        {
            Body = new Body(this, "Primitive.Body", pos);
        }

        protected Primitive(IComponent parent, string name, Body body) : base(parent, name)
        {
            Body = body;
        }

        public static void DrawLine(SpriteBatch sb, Vector2 p1, Vector2 p2, float thickness, float layer, Color color)
        {
            float angle = (float)System.Math.Atan2(p2.Y - p1.Y, p2.X - p1.X);
            float length = Vector2.Distance(p1, p2);

            sb.Draw(Assets.Pixel, p1, null, color,
                    angle, Vector2.Zero, new Vector2(length, thickness),
                    SpriteEffects.None, layer);
        }
    }

Render班级。这个并不重要,因为它只是为任何渲染类提供某种多态性。

    using EntityEngineV4.Engine;
using EntityEngineV4.PowerTools;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace EntityEngineV4.Components.Rendering
{
    public abstract class Render : Component
    {
        public float Alpha = 1f;
        public Color Color = Color.White;
        public SpriteEffects Flip = SpriteEffects.None;
        public float Layer;
        public Vector2 Scale = Vector2.One;

    public Vector2 Origin;

    /// <summary>
    /// Handy rectangle for getting the drawing position
    /// </summary>
    public virtual Rectangle DrawRect { get; set; }

    /// <summary>
    /// Source rectangle of the texture
    /// </summary>
    public virtual Rectangle SourceRect { get; set; }

    /// <summary>
    /// Bounds of the DrawRect
    /// </summary>
    public virtual Vector2 Bounds { get; set; }

    protected Render(IComponent parent, string name)
        : base(parent, name)
    {
    }

    public override void Update(GameTime gt)
    {
        base.Update(gt);
    }

    public override void Draw(SpriteBatch sb = null)
    {
        base.Draw(sb);
    }
    }
}

如果您有任何问题,请不要害怕提问!

4

1 回答 1

0

您应该将原点除以比例。

var scale = new Vector2(Bounds.X, Thickness * Scale.Y);
var origin = new Vector2(Origin.X, Origin.Y * Bounds.Y) / scale;
sb.Draw(Assets.Pixel, new Vector2(minx, miny), null, Color * Alpha, 
        Angle, origin, scale, Flip, Layer);

虽然我认为你做的事情有点复杂......我会使用变换矩阵来变换绘制的矩形......

  public void DrawBorder( Rectangle Bounds, int ThickNess, float angle, Color color ) {
        Vector3 Origin = new Vector3( Bounds.Width, Bounds.Height, 0 ) * 0.5f;
        Vector3 Pos = new Vector3( Bounds.X, Bounds.Y, 0 );

        Matrix transform = Matrix.CreateTranslation( -Origin ) 
                         * Matrix.CreateRotationZ( angle ) 
                         * Matrix.CreateTranslation( Pos );
        Batch.Begin( SpriteSortMode.Immediate, BlendState.AlphaBlend, transform );

        Bounds.X = 0;
        Bounds.Y = 0;
        Rectangle aux = Bounds;

        Bounds.X -= ThickNess;
        Bounds.Width = ThickNess;
        Batch.Draw( Batch.WhiteTexture, Bounds, color );
        Bounds.X = aux.Right;
        Batch.Draw( Batch.WhiteTexture, Bounds, color );

        Bounds.Y = aux.Top - ThickNess;
        Bounds.X = aux.Left - ThickNess;
        Bounds.Width = aux.Width + 2 * ThickNess;
        Bounds.Height = ThickNess;

        Batch.Draw( Batch.WhiteTexture, Bounds, color );

        Bounds.Y = aux.Bottom;

        Batch.Draw( Batch.WhiteTexture, Bounds, color );

        Batch.End( );
    }
于 2013-08-03T22:52:58.893 回答