我怎样才能计算精灵的“最远”边缘来创建一个 带有原点的变换精灵周围的矩形轮廓?
我想实现这样的目标 http://oi43.tinypic.com/14l39k0.jpg http://i42.tinypic.com/2m62v41.png 红框是“轮廓”,黑框是 转化的精灵。盒子需要根据角落进行扩展 - 只是 一个边界框真的。
我尝试了各种各样的方程式来找到a的坐标 转换后的精灵:
Transformed.X = pos.X * (float)Math.Cos(angle) - pos.Y * (float)Math.Sin(angle); Transformed.Y = pos.X * (float)Math.Sin(angle) + pos.Y * (float)Math.Cos(angle);
但我似乎无法使其发挥作用。任何想法我怎么能实现这一目标?
任何帮助都将不胜感激。
涓
感谢Zenchovey,我能够解决我的问题。这是我使用的代码:
启动变量
Vector2 TransformPos = Vector2.Zero;
Vector2 TransformPos2 = Vector2.Zero;
float[] px = new float[2];
float[] py = new float[2];
float[] pxl = new float[2];
float[] pyl = new float[2];
float ox;
float oy;
更新方法
// Vars
ox = pos.X;
oy = pos.Y;
// top left
pxl[0] = pos.X - Origin.X;
pyl[0] = pos.Y - Origin.Y;
// bottom left
pxl[1] = pos.X - Origin.X;
pyl[1] = pos.Y + Origin.Y;
// top right
px[0] = pos.X + Origin.X;
py[0] = pos.Y - Origin.Y;
// bottom right
px[1] = pos.X + Origin.X;
py[1] = pos.Y + Origin.Y;
if (rot <= MathHelper.ToRadians(90) && rot >= MathHelper.ToRadians(0))
{
TransformPos.X = (float)Math.Cos(rot) * (pxl.Min() - ox) - (float)Math.Sin(rot) * (pyl.Max() - oy) + ox;
TransformPos.Y = (float)Math.Sin(rot) * (pxl.Min() - ox) + (float)Math.Cos(rot) * (pyl.Min() - oy) + oy;
TransformPos2.X = (float)Math.Cos(rot) * (px.Max() - ox) - (float)Math.Sin(rot) * (py.Min() - oy) + ox;
TransformPos2.Y = (float)Math.Sin(rot) * (px.Max() - ox) + (float)Math.Cos(rot) * (py.Max() - oy) + oy;
}
else
if (rot <= MathHelper.ToRadians(270) && rot >= MathHelper.ToRadians(180))
{
TransformPos2.X = (float)Math.Cos(rot) * (pxl.Min() - ox) - (float)Math.Sin(rot) * (pyl.Max() - oy) + ox;
TransformPos2.Y = (float)Math.Sin(rot) * (pxl.Min() - ox) + (float)Math.Cos(rot) * (pyl.Min() - oy) + oy;
TransformPos.X = (float)Math.Cos(rot) * (px.Max() - ox) - (float)Math.Sin(rot) * (py.Min() - oy) + ox;
TransformPos.Y = (float)Math.Sin(rot) * (px.Max() - ox) + (float)Math.Cos(rot) * (py.Max() - oy) + oy;
}
else
if (rot <= MathHelper.ToRadians(180) && rot >= MathHelper.ToRadians(90))
{
TransformPos2.X = (float)Math.Cos(rot) * (pxl.Max() - ox) - (float)Math.Sin(rot) * (pyl.Min() - oy) + ox;
TransformPos.Y = (float)Math.Sin(rot) * (pxl.Max() - ox) + (float)Math.Cos(rot) * (pyl.Max() - oy) + oy;
TransformPos.X = (float)Math.Cos(rot) * (px.Min() - ox) - (float)Math.Sin(rot) * (py.Max() - oy) + ox;
TransformPos2.Y = (float)Math.Sin(rot) * (px.Min() - ox) + (float)Math.Cos(rot) * (py.Min() - oy) + oy;
}
else
if (rot <= MathHelper.ToRadians(360) && rot >= MathHelper.ToRadians(270))
{
TransformPos.X = (float)Math.Cos(rot) * (pxl.Max() - ox) - (float)Math.Sin(rot) * (pyl.Min() - oy) + ox;
TransformPos2.Y = (float)Math.Sin(rot) * (pxl.Max() - ox) + (float)Math.Cos(rot) * (pyl.Max() - oy) + oy;
TransformPos2.X = (float)Math.Cos(rot) * (px.Min() - ox) - (float)Math.Sin(rot) * (py.Max() - oy) + ox;
TransformPos.Y = (float)Math.Sin(rot) * (px.Min() - ox) + (float)Math.Cos(rot) * (py.Min() - oy) + oy;
}
Transform = new Rectangle((int)TransformPos.X, (int)TransformPos.Y, (int)TransformPos2.X - (int)TransformPos.X, (int)TransformPos2.Y - (int)TransformPos.Y);
它根据它的旋转来查找精灵角的最大值和最小值,以制作边界框。 代码假设原点是精灵的中间位置,你必须根据原点更改代码
答案 0 :(得分:0)
如果在未旋转的精灵上找到每个角的位置,然后围绕点旋转它们,则进行旋转以找到旋转精灵的每个角。 (How to do this is described here)
然后您可以找到这些点的最大值和最小值x和y值。 minX和minY将是你的边界矩形的左上角,maxX和maxY将是你的边界矩形的右下角。
答案 1 :(得分:0)
我试图在一年前左右将一个对撞机放在旋转的矩形物体(汽车)上,然后空了。虽然你可以旋转精灵,但是为了碰撞,你不能围绕它旋转一个矩形。
我最终在我的对象上使用了一个“完成工作”的圆圈,但并不完美。我读到的其他解决方案包括在一个矩形物体上放置三个圆圈(一个在前面,一个在中间,一个在后面)。报道非常好,但数学比我想要的要多。
作为最后的手段,是否有一个未旋转的矩形可以对你的精灵进行所有可能的旋转?
这些都不是完美的,但它们可能足够接近。
干杯, 甲
答案 2 :(得分:0)
我知道这个问题有点老了,但是如果有人对工作简单的MonoGame解决方案感兴趣(还要考虑纹理大小,因为在MonoGame中起源是基于纹理大小而不是dest rect),这是一个:
/// <summary>
/// Rotate a vector around pivot.
/// </summary>
/// <param name="vec">Vector to rotate.</param>
/// <param name="pivot">Point to rotate around.</param>
/// <param name="theta">Rotation angle.</param>
/// <returns>Rotated vector.</returns>
public static Vector2 RotateAround(Vector2 vec, Vector2 pivot, float theta)
{
return new Vector2(
(float)(System.Math.Cos(theta) * (vec.X - pivot.X) - System.Math.Sin(theta) * (vec.Y - pivot.Y) + pivot.X),
(float)(System.Math.Sin(theta) * (vec.X - pivot.X) + System.Math.Cos(theta) * (vec.Y - pivot.Y) + pivot.Y));
}
/// <summary>
/// Get rectangle and rotation (angle + origin) and calculate bounding box containing the rotated rect.
/// </summary>
/// <param name="rect">Rectangle to rotate.</param>
/// <param name="rotation">Rotation angle.</param>
/// <param name="origin">Rotation origin.</param>
/// <param name="textureSize">In MonoGame origin is relative to source texture size, not dest rect.
/// So this param specify source texture size.</param>
/// <returns>Rotated rectangle bounding box.</returns>
public static Rectangle GetRotatedBoundingBox(Rectangle rect, float rotation, Vector2 origin, Rectangle textureSize)
{
// fix origin to be relative to rect location + fix it to be relative to rect size rather then texture size
var originSize = ((origin / textureSize.Size.ToVector2()) * rect.Size.ToVector2());
var convertedOrigin = rect.Location.ToVector2() + originSize;
// calculate top-left rotated corner
var topLeft = RotateAround(rect.Location.ToVector2(), convertedOrigin, rotation);
// calculate rest of rotated corners
Vector2[] corners = new Vector2[] {
RotateAround(new Vector2(rect.Left, rect.Bottom), convertedOrigin, rotation),
RotateAround(new Vector2(rect.Right, rect.Bottom), convertedOrigin, rotation),
RotateAround(new Vector2(rect.Right, rect.Top), convertedOrigin, rotation)
};
// find min and max points
Vector2 min, max;
min = max = topLeft;
foreach (var corner in corners)
{
if (corner.X < min.X) min.X = corner.X;
if (corner.Y < min.Y) min.Y = corner.Y;
if (corner.X > max.X) max.X = corner.X;
if (corner.Y > max.Y) max.Y = corner.Y;
}
// create rectangle from min-max and return it
return new Rectangle(min.ToPoint() - originSize.ToPoint(), (max - min).ToPoint());
}
只需将这两个静态函数添加到某个类中,然后使用Draw参数调用GetRotatedBoundingBox()。
用法示例:
// update rotation and start batch
rotation += 0.01f;
spriteBatch.Begin();
// dest and origin values (play with these to see different results)
var dest = new Rectangle(new Point(200, 200), new Point(100, 200));
var origin = new Vector2(15, 200);
// draw sprite
spriteBatch.Draw(rectTexture, dest, null, Color.White, rotation, origin, SpriteEffects.None, 0f);
// draw sprite bounding box (in my case I put the functions under Source.Graphics.Utils static class)
var boundingBox = Source.Graphics.Utils.GetRotatedBoundingBox(dest, rotation, origin, rectTexture.Bounds);
spriteBatch.Draw(rectTexture, boundingBox, Color.Red);
// end batch
spriteBatch.End();