So I have been fooling around with Pygame and have run into a problem that I can solve, but only in-elegantly.
Basically I have a unit(at this point just a red square) on a plain field of black. If I click the Unit and then click anywhere else on the field the unit proceeds to that point. The algorithm itself works pretty flawlessly, even once obstacles are introduced it handles path-finding quickly.
My problem is in my implementation. The unit is a 16 by 16 square, the field is thus divided into 16 by 16 squares. If I change the unit’s destination while it is in transit it sometimes “back-tracks” to the previous “way-point” before continuing on its new route.
I understand why this happens, The path finding module treats each square as a point on a grid, so that the pixel coordinate of point (2,2) is actually (32,32), when I pass the mouse coordinates into the path method I divide them by 16 getting rounded down integers(so (34,37) becomes (2,2)) so while the unit may be between actual “grid-points” the path finding module finds the path from its last actual way point, not it’s current location. when it passes the new route to the unit, the unit has to “back-track” in order to follow the route the path-finding module has found
clearly every game developer that does any kind of path-finding has solved this so I’m hoping that I can find a more elegant solution.
I don’t want to find a path along every single pixel on the screen just waypoints, but the backtracking is a little irritating. Any suggestions?
as suggested below is the concerned code:
in the main .py file
if pygame.mouse.get_pressed()[0]: # if left mouse button pressed
mouse_x,mouse_y = pygame.mouse.get_pos()
if selected: # checks if a unit is selected
unit.getRoute((mouse_x/16,mouse_y/16))
in the unit.py file
def getRoute(self,target):
self.route = path((self.x/16,self.y/16), target)
def getNode(self):
if self.route:
self.node = route.pop(0)
dif_x,dif_y = self.node[0] - self.x, self.node[1] - self.y
if dif_x > 0:
self.vector_x = self.speed
if dif_x < 0:
self.vector_x = self.speed * -1
else:
self.vector_x = 0
if dif_y > 0:
self.vector_y = self.speed
if dif_x < 0:
self.vector_y = self.speed * -1
else:
self.vector_y = 0
else:
self.node = None
self.vector_x = 0
self.vector_y = 0
def update(self):
if self.route or self.node:
if self.route and not self.node:
self.getNode()
if (self.x,self.y) == self.node:
self.getNode()
self.x += self.vector_x
self.y += self.vector_y
self.rect.topleft = (self.x,self.y)
You should take care of managing this first step in a special way. This because even if the unit is already moving the cell specified with it remains the same until it reaches the next one.
Now I suggest you to make sure to update the cell of the unit as soon as half of the movement has been done (so that the pathfinder will search for the path from the next cell and not from the previous one). In addition you should manage the special situation with something like
Of course this will be easier or harder according to how much freedom of movement you have, if you allow only orthogonal movements that it will be straightforward, if you allow diagonal movement then you should make care to not cross over an obstacle (then it depends on how much tolerance you want to small glitches, like the unit overlapping with a corner of an obstacle).