需求:鼠标点击画布,画出 Robot 对象,每个 Robot 可以自己寻找路径,保证最后所有的 Robot 在画布上均匀分布。
定义 Robot 类
namespace AntisocialRobots
{
/// <summary>Represents one robot.</summary>
internal class Robot
{
/// <summary>The visual element used to represent the robot on the screen.</summary>
public Ellipse Element;
/// <summary>The current location of the robot within the room.</summary>
public RoomPoint Location;
/// <summary>The game frame in which this robot was last moved.</summary>
public int LastMovedFrame;
}
}定义 RoomPosition 类
namespace AntisocialRobots
{
internal struct RoomPoint
{
public int X;
public int Y;
public RoomPoint(int x, int y)
{
X = x;
Y = y;
}
public double DistanceTo(RoomPoint other) { return Math.Sqrt(Square(other.X-X)+Square(other.Y-Y));}
public double AngleTo(RoomPoint other) { return Math.Atan2(other.Y - Y, other.X - X); }
public static double Square(double n) { return n*n; }
}
}
鼠标点击位置转换为画布位置
RoomPoint MousePositionToRoomPoint(MouseEventArgs e)
{
Point pt = e.GetPosition(Room);
return new RoomPoint((int)(pt.X * ROOM_SIZE), (int)(pt.Y * ROOM_SIZE));
}void SimulateOneStep(Robot r)
{
RoomPoint ptR = r.Location;
double vectorX = 0, vectorY = 0;
foreach (Robot s in _robots)
{
if (r == s) continue;
RoomPoint ptS = s.Location;
double inverseSquareDistance = 1.0 / RoomPoint.Square(ptR.DistanceTo(ptS));
double angle = ptR.AngleTo(ptS);
vectorX -= inverseSquareDistance * Math.Cos(angle);
vectorY -= inverseSquareDistance * Math.Sin(angle);
}
double degrees = Math.Atan2(vectorY, vectorX) * 180 / Math.PI;
degrees += 22.5;
while (degrees < 0) degrees += 360;
while (degrees >= 360) degrees -= 360;
int direction = (int)(degrees * 8 / 360);
if ((direction == 7) || (direction == 0) || (direction == 1))
ptR.X = Math.Min(ptR.X + 1, ROOM_SIZE - 1);
else if ((direction == 3) || (direction == 4) || (direction == 5))
ptR.X = Math.Max(ptR.X - 1, 0);
if ((direction == 1) || (direction == 2) || (direction == 3))
ptR.Y = Math.Min(ptR.Y + 1, ROOM_SIZE - 1);
else if ((direction == 5) || (direction == 6) || (direction == 7))
ptR.Y = Math.Max(ptR.Y - 1, 0);
if (((ptR.X != r.Location.X) || (ptR.Y != r.Location.Y)) && _roomCells[ptR.X, ptR.Y] == null)
{
_roomCells[r.Location.X, r.Location.Y] = null;
_roomCells[ptR.X, ptR.Y] = r;
r.Location = new RoomPoint(ptR.X, ptR.Y);
}
}Robot 屏幕位置计算:
void SetRobotElementPosition(Robot robot, RoomPoint pt)
{
Canvas.SetLeft(robot.Element,((double)pt.X)/ROOM_SIZE);
Canvas.SetTop(robot.Element,((double)pt.Y)/ROOM_SIZE);
}现在问题是必须一直执行后台计算来保证 Robot 在画布上画出来之后,能够自己去计算位置,并在画布上画出新的位置。也就是说不能只在画 Robot 这个动作的完成的时候计算位置,而是在程序运行期间都要计算所有 Robot 的位置。使用线程可以完成这个任务:
Action recomputeAndRedraw = null;
recomputeAndRedraw = delegate
{
Dispatcher.BeginInvoke((Action)delegate
{
PerformSimulationStep();
recomputeAndRedraw();
}, DispatcherPriority.Background);
};
Loaded += delegate
{
_framesPerSecondStopwatch.Start();
recomputeAndRedraw();
};
c# AntiSocialRobots 源码分析,布布扣,bubuko.com
原文:http://blog.csdn.net/changtianshuiyue/article/details/20283725