Reputation: 142
Been rather busy posting today and creating an AI program to simulate Boids. Right now I am just working on getting a single "boids" drawing a moving around. The "boid" is just a circle(ellipsis) with a line draw to symbolize its "Forward Vector".
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;
}
}
Currently when running a program implementing this class, instantiate a default SwarmCir() and just calling the moving functions at the bottom I get really weird results. Essentially I want 'W' to move the circle along the "forward vector" which ever way the line is pointing. Obviously for 'S' is just reverse. Then when turning I would like the shape and line to turn properly. If more information is needed Please ask. Working towards a complete AI workbench.
Upvotes: 1
Views: 2225
Reputation: 3266
Since you're only drawing a circle and a line, I would skip the transformations used in the Rotate method. I would also store the forward vector instead of the forward point and rotAngle in the class. And use a PointF for position instead of float _pointX/_pointY, and a radius instead of width/height, since they will be equal for circles. I would also make the fields private to avoid modification from outside the class.
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);
Then, I would use _point as the center point for the circles (in your code, the _pointX/_pointY refers to a point to the top/left of the circle). The draw and move methods then becomes:
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;
}
By the way, I often define some extension methods for PointF to ease adding and multiplying PointF's and scalars.
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);
}
}
This makes the draw and move methods code a bit more elegant in my opinion:
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);
}
Alright, now there's just the rotation left. Start by adding the Rotate method to 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)));
}
The turn methods then becomes:
public void TurnLeft()
{
_forwardVector = _forwardVector.Rotate(10.0f);
}
Lets hope that works out. I haven't compiled and tested this code so there might be some typos...
Upvotes: 2
Reputation: 1986
I've had a quick look at your code and in TurnLeft()
and TurnRight()
you change the field rotAng
, a field that you don't use elsewhere in your class. Perhaps ForwardVec()
should use it? Perhaps multiply some x coordinate with Math.Cos(rotAng)
and a y coordinate with Math.Sin(rotAng)
?
Just guessing here...
Upvotes: 0