Coverage Summary for Class: TileMapGraph (com.mygdx.game.AI)
Class |
Class, %
|
Method, %
|
Line, %
|
TileMapGraph |
0%
(0/1)
|
0%
(0/12)
|
0%
(0/57)
|
1 package com.mygdx.game.AI;
2
3 import com.badlogic.gdx.ai.pfa.Connection;
4 import com.badlogic.gdx.ai.pfa.indexed.IndexedGraph;
5 import com.badlogic.gdx.maps.MapLayer;
6 import com.badlogic.gdx.maps.MapLayers;
7 import com.badlogic.gdx.maps.tiled.TiledMap;
8 import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
9 import com.badlogic.gdx.math.Vector2;
10 import com.badlogic.gdx.utils.Array;
11 import com.badlogic.gdx.utils.ObjectMap;
12
13 import static com.mygdx.utils.TileMapCells.OBSTACLE;
14 import static com.mygdx.utils.TileMapCells.PASSABLE;
15
16 /**
17 * The Graphical representation of the tilemap with each cell being bidirectionally to the adjacent nodes.
18 */
19 public class TileMapGraph implements IndexedGraph<Node> {
20 //private final NodeHeuristic heuristic; - commented out for Assessment 2 because heuristic functionality was removed due to redundancy
21 private final Array<Node> nodes;
22 private final Array<Path> paths;
23 private final Vector2 mapDim;
24
25 private final ObjectMap<Node, Array<Connection<Node>>> nodePaths;
26
27 private TileMapGraph() {
28 //heuristic = new NodeHeuristic(); - commented out for Assessment 2 because heuristic functionality was removed due to redundancy
29 nodes = new Array<>();
30 paths = new Array<>();
31 nodePaths = new ObjectMap<>();
32 mapDim = new Vector2();
33 }
34
35 /**
36 * Creates a Graph from the given tilemap
37 * @param map the source tilemap
38 */
39 public TileMapGraph(TiledMap map) {
40 this();
41
42 MapLayers layers = map.getLayers();
43 TiledMapTileLayer layer = null;
44
45 // find the collision layer
46 for (MapLayer l : layers) {
47 if (l.getName().equals("Collision")) {
48 layer = (TiledMapTileLayer) l;
49 }
50 }
51 // if there is no collision layer
52 if (layer == null) {
53 return;
54 }
55 // the map dimensions
56 mapDim.set(layer.getWidth(), layer.getHeight());
57
58 nodes.ensureCapacity((int) mapDim.x * (int) mapDim.y);
59
60 // create all the nodes
61 for (int i = 0; i < mapDim.x * mapDim.y; i++) {
62 nodes.add(new Node(0, 0));
63 }
64
65 // for each column
66 for (int x = 0; x < layer.getWidth(); x++) {
67 // for each row
68 for (int y = 0; y < layer.getHeight(); y++) {
69 TiledMapTileLayer.Cell center = layer.getCell(x, y);
70
71 if (getType(center) == OBSTACLE) {
72 continue;
73 }
74 // the central node
75 addNode(x, y);
76
77 // all surrounding nodes
78 for (int i = -1; i < 2; i++) {
79 for (int j = -1; j < 2; j++) {
80
81 // prevents the node pathing to its self
82 if (i == 0 && j == 0) {
83 continue;
84 }
85
86 TiledMapTileLayer.Cell cell = layer.getCell(x + i, y + j);
87 // is cell outside the map
88 if (cell == null) {
89 continue;
90 }
91
92 // is the cell passable
93 if (cell.getTile().getId() == PASSABLE) {
94
95 addNode(x + i, y + j);
96 addPath(x, y, x + i, y + j);
97 }
98 }
99 }
100 }
101 }
102 }
103
104 /**
105 * Node a position (x, y)
106 * @param x co-ord
107 * @param y co-ord
108 * @return Node at (x, y) or null
109 */
110 public Node getNode(float x, float y) {
111 Node n = nodes.get(getIndex(x, y));
112 if (n.cost == -1) {
113 return null;
114 }
115 return n;
116 }
117
118 /**
119 * Find index of a position (x, y)
120 * @param x co-ord
121 * @param y co-ord
122 * @return the index of the parsed co-ordinate
123 */
124 private int getIndex(float x, float y) {
125 return (int) (mapDim.x * y + x);
126 }
127
128 /**
129 * @return type of cell as far as the tile map is condensed
130 */
131 private int getType(TiledMapTileLayer.Cell c) {
132 return c.getTile().getId();
133 }
134
135 /**
136 * Find index of a position (x, y)
137 * @param x co-ord
138 * @param y co-ord
139 * @return the index of the parsed co-ordinate
140 */
141 private int getIndex(int x, int y) {
142 return (int) mapDim.x * y + x;
143 }
144
145 /**
146 * adds Node unless node is already present
147 * @param x x pos
148 * @param y y pos
149 */
150 private void addNode(float x, float y) {
151 Node n = nodes.get(getIndex((int) x, (int) y));
152 if (n.cost > 0) {
153 return;
154 }
155 n.set(x, y);
156 n.cost = 1;
157 }
158
159 /**
160 * Adds path to map (doesn't check for duplicates)
161 * @param a src
162 * @param b dst
163 */
164 private void addPath(Node a, Node b) {
165 Path path = new Path(a, b);
166
167 if (!nodePaths.containsKey(a)) {
168 nodePaths.put(a, new Array<>());
169 }
170 nodePaths.get(a).add(path);
171 paths.add(path);
172 }
173
174 /**
175 * Adds path to map (doesn't check for duplicates)
176 * @param x1 src.x
177 * @param y1 src.y
178 * @param x2 dst.x
179 * @param y2 dst.y
180 */
181 private void addPath(float x1, float y1, float x2, float y2) {
182 Node a = getNode(x1, y1);
183 Node b = getNode(x2, y2);
184
185 addPath(a, b);
186 }
187
188 /**
189 * @param node the node being queried
190 * @return the index of the parsed node
191 */
192 @Override
193 public int getIndex(Node node) {
194 return getIndex(node.getPosition().x, node.getPosition().y);
195 }
196
197 /**
198 * @return the amount of nodes present in the map
199 */
200 @Override
201 public int getNodeCount() {
202 return (int) (mapDim.x * mapDim.y);
203 }
204
205 /**
206 * @param fromNode the node being queried
207 * @return the list of connections present starting from the parsed node
208 */
209 @Override
210 public Array<Connection<Node>> getConnections(Node fromNode) {
211 if (nodePaths.containsKey(fromNode)) {
212 return nodePaths.get(fromNode);
213 }
214
215 return new Array<>();
216 }
217
218 //public GraphPath<Node> findPath(Node start, Node goal) {
219 // if (start == null || goal == null) {
220 // return null;
221 // }
222 // GraphPath<Node> path = new DefaultGraphPath<>();
223 // new IndexedAStarPathFinder<>(this).searchNodePath(start, goal, heuristic, path);
224 // return path;
225 // }
226
227 //public QueueFIFO<Vector2> findOptimisedPath(Node a, Node b) {
228 // GraphPath<Node> path = findPath(a, b);
229 // QueueFIFO<Vector2> res = new QueueFIFO<>();
230 // Vector2 delta = new Vector2();
231 // float sequenceLength = 0; // the amount of times a
232 // Vector2 cur = new Vector2();
233 //
234 // Vector2 prev = path.get(0).getPosition();
235 // for (int i = 1; i < path.getCount(); i++) {
236 // Node n = path.get(i);
237 // cur.set(n.getPosition());
238 // // d contains the current vector between the current pos and prev
239 // Vector2 d = cur.cpy();
240 // d.sub(prev);
241 //
242 //
243 // if (delta.x == d.x && delta.y == d.y) {
244 // sequenceLength++;
245 // } else {
246 // res.add(delta.scl(sequenceLength));
247 // delta = d;
248 // sequenceLength = 1;
249 // }
250 // prev.set(cur);
251 // }
252 // res.remove(0);
253 // res.add(delta.scl(sequenceLength));
254 // return res;
255 // }
256
257 //public QueueFIFO<Vector2> findOptimisedPath(Vector2 a, Vector2 b) {
258 // Node n1 = getNode(a.x, a.y);
259 // Node n2 = getNode(b.x, b.y);
260 // return findOptimisedPath(n1, n2);
261 // }
262
263 //public QueueFIFO<Vector2> findOptimisedPath(float x1, float y1, float x2, float y2) {
264 // Node a = getNode(x1, y1);
265 // Node b = getNode(x2, y2);
266 // return findOptimisedPath(a, b);
267 // }
268 }