Vector XNA-边界框旋转噩梦

Vector XNA-边界框旋转噩梦,vector,xna,rotation,sprite,Vector,Xna,Rotation,Sprite,我现在正在经历一场噩梦,试图找到一个正确的公式来获得一个对应于我的精灵方向的边界框 我知道!在互联网上有很多例子,解决方案,解释,包括这里,在这个网站上。但是相信我,我都试过了。我试着仅仅应用解决方案,我试着理解解释,但每个帖子都给出了不同的解决方案,而且没有一个有效 我显然错过了一些重要的事情 所以,基本上,我有一个sprite,它的纹理是原生的(20宽×40高),在启动应用程序时位于(200200)。《精灵起源》是一部经典之作 _origin = new Vector2((float)_te

我现在正在经历一场噩梦,试图找到一个正确的公式来获得一个对应于我的精灵方向的边界框

我知道!在互联网上有很多例子,解决方案,解释,包括这里,在这个网站上。但是相信我,我都试过了。我试着仅仅应用解决方案,我试着理解解释,但每个帖子都给出了不同的解决方案,而且没有一个有效

我显然错过了一些重要的事情

所以,基本上,我有一个sprite,它的纹理是原生的(20宽×40高),在启动应用程序时位于(200200)。《精灵起源》是一部经典之作

_origin = new Vector2((float)_texture.Width / 2, (float)_texture.Height / 2);
所以原点会返回一个(5.5;8)向量2

通过键盘输入,我可以旋转这个精灵。默认旋转为0或Key.Up。然后旋转90对应于键。向右,180对应于键。向下,依此类推

目前,不需要移动,只需要旋转

下面是我计算边界矩形的代码:

public partial class Character : ICollide
{
    private const int InternalRunSpeedBonus = 80;
    private const int InternalSpeed = 80;
    private Vector2 _origin;
    private Texture2D _texture;
    private Texture2D _axisBase;
    private Texture2D _axisOrig;

    public Character()
    {
        MoveData = new MoveWrapper { Rotation = 0f, Position = new Vector2(200, 200), Speed = new Vector2(InternalSpeed) };
    }

    public MoveWrapper MoveData { get; set; }

    #region ICollide Members

    public Rectangle Bounds
    {
        get { return MoveData.Bounds; }
    }

    public Texture2D Texture
    {
        get { return _texture; }
    }
    #endregion ICollide Members

    public void Draw(SpriteBatch theSpriteBatch)
    {
        theSpriteBatch.Draw(_texture, MoveData.Position, null, Color.White, MoveData.Rotation, _origin, 1f, SpriteEffects.None, 0);//main sprite
        theSpriteBatch.Draw(_axisOrig, MoveData.Position, null, Color.White, 0f, _origin, 1f, SpriteEffects.None, 0);//green
        theSpriteBatch.Draw(_axisBase, MoveData.Position, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0);//red

    }

    public void Load(ContentManager theContentManager)
    {
        _texture = theContentManager.Load<Texture2D>("man");
        _axisBase = theContentManager.Load<Texture2D>("axis");
        _axisOrig = theContentManager.Load<Texture2D>("axisOrig");
        _origin = new Vector2((float)_texture.Width / 2, (float)_texture.Height / 2);

    }

    public void MoveForward(GameTime theGameTime, KeyboardState aCurrentKeyboardState)
    {
        InternalMove(theGameTime, aCurrentKeyboardState);
    }

    private void InternalMove(GameTime theGameTime, KeyboardState aCurrentKeyboardState, bool forward = true)
    {
        //stuff to get the move wrapper data valorized (new position, speed, rotation, etc.)
        MoveWrapper pm = MovementsHelper.Move(MoveData.Position, MoveData.Rotation, aCurrentKeyboardState, InternalSpeed,
                                              InternalRunSpeedBonus, theGameTime, forward);
        pm.Bounds = GetBounds(pm);
        MoveData = pm;
    }

    public void MoveBackward(GameTime theGameTime, KeyboardState aCurrentKeyboardState)
    {
        InternalMove(theGameTime, aCurrentKeyboardState, false);

    }

    private Rectangle GetBounds(MoveWrapper pm)
    {
        return GetBoundingBox(pm, _texture.Width, _texture.Height);
    }

    public  Rectangle GetBoundingBox(MoveWrapper w, int tWidth, int tHeight)
    {
        //1) get original bounding vectors

        //upper left => same as position
        Vector2 p1 = w.Position;

        //upper right x = x0+width, y = same as position
        Vector2 p2 = new Vector2(w.Position.X + tWidth, w.Position.Y);

        //lower right x = x0+width, y = y0+height
        Vector2 p3 = new Vector2(w.Position.X + tWidth, w.Position.Y + tHeight);

        //lower left x = same as position,y = y0+height
        Vector2 p4 = new Vector2(w.Position.X, w.Position.Y + tHeight);


        //2) rotate all points given rotation and origin
        Vector2 p1r = RotatePoint(p1, w);
        Vector2 p2r = RotatePoint(p2, w);
        Vector2 p3r = RotatePoint(p3, w);
        Vector2 p4r = RotatePoint(p4, w);

        //3) get vector2 bouding rectancle location
        var minX = Math.Min(p1r.X, Math.Min(p2r.X, Math.Min(p3r.X, p4r.X)));
        var maxX = Math.Max(p1r.X, Math.Max(p2r.X, Math.Max(p3r.X, p4r.X)));

        //4) get bounding rectangle width and height
        var minY = Math.Min(p1r.Y, Math.Min(p2r.Y, Math.Min(p3r.Y, p4r.Y)));
        var maxY = Math.Max(p1r.Y, Math.Max(p2r.Y, Math.Max(p3r.Y, p4r.Y)));

        var width = maxX - minX;
        var height = maxY - minY;

        // --> begin hack to get it work for 0,90,180,270 degrees
        var origMod = new Vector2((float)tWidth / 2, (float)tHeight / 2);

        var degree = (int)MathHelper.ToDegrees(w.Rotation);

        if (degree == 0)
        {
            minX -= origMod.X;
            minY -= origMod.Y;
        }
        else if (degree == 90)
        {
            minX += origMod.Y;
            minY -= origMod.X;
        }
        else if (degree == 180)
        {
            minX += origMod.X;
            minY += origMod.Y;
        }
        else if (degree == 270)
        {
            minX -= origMod.Y;
            minY += origMod.X;
        }
        // end hack <--

        return new Rectangle((int)minX, (int)minY, (int)width, (int)height);
    }

    public  Vector2 RotatePoint(Vector2 p, MoveWrapper a)
    {
        var m = Matrix.CreateRotationZ(a.Rotation);

        var refToWorldOrig = p - a.Position;
        Vector2 rotatedVector = Vector2.Transform(refToWorldOrig, m);
        var backToSpriteOrig = rotatedVector + a.Position;
        return backToSpriteOrig;

        //does not work
        //var Origin = new Vector3(_origin, 0);
        //var Position = new Vector3(p, 0);

        //var m = Matrix.CreateTranslation(-Origin)
        //        * Matrix.CreateRotationZ(a.Rotation)
        //        * Matrix.CreateTranslation(Position);

        //return Vector2.Transform(p, m);
    }
}
公共部分类字符:ICollide
{
私人常数int InternalRunSpeedBonus=80;
私有常数int InternalSpeed=80;
私有向量2_起源;
私有纹理2D_纹理;
私有纹理2D_axisBase;
私有纹理2D_axisOrig;
公共性质()
{
MoveData=newmovewrapper{Rotation=0f,Position=newvector2(200200),Speed=newvector2(InternalSpeed)};
}
公共移动包装器移动数据{get;set;}
#区域ICollide成员
公共矩形边界
{
获取{return MoveData.Bounds;}
}
公共纹理2D纹理
{
获取{return\u texture;}
}
#端区ICollide成员
公共作废抽签(SpriteBatch the SpriteBatch)
{
spritebatch.Draw(_纹理,MoveData.Position,null,Color.White,MoveData.Rotation,_原点,1f,SpriteEffects.None,0);//主精灵
PriteBatch.Draw(_axisOrig,MoveData.Position,null,Color.White,0f,_origin,1f,SpriteEffects.None,0);//绿色
PriteBatch.Draw(_axisBase,MoveData.Position,null,Color.White,0f,Vector2.Zero,1f,SpriteEffects.None,0);//红色
}
公共无效加载(ContentManager内容管理器)
{
_纹理=contentmanager.Load(“man”);
_axisBase=contentmanager.Load(“axis”);
_axisOrig=contentmanager.Load(“axisOrig”);
_原点=新矢量2((浮动)\纹理宽度/2,(浮动)\纹理高度/2);
}
public void向前移动(游戏时间游戏时间,键盘状态当前键盘状态)
{
内部移动(游戏时间、当前键盘状态);
}
私有无效内部移动(游戏时间游戏时间,键盘状态当前键盘状态,布尔向前=真)
{
//使移动包装器数据值化的内容(新位置、速度、旋转等)
MoveWrapper pm=MovementsHelper.Move(MoveData.Position,MoveData.Rotation,当前键盘状态,内部速度,
内部运行速度奖励,游戏时间,向前);
pm.Bounds=GetBounds(pm);
MoveData=pm;
}
公共无效向后移动(游戏时间游戏时间,键盘状态当前键盘状态)
{
内部移动(游戏时间,当前键盘状态,false);
}
私有矩形GetBounds(MoveWrapper pm)
{
返回GetBoundingBox(pm、_texture.Width、_texture.Height);
}
公共矩形GetBoundingBox(移动包装器w、整数tWidth、整数tWidth)
{
//1) 获取原始边界向量
//左上=>与位置相同
矢量2 p1=w位置;
//右上角x=x0+宽度,y=与位置相同
向量2 p2=新向量2(w位置X+tWidth,w位置Y);
//右下角x=x0+宽度,y=y0+高度
矢量2 p3=新矢量2(w位置X+tWidth,w位置Y+tWidth);
//左下角x=与位置相同,y=y0+高度
向量2 p4=新向量2(w.Position.X,w.Position.Y+右侧);
//2) 旋转给定旋转和原点的所有点
向量2 p1r=旋转点(p1,w);
向量2 p2r=旋转点(p2,w);
向量2 p3r=旋转点(p3,w);
向量2 p4r=旋转点(p4,w);
//3) 获取向量2布丁矩形位置
var minX=Math.Min(p1r.X,Math.Min(p2r.X,Math.Min(p3r.X,p4r.X));
var maxX=Math.Max(p1r.X,Math.Max(p2r.X,Math.Max(p3r.X,p4r.X));
//4) 获取边框的宽度和高度
var minY=Math.Min(p1r.Y,Math.Min(p2r.Y,Math.Min(p3r.Y,p4r.Y));
var maxY=Math.Max(p1r.Y,Math.Max(p2r.Y,Math.Max(p3r.Y,p4r.Y));
变量宽度=最大值-最小值;
变量高度=最大值-最小值;
//-->开始攻击,使其在0,90180270度下工作
var origMod=新矢量2((浮动)两倍/2,(浮动)右/2);
变量度=(int)MathHelper.ToDegrees(w.旋转);
如果(度==0)
{
minX-=origMod.X;
minY-=origMod.Y;
}
否则,如果(度==90)
{
minX+=原始坐标Y;
minY-=origMod.X;
}
否则,如果(度==180)
{
minX+=origMod.X;
minY+=原始种群Y;
}
否则如果(度==270)
{
minX-=原始模式Y;
minY+=origMod.X;
}

//end hack您可以使用矩阵结构旋转位置

Vector2 p1 = MoveData.Position;
var m = Matrix.CreateRotationZ(angleInRadians);
p1 = Vector2.Transform(p1, m);

如果要围绕原点旋转,则应为:

  var Origin = new Vector3(Origin2D, 0);
  var Position = new Vector3(Position2D, 0);

  var m = Matrix.CreateTranslation(-Origin) 
        * Matrix.CreateRotationZ(angleInRadians) 
        * Matrix.CreateTranslation(Position);

终于找到了让它在没有黑客的情况下工作的方法

    public Vector2 RotatePoint(Vector2 p, MoveWrapper a)
    {

        var wm = Matrix.CreateTranslation(-a.Position.X - _origin.X, -a.Position.Y - _origin.Y, 0)//set the reference point to world reference taking origin into account
                 * Matrix.CreateRotationZ(a.Rotation) //rotate
                 * Matrix.CreateTranslation(a.Position.X, a.Position.Y, 0); //translate back

        var rp = Vector2.Transform(p, wm);
        return rp;
    }
额外的效果,这比我以前的“黑客”方法更精确(就像我画的指南所显示的)


我只是意识到这与布劳的建议非常接近,只是我的第一个翻译将参考值设置回了世界0,0,0减去精灵的起源。我想我当时不明白这个暗示…

已经尝试过了,但没有运气。此外,这需要怎么做