1.这是代码的最大块,创建一个名为“PathFinder.cs”的新文件并将其放在MirObjects文件夹中
码:
using Client.MirScenes;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
namespace Client.MirObjects
{
public class Heap<T> where T : IHeapItem<T>
{
private T[] items;
private int currentItemCount;
public Heap(int maxHeapSize)
{
items = new T[maxHeapSize];
}
public void Add(T item)
{
item.HeapIndex = currentItemCount;
items[currentItemCount] = item;
SortUp(item);
currentItemCount++;
}
public T RemoveFirst()
{
T firstItem = items[0];
currentItemCount--;
items[0] = items[currentItemCount];
items[0].HeapIndex = 0;
SortDown(items[0]);
return firstItem;
}
public void UpdateItem(T item)
{
SortUp(item);
}
public int Count { get { return currentItemCount; } }
public bool Contains(T item)
{
return Equals(items[item.HeapIndex], item);
}
private void SortDown(T item)
{
while (true)
{
int childIndexLeft = (item.HeapIndex * 2) + 1;
int childIndexRight = (item.HeapIndex * 2) + 2;
int swapIndex = 0;
if(childIndexLeft < currentItemCount)
{
swapIndex = childIndexLeft;
if(childIndexRight < currentItemCount)
{
if(items[childIndexLeft].CompareTo(items[childIndexRight]) < 0)
{
swapIndex = childIndexRight;
}
}
if(item.CompareTo(items[swapIndex]) < 0)
{
Swap(item, items[swapIndex]);
}
else
{
return;
}
}
else
{
return;
}
}
}
private void SortUp(T item)
{
int parentIndex = (item.HeapIndex - 1) / 2;
while (true)
{
T parentItem = items[parentIndex];
if (item.CompareTo(parentItem) > 0)
{
Swap(item, parentItem);
}
else
break;
parentIndex = (item.HeapIndex - 1) / 2;
}
}
private void Swap(T itemA, T itemB)
{
items[itemA.HeapIndex] = itemB;
items[itemB.HeapIndex] = itemA;
int itemAIndex = itemA.HeapIndex;
itemA.HeapIndex = itemB.HeapIndex;
itemB.HeapIndex = itemAIndex;
}
}
public interface IHeapItem<T> :IComparable<T>
{
int HeapIndex
{
get;set;
}
}
public class Node : IHeapItem<Node>
{
public bool Walkable
{
get { return Map.EmptyCell(Location); }
}
public MapControl Map;
public Point Location;
public Node Parent;
public int GCost, HCost;
public int FCost
{
get { return GCost + HCost; }
}
private int _heapIndex;
public int HeapIndex
{
get { return _heapIndex; }
set { _heapIndex = value; }
}
public int CompareTo(Node nodeToCompare)
{
int compare = FCost.CompareTo(nodeToCompare.FCost);
if (compare == 0)
{
compare = HCost.CompareTo(nodeToCompare.HCost);
}
return -compare;
}
public Node(MapControl map, int x, int y)
{
Map = map;
Location = new Point(x, y);
}
}
public class PathFinder
{
private Node[,] Grid;
public MapControl Map;
public int MaxSize
{
get { return Map.Width * Map.Height; }
}
public PathFinder(MapControl map)
{
Map = map;
CreateGrid();
}
private void CreateGrid()
{
Grid = new Node[Map.Width, Map.Height];
for (int x = 0; x < Map.Width; x++)
{
for (int y = 0; y < Map.Height; y++)
{
Grid[x, y] = new Node(Map, x, y);
}
}
}
public List<Node> FindPath(Point start, Point target)
{
Node startNode = GetNode(start);
Node targetNode = GetNode(target);
Heap<Node> openSet = new Heap<Node>(MaxSize);
HashSet<Node> closedSet = new HashSet<Node>();
openSet.Add(startNode);
while (openSet.Count > 0)
{
Node currentNode = openSet.RemoveFirst();
closedSet.Add(currentNode);
if (currentNode == targetNode)
{
return RetracePath(startNode, targetNode);
}
foreach (Node neighbor in GetNeighbours(currentNode))
{
if (!neighbor.Walkable || closedSet.Contains(neighbor))
continue;
int newMovementCostToNeighbor = currentNode.GCost + GetDistance(currentNode, neighbor);
if (newMovementCostToNeighbor < neighbor.GCost || !openSet.Contains(neighbor))
{
neighbor.GCost = newMovementCostToNeighbor;
neighbor.HCost = GetDistance(neighbor, targetNode);
neighbor.Parent = currentNode;
if (!openSet.Contains(neighbor))
openSet.Add(neighbor);
else
{
openSet.UpdateItem(neighbor);
}
}
}
}
return null;
}
public List<Node> RetracePath(Node startNode, Node endNode)
{
List<Node> path = new List<Node>();
Node currentNode = endNode;
while (currentNode != startNode)
{
path.Add(currentNode);
currentNode = currentNode.Parent;
}
path.Add(startNode);
path.Reverse();
return path;
}
private int GetDistance(Node nodeA, Node nodeB)
{
int distX = Math.Abs(nodeA.Location.X - nodeB.Location.X);
int distY = Math.Abs(nodeA.Location.Y - nodeB.Location.Y);
if (distX > distY)
return 14 * distY + (10 * (distX - distY));
return 14 * distX + (10 * (distY - distX));
}
private Node GetNode(Point location)
{
return Grid[location.X, location.Y];
}
private List<Node> GetNeighbours(Node node)
{
List<Node> neighbours = new List<Node>();
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0) continue;
int checkX = node.Location.X + x;
int checkY = node.Location.Y + y;
if (checkX >= 0 && checkX < Grid.GetLength(0) && checkY >= 0 && checkY < Grid.GetLength(1))
{
neighbours.Add(Grid[checkX, checkY]);
}
}
}
return neighbours;
}
}
}
2.找到“public sealed class BigMapDialog:MirControl”,然后删除以下行
码:
NotControl = true;
3.在BigMapDialog()构造函数中添加以下行,然后在其下面的方法中添加
码:
MouseDown += OnMouseClick;
码:
private void OnMouseClick(object sender, MouseEventArgs e)
{
int X = (int)Math.Floor(((e.X - Location.X) / scaleX) + startPointX);
int Y = (int)Math.Floor(((e.Y - Location.Y) / scaleY) + startPointY);
var path = GameScene.Scene.MapControl.PathFinder.FindPath(MapObject.User.CurrentLocation, new Point(X, Y));
if (path == null || path.Count == 0)
{
GameScene.Scene.ChatDialog.ReceiveChat("Could not find suitable path.", ChatType.System);
}
else
{
GameScene.Scene.MapControl.CurrentPath = path;
GameScene.Scene.MapControl.AutoPath = true;
}
}
4.进一步查找“private void OnBeforeDraw()”。在方法的底部添加以下代码
码:
if (GameScene.Scene.MapControl.AutoPath)
{
foreach (var node in GameScene.Scene.MapControl.CurrentPath)
{
Color colour = Color.White;
float x = ((node.Location.X - startPointX) * scaleX) + Location.X;
float y = ((node.Location.Y - startPointY) * scaleY) + Location.Y;
DXManager.Sprite.Draw2D(DXManager.RadarTexture, Point.Empty, 0, new PointF((int)(x - 0.5F), (int)(y - 0.5F)), colour);
}
}
5.找到“公共密封类MapControl:MirControl”。在顶部附近(构造函数外部)添加以下内容
码:
private bool _autoPath;
public bool AutoPath
{
get
{
return _autoPath;
}
set
{
if (_autoPath == value) return;
_autoPath = value;
if (!_autoPath)
CurrentPath = null;
if (GameScene.Scene != null)
GameScene.Scene.ChatDialog.ReceiveChat(value ? "[AutoPath: On]" : "[AutoPath: Off]", ChatType.Hint);
}
}
public PathFinder PathFinder = null;
public List<Node> CurrentPath = null;
6.找到“CheckInput()”方法,然后找到“if(MapObject.TargetObject == null || MapObject.TargetObject.Dead)return;”
在它上面,添加以下代码。
码:
if (AutoPath)
{
if (CurrentPath == null || CurrentPath.Count == 0)
{
AutoPath = false;
return;
}
Node currentNode = CurrentPath.SingleOrDefault(x => User.CurrentLocation == x.Location);
if (currentNode != null)
{
while (true)
{
Node first = CurrentPath.First();
CurrentPath.Remove(first);
if (first == currentNode)
break;
}
}
if (CurrentPath.Count > 0)
{
MirDirection dir = Functions.DirectionFromPoint(User.CurrentLocation, CurrentPath.First().Location);
Node upcomingStep = CurrentPath.SingleOrDefault(x => Functions.PointMove(User.CurrentLocation, dir, 2) == x.Location);
if (!CanWalk(dir))
{
CurrentPath = PathFinder.FindPath(MapObject.User.CurrentLocation, CurrentPath.Last().Location);
return;
}
if (GameScene.CanRun && CanRun(dir) && CMain.Time > GameScene.NextRunTime && User.HP >= 10 && CurrentPath.Count > 1 && upcomingStep != null)
{
User.QueuedAction = new QueuedAction { Action = MirAction.Running, Direction = dir, Location = Functions.PointMove(User.CurrentLocation, dir, 2) };
return;
}
if (CanWalk(dir))
{
User.QueuedAction = new QueuedAction { Action = MirAction.Walking, Direction = dir, Location = Functions.PointMove(User.CurrentLocation, dir, 1) };
return;
}
}
}
7.找到“if(CMain.Alt)” - 在它上面添加
码:
if (AutoPath)
AutoPath = false;
就这样。我认为可以改进很多,但希望你能建议如何做到这一点。
为了提高效率,我在最大的地图(Bichon)和最复杂的地图(Prajna Temple)上进行了测试 - 在最糟糕的情况下绘制和绘制路线的时间不到10毫秒。除非找不到路线,否则它必须绘制每个坐标,这对于Bichon来说需要500毫秒。
它可能值得线程化,以便客户端不受影响。
使用
打开你的bigmap并点击某个地方。左键单击其他任何地方取消。
寻路算法代码分享
摘要:
...
您需要 登录账户 后才能发表评论
还没有评论,来说两句吧...