我现在正在经历一场噩梦,试图找到合适的公式来获得与我的精灵方向相对应的边界框。
我知道!互联网上有很多例子,解决方案和解释,包括这里,在这个网站上。但相信我,我已经尝试过所有这些。我试图只应用解决方案,我试图理解解释,但每个帖子都给出了不同的解决方案,但没有一个能够解决。
我显然错过了一些重要的事情......
所以,基本上,我有一个精灵,当启动应用程序时,纹理本身(20宽* 40高)和位于(200,200)。精灵起源是经典的
_origin = new Vector2((float)_texture.Width / 2, (float)_texture.Height / 2);
因此,原点将返回(5.5; 8)向量2
通过键盘输入,我可以旋转此精灵。默认旋转为0或Key.Up.然后,旋转90对应于Key.Right,180对应于Key.Down,依此类推......
目前,没有任何动作,只是轮换。
所以这是我的代码来计算边界矩形:
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);
}
}
旋转参数是MathHelper度到弧度的结果。
我有一个绘制对应于边界框的矩形的函数,我希望边界框与我的精灵完全重叠,至少对于0,90,180和270度角度旋转。
相反,我在旋转计算后有奇怪的坐标: - 当旋转到90°时,边界框X为负(因此框不可见) - 当旋转到180°时,边界框X和Y为负(因此框不可见) - 当旋转到270°时,边界框Y为负(因此框不可见)
有人可以向我解释我做错了什么,就像向3岁的孩子解释一样,因为关于数学,我就是这样!
:)
编辑 :我发现了一个黑客让它在0度,90度,180度,270度下工作但现在我被困在中间位置(45,135,215,325)度,这让我觉得必须在一个公式中计算所有那些东西,以适用于任何角度...
答案 0 :(得分:1)
终于找到了让它在没有黑客的情况下工作的方法!!!!!!!!!!!!!!!!
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;
}
奖金效果,这比我以前的“hacky”方法更准确(正如我所绘制的指南所示)
我认为这与Blau提出的非常接近,只是我的第一次翻译将参考设置回世界0,0,0减去精灵起源。我猜id当时并不理解这个暗示......
答案 1 :(得分:0)
您可以使用矩阵结构旋转位置。
Vector2 p1 = MoveData.Position;
var m = Matrix.CreateRotationZ(angleInRadians);
p1 = Vector2.Transform(p1, m);
答案 2 :(得分:0)
如果你想围绕一个原点旋转它应该是:
var Origin = new Vector3(Origin2D, 0);
var Position = new Vector3(Position2D, 0);
var m = Matrix.CreateTranslation(-Origin)
* Matrix.CreateRotationZ(angleInRadians)
* Matrix.CreateTranslation(Position);