下面是算法主要源码:
- 在这个项目我事实上做了一些变通,Km和H的计算方式没有完全依据算法,另外去掉了一些感觉用不上的过程
- 还有队列的储存方式为了贪方便只是用了个单向链表,查找时还是很慢的,如果改变储存方式其实能有进一步提升
Key类和Key的单向链表(U队列)
using System.Collections;
using System.Collections.Generic;
public class Key
{
static int idGiver;
public double Key1;
public double Key2;
public int id;
public Key()
{
id = idGiver;
idGiver++;
}
public void CopyKey(Key copyFrom)
{
Key1 = copyFrom.Key1;
Key2 = copyFrom.Key2;
id = copyFrom.id;
}
public static bool operator <(Key a, Key b)
{
if (a.Key1 < b.Key1)
return true;
else if (a.Key1 > b.Key1)
return false;
else if (a.Key2 < b.Key2)
return true;
else
return false;
}
public static bool operator >(Key a, Key b)
{
if (a.Key1 > b.Key1)
return true;
else if (a.Key1 < b.Key1)
return false;
else if (a.Key2 > b.Key2)
return true;
else
return false;
}
public static bool operator ==(Key a, Key b)
{
if ((a as object) != null)
return a.Equals(b);
else
return (b as object) == null;
}
public static bool operator !=(Key a, Key b)
{
if ((a as object) != null)
return !a.Equals(b);
else
return (b as object) != null;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if ((obj.GetType().Equals(this.GetType())) == false)
{
return false;
}
Key b = (Key)obj;
return Key1 == b.Key1 && Key2 == b.Key2 && id == b.id;
}
public override int GetHashCode()
{
return Key1.GetHashCode() ^ Key2.GetHashCode() ^ id.GetHashCode();
}
}
public class KeyQueue
{
private KeyQueue(KeyQueueElement givenHead)
{
head = givenHead;
}
public int Count { get { return count; } }
public Node PeekFirstNode
{
get
{
if (head != null)
{
return head.node;
}
else
{
return null;
}
}
}
public Key PeekFirstKey
{
get
{
if (head != null)
{
return head.key;
}
else
{
return null;
}
}
}
KeyQueueElement head;
int count = 0;
private class KeyQueueElement
{
public Key key;
public Node node;
public KeyQueueElement nextElement;
}
public static KeyQueue CreateList(Key givenKey, Node givenNode)
{
givenNode.InsertKey = givenKey;
KeyQueueElement creatingHead = new KeyQueueElement()
{
key = givenNode.InsertKey,
node = givenNode,
};
KeyQueue U = new KeyQueue(creatingHead);
U.count++;
return U;
}
public void Insert(Key givenKey, Node givenNode)
{
givenNode.InsertKey = givenKey;
count++;
KeyQueueElement insertElement = new KeyQueueElement
{
key = givenNode.InsertKey,
node = givenNode,
};
if (head == null)
{
head = insertElement;
return;
}
else if (givenKey < head.key)
{
insertElement.nextElement = head;
head = insertElement;
return;
}
else
{
KeyQueueElement tempListElement = head;
KeyQueueElement tempNextElement = head.nextElement;
while (tempNextElement != null)
{
if (givenKey < tempNextElement.key)
{
insertElement.nextElement = tempNextElement;
tempListElement.nextElement = insertElement;
return;
}
else
{
tempListElement = tempNextElement;
tempNextElement = tempListElement.nextElement;
}
}
tempListElement.nextElement = insertElement;
return;
}
}
public void RemoveFirst()
{
head.node.InsertKey = null;
count--;
head = head.nextElement;
}
public void Remove(Node givenNode)
{
Key insertKey = givenNode.InsertKey;
if(insertKey == null)
{
return;
}
if (head == null)
{
return;
}
if (insertKey == head.key)
{
head = head.nextElement;
givenNode.InsertKey = null;
count--;
return;
}
else
{
KeyQueueElement lastListElement = head;
KeyQueueElement tempListElement = head.nextElement;
while (tempListElement != null)
{
if (tempListElement.key > insertKey)
{
return;
}
else if (tempListElement.key == insertKey)
{
lastListElement.nextElement = tempListElement.nextElement;
givenNode.InsertKey = null;
count--;
return;
}
lastListElement = tempListElement;
tempListElement = tempListElement.nextElement;
}
}
}
}
Node(结点)类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Node
{
public int x;
public int y;
public GameObject tile;
public static double km;
public double g = double.PositiveInfinity;
public double rhs = double.PositiveInfinity;
public double h;
public bool enable = true;
public List<Node> neighbour = new List<Node>();
private bool insert;
private Key insertKey = new Key();
private Key tempKey = new Key();
private static Key startKey = new Key();
public Key InsertKey
{
get
{
if (insert == false)
{
return null;
}
else
{
return insertKey;
}
}
set
{
if(value == null)
{
insert = false;
}
else
{
insert = true;
insertKey.CopyKey(value);
}
}
}
public Key GetUpdatedKey
{
get
{
tempKey.Key1 = (g < rhs ? g : rhs) + h + km;
tempKey.Key2 = (g < rhs ? g : rhs);
return tempKey;
}
}
public Key GetStartUpdatedKey
{
get
{
startKey.Key1 = (g < rhs ? g : rhs) + h + km;
startKey.Key2 = (g < rhs ? g : rhs);
return startKey;
}
}
public Node() { }
public Node(int inputX, int inputY, GameObject gameObject)
{
x = inputX;
y = inputY;
tile = gameObject;
}
public void UpdateVertex()
{
DStarLite.U.Remove(this);
if (g != rhs)
{
DStarLite.U.Insert(GetUpdatedKey, this);
}
}
}
DStarLite类
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
public class DStarLite
{
public static Node sStart;
public static Node sGoal;
public static List<Node> nodes = new List<Node>();
public static KeyQueue U;
public static Queue<Node> finalPath = new Queue<Node>();
static void CalculateAllH()
{
foreach (Node tempNode in nodes)
{
tempNode.h = (Mathf.Abs(tempNode.x - sStart.x) + Mathf.Abs(tempNode.y - sStart.y)) * 10;
}
}
public static void Initialize()
{
sGoal.rhs = 0;
Node.km = 0;
CalculateAllH();
U = KeyQueue.CreateList(sGoal.GetUpdatedKey, sGoal);
}
public static void ComputePath()
{
Key tempOldKey = new Key();
Key tempNewKey;
Node Utop;
double tempRhs;
double gOld;
while ((U.PeekFirstKey != null && (U.PeekFirstKey < sStart.GetStartUpdatedKey) || sStart.rhs != sStart.g))
{
tempOldKey.CopyKey(U.PeekFirstKey);
Utop = U.PeekFirstNode;
U.RemoveFirst();
tempNewKey = Utop.GetUpdatedKey;
if (tempOldKey < tempNewKey)
{
U.Insert(tempNewKey, Utop);
}
else if (Utop.g > Utop.rhs)
{
Utop.g = Utop.rhs;
foreach (Node predecessor in Utop.neighbour)
{
if (predecessor != sGoal)
{
tempRhs = Cost(predecessor, Utop) + Utop.g;
if (predecessor.rhs > tempRhs)
{
predecessor.rhs = tempRhs;
}
}
predecessor.UpdateVertex();
}
}
else
{
gOld = Utop.g;
Utop.g = double.PositiveInfinity;
foreach (Node predecessor in Utop.neighbour)
{
if (predecessor != sGoal)
{
if (predecessor.rhs == Cost(predecessor, Utop) + gOld)
{
predecessor.rhs = double.PositiveInfinity;
foreach (Node successor in predecessor.neighbour)
{
tempRhs = Cost(successor, predecessor) + successor.g;
if (predecessor.rhs > tempRhs)
{
predecessor.rhs = tempRhs;
}
}
}
}
predecessor.UpdateVertex();
}
}
}
GetFinalPath();
}
static void GetFinalPath()
{
finalPath.Clear();
Node tempStartNode = sStart;
Node tempBestSuccessor = null;
double tempG;
if (sStart == sGoal)
{
return;
}
do
{
tempG = double.PositiveInfinity;
foreach (Node successor in tempStartNode.neighbour)
{
if (tempG > successor.g)
{
tempG = successor.g;
tempBestSuccessor = successor;
}
}
if (tempG == double.PositiveInfinity)
{
finalPath.Clear();
return;
}
else
{
finalPath.Enqueue(tempBestSuccessor);
tempStartNode = tempBestSuccessor;
}
}
while (tempStartNode != sGoal);
}
public static double Cost(Node from, Node to)
{
if (!from.enable || !to.enable)
{
return double.PositiveInfinity;
}
else
{
int DeltaX = Mathf.Abs(from.x - to.x);
int DeltaY = Mathf.Abs(from.y - to.y);
switch (DeltaX + DeltaY)
{
case 0: return 0;
case 1: return 10;
case 2: return 20;
default: return 0;
}
}
}
public static Node GetNextPathNode()
{
if (finalPath != null && finalPath.Count != 0)
{
Node to = finalPath.Dequeue();
Node.km += Cost(sStart, to);
sStart = to;
return to;
}
else
return null;
}
public static void OnNodeDisabled(Node disabled)
{
double cOld;
double tempRhs;
Node tempOldNode = new Node
{
x = disabled.x,
y = disabled.y,
};
disabled.enable = false;
disabled.rhs = double.PositiveInfinity;
CalculateAllH();
foreach (Node predecessor in disabled.neighbour)
{
cOld = Cost(predecessor, tempOldNode);
if (predecessor.rhs == cOld + disabled.g)
{
if (predecessor == sGoal)
{
continue;
}
predecessor.rhs = double.PositiveInfinity;
foreach (Node successor in predecessor.neighbour)
{
tempRhs = Cost(predecessor, successor) + successor.g;
if (predecessor.rhs > tempRhs)
{
predecessor.rhs = tempRhs;
}
}
}
predecessor.UpdateVertex();
}
disabled.UpdateVertex();
}
public static void OnNodeEnabled(Node enabled)
{
enabled.enable = true;
CalculateAllH();
double tempCost;
double tempRhs;
foreach (Node predecessor in enabled.neighbour)
{
tempCost = Cost(predecessor, enabled);
tempRhs = tempCost + predecessor.g;
if (enabled.rhs > tempRhs)
{
enabled.rhs = tempRhs;
}
}
enabled.UpdateVertex();
}
}