用向前矢量绘制一个圆,并随着旋转同时移动两者
本文关键字:旋转 移动 一个 绘制 | 更新日期: 2023-09-27 18:31:44
今天忙着发帖,并创建一个AI程序来模拟Boids。现在我只是在努力让一个"boids"画一个移动。"boid"只是一个圆(省略号),用线条绘制来象征其"前向量"。
class SwarmCir
{
public float _pointX;
public float _pointY;
public float _height;
public float _width;
Pen _pen = new Pen(Color.Black);
PointF _ForwardPoint = new PointF(0, 0);
float rotAng = 0.0f;
public SwarmCir()
{
_pointX = 1.0f;
_pointY = 1.0f;
_height = 5.0f;
_width = 5.0f;
_ForwardPoint.X = 7.0f;
_ForwardPoint.Y = 7.0f;
}
public SwarmCir(Point XY)
{
_pointX = XY.X;
_pointY = XY.Y;
_height = 5.0f;
_width = 5.0f;
}
public SwarmCir( Point XY, float Height, float Width )
{
_pointX = XY.X;
_pointY = XY.Y;
_height = Height;
_width = Width;
}
public void SetPen(Pen p)
{
_pen = p;
}
public void Draw(Graphics g)
{
g.DrawEllipse(_pen, _pointX, _pointY, _width, _height);
g.DrawLine(_pen, new PointF(_pointX, _pointY), _ForwardPoint);
}
public void Rotate(PaintEventArgs e)
{
e.Graphics.TranslateTransform(_pointX, _pointY);
e.Graphics.RotateTransform(rotAng);
e.Graphics.TranslateTransform(-_pointX, -_pointY);
}
public PointF ForwardVec()
{
PointF temp = new PointF();
temp.X = _pointX - _ForwardPoint.X;
temp.Y = _pointY - _ForwardPoint.Y;
return Normalize(temp);
}
public PointF Normalize(PointF p)
{
PointF temp = new PointF();
if (p.X > p.Y)
{
temp.X = 1;
temp.Y = p.Y / p.X;
}
else if (p.Y > p.X)
{
temp.Y = 1;
temp.X = p.X / p.Y;
}
else
{
return new PointF(1, 1);
}
return temp;
}
public void MoveForward()
{
_pointX += ForwardVec().X;
_pointY += ForwardVec().Y;
}
public void MoveBackwards()
{
_pointX -= ForwardVec().X;
_pointY -= ForwardVec().Y;
}
public void TurnLeft()
{
rotAng += 10.0f;
}
public void TurnRight()
{
rotAng -= 10.0f;
}
}
目前,在运行实现此类的程序时,实例化默认的 SwarmCir() 并调用底部的移动函数,我得到了非常奇怪的结果。从本质上讲,我希望"W"沿"向前向量"移动圆圈,无论该向量指向线指向何处。显然,对于"S"来说只是相反的。然后在转弯时,我希望形状和线条正确转动。如果需要更多信息,请询问。致力于打造完整的 AI 工作台。
由于您只绘制一个圆和一条线,因此我将跳过 Rotate 方法中使用的转换。我还会在类中存储正向向量,而不是正向点和 rotAngle。并使用 PointF 表示位置而不是浮点 _pointX/_pointY,并使用半径而不是宽度/高度,因为它们对于圆是相等的。我还会将字段设为私有,以避免从类外部进行修改。
class SwarmCir
{
private PointF _point;
private PointF _forwardVector = new PointF(1, 0);
private float _radius = 2.5f;
private float _vectorLength = 5.0f;
private Pen _pen = new Pen(Color.Black);
然后,我会使用 _point 作为圆圈的中心点(在您的代码中,_pointX/_pointY 是指圆圈顶部/左侧的点)。然后,绘制和移动方法变为:
public void Draw(Graphics g)
{
g.DrawEllipse(_pen, _point.X - _radius, _point.Y - _radius, 2 * _radius, 2 * _radius);
g.DrawLine(_pen, _point,
new PointF(_point.X + _forwardVector.X * _vectorLength,
_point.Y + _forwardVector.Y * _vectorLength));
}
public void MoveForward()
{
_point.X += _forwardVector.X;
_point.Y += _forwardVector.Y;
}
顺便说一下,我经常为 PointF 定义一些扩展方法,以简化 PointF 和标量的添加和乘法。
static class PointFExtensions
{
public static PointF Add(this PointF point, PointF other)
{
return new PointF(point.X + other.X, point.Y + other.Y);
}
public static PointF Add(this PointF point, float value)
{
return new PointF(point.X + value, point.Y + value);
}
public static PointF Multiply(this PointF point, PointF other)
{
return new PointF(point.X * other.X, point.Y * other.Y);
}
public static PointF Multiply(this PointF point, float value)
{
return new PointF(point.X * value, point.Y * value);
}
}
在我看来,这使得绘制和移动方法的代码更加优雅:
public void Draw(Graphics g)
{
g.DrawEllipse(_pen, _point.X - _radius, _point.Y - _radius, 2 * _radius, 2 * _radius);
g.DrawLine(_pen, _point, _point.Add(_forwardVector.Multiply(_vectorLength)));
}
public void MoveForward()
{
_point = _point.Add(_forwardVector);
}
好了,现在只剩下轮换了。首先将 Rotate 方法添加到 PointFExtensions:
public static PointF Rotate(this PointF point, double angle)
{
angle *= Math.PI / 180.0; // Convert from degrees to radians
return new PointF(
Convert.ToSingle(point.X * Math.Cos(angle) - point.Y * Math.Sin(angle)),
Convert.ToSingle(point.X * Math.Sin(angle) + point.Y * Math.Cos(angle)));
}
然后,转弯方法变为:
public void TurnLeft()
{
_forwardVector = _forwardVector.Rotate(10.0f);
}
让我们希望这能成功。我还没有编译和测试这段代码,所以可能会有一些错别字......
我快速浏览了您的代码,并在TurnLeft()
和TurnRight()
中更改了字段rotAng
,该字段在类中的其他地方不使用。也许ForwardVec()
应该使用它?也许将一些 x 坐标与 Math.Cos(rotAng)
相乘,将 y 坐标与 Math.Sin(rotAng)
相乘?
只是在这里猜测...