我正在尝试为XNA提供一些基元,包括能够制作可以旋转的轮廓矩形。这非常有用,因为您可以使用它创建一些甜蜜的动态内容,以及它用于调试目的。
我可以看到我遇到的问题here
基本上,正在发生的事情是,在绘制轮廓矩形时,将线条的粗细度调整到1,组成矩形的线条移动得越来越远。
这很奇怪但是,我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);
}
}
}
如果您有任何疑问,请不要害怕提问!
答案 0 :(得分: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( );
}