c# AntiSocialRobots 源码分析
2014-03-02 11:28
232 查看
需求:鼠标点击画布,画出 Robot 对象,每个 Robot 可以自己寻找路径,保证最后所有的 Robot 在画布上均匀分布。
定义 Robot 类
定义 RoomPosition 类
鼠标点击位置转换为画布位置
模拟 Robot 移动一个位置,对于 Robot 对象来说,它并不需要知道自己在屏幕上的实际位置,它只应当知道自己在房间中(画布)的位置,因此模拟移动一个位置,应当只改变 Robot 对象的 RoomPosition.
Robot 在屏幕上的位置由主程序来控制,根据 RoomPosition 来转换。这样虽然进行了两次位置转换,但是剥离了业务和实现之间的耦合,使代码更简洁。
Robot 屏幕位置计算:
界面加载起来之后, action 就会一直在后台执行,计算 Robot 位置,并在界面上画出来。
技巧:
private TaskFactory _uiTasks;
_uiTasks=new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
//在 Action 中执行异步操作。
_uiTasks.StartNew(()=>{});
_uiTasks.StartNew(delegate{});
定义 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)); }
模拟 Robot 移动一个位置,对于 Robot 对象来说,它并不需要知道自己在屏幕上的实际位置,它只应当知道自己在房间中(画布)的位置,因此模拟移动一个位置,应当只改变 Robot 对象的 RoomPosition.
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 在屏幕上的位置由主程序来控制,根据 RoomPosition 来转换。这样虽然进行了两次位置转换,但是剥离了业务和实现之间的耦合,使代码更简洁。
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(); };
界面加载起来之后, action 就会一直在后台执行,计算 Robot 位置,并在界面上画出来。
技巧:
private TaskFactory _uiTasks;
_uiTasks=new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
//在 Action 中执行异步操作。
_uiTasks.StartNew(()=>{});
_uiTasks.StartNew(delegate{});
相关文章推荐
- C# Synchronized 和 SyncRoot 实现线程同步的源码分析及泛型集合的线程安全访问
- Spring Security 源码分析(四):Spring Social实现微信社交登录
- 格点数据等值线分析--C#源码
- C#中Queue<T>类的使用以及部分方法的源码分析
- 从分析家中得到股票数据!C#源码 (代码很长,建议火狐)
- C# List源码分析(二)
- des加密解密源码 C# key值问题分析
- Spring Security源码分析四:Spring Social实现微信社交登录
- @Html.AntiForgeryToken() 源码分析,表单防伪码的生成
- C#编写数据分析软件(附源码)
- C# List源码分析(二)
- Spring Security源码分析六:Spring Social社交登录源码解析
- C#开发的人脸左右相似度计算软件源码分析
- C# Synchronized 和 SyncRoot 实现线程同步的源码分析及泛型集合的线程安全访问
- Spring Security源码分析十四:Spring Social 社交登录的绑定与解绑
- des加密解密源码 C# key值问题分析
- C#中Stack<T>类的使用及部分成员函数的源码分析
- C#分析数据库结构,使用XSL模板自动生成代码 - 清清月儿 .NET万花筒 Asp.net技术 Asp.net教程 Asp.net源码 Asp.net基础 Asp.net控件 Asp.net入门 - CSDNBlog
- [C#]委托实例分析(附源码)
- Spring Security源码分析十四:Spring Social社交登录的绑定与解绑