1 /** 2 AStar class representation that uses vectors as edges. 3 4 Copyright: 5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. 6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) 7 Copyright (c) 2017-2018 Godot-D contributors 8 9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License) 10 11 12 */ 13 module godot.astar; 14 import std.meta : AliasSeq, staticIndexOf; 15 import std.traits : Unqual; 16 import godot.d.meta; 17 import godot.core; 18 import godot.c; 19 import godot.d.bind; 20 import godot.d.reference; 21 import godot.object; 22 import godot.classdb; 23 import godot.reference; 24 /** 25 AStar class representation that uses vectors as edges. 26 27 A* (A star) is a computer algorithm that is widely used in pathfinding and graph traversal, the process of plotting an efficiently directed path between multiple points. It enjoys widespread use due to its performance and accuracy. Godot's A* implementation make use of vectors as points. 28 You must add points manually with $(D AStar.addPoint) and create segments manually with $(D AStar.connectPoints). So you can test if there is a path between two points with the $(D AStar.arePointsConnected) function, get the list of existing ids in the found path with $(D AStar.getIdPath), or the points list with $(D AStar.getPointPath). 29 */ 30 @GodotBaseClass struct AStar 31 { 32 enum string _GODOT_internal_name = "AStar"; 33 public: 34 @nogc nothrow: 35 union { godot_object _godot_object; Reference _GODOT_base; } 36 alias _GODOT_base this; 37 alias BaseClasses = AliasSeq!(typeof(_GODOT_base), typeof(_GODOT_base).BaseClasses); 38 package(godot) __gshared bool _classBindingInitialized = false; 39 package(godot) static struct _classBinding 40 { 41 __gshared: 42 @GodotName("_estimate_cost") GodotMethod!(double, long, long) _estimateCost; 43 @GodotName("_compute_cost") GodotMethod!(double, long, long) _computeCost; 44 @GodotName("get_available_point_id") GodotMethod!(long) getAvailablePointId; 45 @GodotName("add_point") GodotMethod!(void, long, Vector3, double) addPoint; 46 @GodotName("get_point_position") GodotMethod!(Vector3, long) getPointPosition; 47 @GodotName("set_point_position") GodotMethod!(void, long, Vector3) setPointPosition; 48 @GodotName("get_point_weight_scale") GodotMethod!(double, long) getPointWeightScale; 49 @GodotName("set_point_weight_scale") GodotMethod!(void, long, double) setPointWeightScale; 50 @GodotName("remove_point") GodotMethod!(void, long) removePoint; 51 @GodotName("has_point") GodotMethod!(bool, long) hasPoint; 52 @GodotName("get_points") GodotMethod!(Array) getPoints; 53 @GodotName("get_point_connections") GodotMethod!(PoolIntArray, long) getPointConnections; 54 @GodotName("connect_points") GodotMethod!(void, long, long, bool) connectPoints; 55 @GodotName("disconnect_points") GodotMethod!(void, long, long) disconnectPoints; 56 @GodotName("are_points_connected") GodotMethod!(bool, long, long) arePointsConnected; 57 @GodotName("clear") GodotMethod!(void) clear; 58 @GodotName("get_closest_point") GodotMethod!(long, Vector3) getClosestPoint; 59 @GodotName("get_closest_position_in_segment") GodotMethod!(Vector3, Vector3) getClosestPositionInSegment; 60 @GodotName("get_point_path") GodotMethod!(PoolVector3Array, long, long) getPointPath; 61 @GodotName("get_id_path") GodotMethod!(PoolIntArray, long, long) getIdPath; 62 } 63 bool opEquals(in AStar other) const { return _godot_object.ptr is other._godot_object.ptr; } 64 AStar opAssign(T : typeof(null))(T n) { _godot_object.ptr = null; } 65 bool opEquals(typeof(null) n) const { return _godot_object.ptr is null; } 66 mixin baseCasts; 67 static AStar _new() 68 { 69 static godot_class_constructor constructor; 70 if(constructor is null) constructor = _godot_api.godot_get_class_constructor("AStar"); 71 if(constructor is null) return typeof(this).init; 72 return cast(AStar)(constructor()); 73 } 74 @disable new(size_t s); 75 /** 76 Called when estimating the cost between a point and the path's ending point. 77 */ 78 double _estimateCost(in long from_id, in long to_id) 79 { 80 Array _GODOT_args = Array.empty_array; 81 _GODOT_args.append(from_id); 82 _GODOT_args.append(to_id); 83 String _GODOT_method_name = String("_estimate_cost"); 84 return this.callv(_GODOT_method_name, _GODOT_args).as!(RefOrT!double); 85 } 86 /** 87 Called when computing the cost between two connected points. 88 */ 89 double _computeCost(in long from_id, in long to_id) 90 { 91 Array _GODOT_args = Array.empty_array; 92 _GODOT_args.append(from_id); 93 _GODOT_args.append(to_id); 94 String _GODOT_method_name = String("_compute_cost"); 95 return this.callv(_GODOT_method_name, _GODOT_args).as!(RefOrT!double); 96 } 97 /** 98 Returns the next available point id with no point associated to it. 99 */ 100 long getAvailablePointId() const 101 { 102 checkClassBinding!(typeof(this))(); 103 return ptrcall!(long)(_classBinding.getAvailablePointId, _godot_object); 104 } 105 /** 106 Adds a new point at the given position with the given identifier. The algorithm prefers points with lower `weight_scale` to form a path. The `id` must be 0 or larger, and the `weight_scale` must be 1 or larger. 107 108 109 var as = AStar.new() 110 111 as.add_point(1, Vector3(1,0,0), 4) # Adds the point (1,0,0) with weight_scale=4 and id=1 112 113 114 If there already exists a point for the given id, its position and weight scale are updated to the given values. 115 */ 116 void addPoint(in long id, in Vector3 position, in double weight_scale = 1) 117 { 118 checkClassBinding!(typeof(this))(); 119 ptrcall!(void)(_classBinding.addPoint, _godot_object, id, position, weight_scale); 120 } 121 /** 122 Returns the position of the point associated with the given id. 123 */ 124 Vector3 getPointPosition(in long id) const 125 { 126 checkClassBinding!(typeof(this))(); 127 return ptrcall!(Vector3)(_classBinding.getPointPosition, _godot_object, id); 128 } 129 /** 130 Sets the position for the point with the given id. 131 */ 132 void setPointPosition(in long id, in Vector3 position) 133 { 134 checkClassBinding!(typeof(this))(); 135 ptrcall!(void)(_classBinding.setPointPosition, _godot_object, id, position); 136 } 137 /** 138 Returns the weight scale of the point associated with the given id. 139 */ 140 double getPointWeightScale(in long id) const 141 { 142 checkClassBinding!(typeof(this))(); 143 return ptrcall!(double)(_classBinding.getPointWeightScale, _godot_object, id); 144 } 145 /** 146 Sets the `weight_scale` for the point with the given id. 147 */ 148 void setPointWeightScale(in long id, in double weight_scale) 149 { 150 checkClassBinding!(typeof(this))(); 151 ptrcall!(void)(_classBinding.setPointWeightScale, _godot_object, id, weight_scale); 152 } 153 /** 154 Removes the point associated with the given id from the points pool. 155 */ 156 void removePoint(in long id) 157 { 158 checkClassBinding!(typeof(this))(); 159 ptrcall!(void)(_classBinding.removePoint, _godot_object, id); 160 } 161 /** 162 Returns whether a point associated with the given id exists. 163 */ 164 bool hasPoint(in long id) const 165 { 166 checkClassBinding!(typeof(this))(); 167 return ptrcall!(bool)(_classBinding.hasPoint, _godot_object, id); 168 } 169 /** 170 Returns an array of all points. 171 */ 172 Array getPoints() 173 { 174 checkClassBinding!(typeof(this))(); 175 return ptrcall!(Array)(_classBinding.getPoints, _godot_object); 176 } 177 /** 178 Returns an array with the ids of the points that form the connect with the given point. 179 180 181 var as = AStar.new() 182 183 as.add_point(1, Vector3(0,0,0)) 184 as.add_point(2, Vector3(0,1,0)) 185 as.add_point(3, Vector3(1,1,0)) 186 as.add_point(4, Vector3(2,0,0)) 187 188 as.connect_points(1, 2, true) 189 as.connect_points(1, 3, true) 190 191 var neighbors = as.get_point_connections(1) # returns $(D 2, 3) 192 193 194 */ 195 PoolIntArray getPointConnections(in long id) 196 { 197 checkClassBinding!(typeof(this))(); 198 return ptrcall!(PoolIntArray)(_classBinding.getPointConnections, _godot_object, id); 199 } 200 /** 201 Creates a segment between the given points. 202 203 204 var as = AStar.new() 205 206 as.add_point(1, Vector3(1,1,0)) 207 as.add_point(2, Vector3(0,5,0)) 208 209 as.connect_points(1, 2, false) # If bidirectional=false it's only possible to go from point 1 to point 2 210 # and not from point 2 to point 1. 211 212 213 */ 214 void connectPoints(in long id, in long to_id, in bool bidirectional = true) 215 { 216 checkClassBinding!(typeof(this))(); 217 ptrcall!(void)(_classBinding.connectPoints, _godot_object, id, to_id, bidirectional); 218 } 219 /** 220 Deletes the segment between the given points. 221 */ 222 void disconnectPoints(in long id, in long to_id) 223 { 224 checkClassBinding!(typeof(this))(); 225 ptrcall!(void)(_classBinding.disconnectPoints, _godot_object, id, to_id); 226 } 227 /** 228 Returns whether there is a connection/segment between the given points. 229 */ 230 bool arePointsConnected(in long id, in long to_id) const 231 { 232 checkClassBinding!(typeof(this))(); 233 return ptrcall!(bool)(_classBinding.arePointsConnected, _godot_object, id, to_id); 234 } 235 /** 236 Clears all the points and segments. 237 */ 238 void clear() 239 { 240 checkClassBinding!(typeof(this))(); 241 ptrcall!(void)(_classBinding.clear, _godot_object); 242 } 243 /** 244 Returns the id of the closest point to `to_position`. Returns -1 if there are no points in the points pool. 245 */ 246 long getClosestPoint(in Vector3 to_position) const 247 { 248 checkClassBinding!(typeof(this))(); 249 return ptrcall!(long)(_classBinding.getClosestPoint, _godot_object, to_position); 250 } 251 /** 252 Returns the closest position to `to_position` that resides inside a segment between two connected points. 253 254 255 var as = AStar.new() 256 257 as.add_point(1, Vector3(0,0,0)) 258 as.add_point(2, Vector3(0,5,0)) 259 260 as.connect_points(1, 2) 261 262 var res = as.get_closest_position_in_segment(Vector3(3,3,0)) # returns (0, 3, 0) 263 264 265 The result is in the segment that goes from `y=0` to `y=5`. It's the closest position in the segment to the given point. 266 */ 267 Vector3 getClosestPositionInSegment(in Vector3 to_position) const 268 { 269 checkClassBinding!(typeof(this))(); 270 return ptrcall!(Vector3)(_classBinding.getClosestPositionInSegment, _godot_object, to_position); 271 } 272 /** 273 Returns an array with the points that are in the path found by AStar between the given points. The array is ordered from the starting point to the ending point of the path. 274 */ 275 PoolVector3Array getPointPath(in long from_id, in long to_id) 276 { 277 checkClassBinding!(typeof(this))(); 278 return ptrcall!(PoolVector3Array)(_classBinding.getPointPath, _godot_object, from_id, to_id); 279 } 280 /** 281 Returns an array with the ids of the points that form the path found by AStar between the given points. The array is ordered from the starting point to the ending point of the path. 282 283 284 var as = AStar.new() 285 286 as.add_point(1, Vector3(0,0,0)) 287 as.add_point(2, Vector3(0,1,0), 1) # default weight is 1 288 as.add_point(3, Vector3(1,1,0)) 289 as.add_point(4, Vector3(2,0,0)) 290 291 as.connect_points(1, 2, false) 292 as.connect_points(2, 3, false) 293 as.connect_points(4, 3, false) 294 as.connect_points(1, 4, false) 295 as.connect_points(5, 4, false) 296 297 var res = as.get_id_path(1, 3) # returns $(D 1, 2, 3) 298 299 300 If you change the 2nd point's weight to 3, then the result will be `$(D 1, 4, 3)` instead, because now even though the distance is longer, it's "easier" to get through point 4 than through point 2. 301 */ 302 PoolIntArray getIdPath(in long from_id, in long to_id) 303 { 304 checkClassBinding!(typeof(this))(); 305 return ptrcall!(PoolIntArray)(_classBinding.getIdPath, _godot_object, from_id, to_id); 306 } 307 }