我现在正在经历一场噩梦,试图找到正确的公式来获得一个与我的精灵方向相对应的边界框。
我知道 !互联网上有很多例子、解决方案、解释,包括这里,在这个网站上。但相信我,我都试过了。我试图只应用解决方案,我试图理解解释,但每篇文章都给出了不同的解决方案,但它们都不起作用。
我显然在这里遗漏了一些重要的东西......
所以,基本上,我有一个精灵,它的纹理是原生的(20 宽 * 40 高)并且在启动应用程序时位于 (200,200)。精灵起源是经典
_origin = new Vector2((float)_texture.Width / 2, (float)_texture.Height / 2);
所以 origin 会返回一个 (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 岁的孩子解释一样,因为关于数学,这就是我!
:)
编辑:我找到了一个 hack 让它在 0、90、180、270 度下工作,但现在我被困在中间位置(45,135,215、325 度),这让我认为必须有一种方法来计算所有这些东西在一个适用于任何角度的单一公式中......