I've been playing around with assigning path movements to npcs in order to have them follow a fixed route. The problem I'm running into is obstacle avoidance. Now it's easy enough to choose a route for the NPC that is clear of obstacles on the map, and I'd only have the NPCs moving around inside of towns where there are no enemies, so collisions with enemies are not a concern either. It's just collisions with the hero that I have to worry about.
I started off by setting set_ignore_obstacles(true) for the NPC movement. For the most part, that works. If the NPC's path goes through the hero's position then the hero will just get stuck for a little while until the NPC passes the hero, and it's just a little annoyance. The problem occurs if the hero happens to be standing where the NPCs path stops (and the NPC just stands in that spot for a while). Now the hero cannot move at all until the NPC starts a new path movement.
So then I played around with trying to push the hero out of the way when there's a collision with the NPC. So in the NPC movement's on_position_changed() function (any time the NPC moves), I check if the NPC and hero overlap with NPC:overlaps(hero, "overlapping"), and if they do, I assign a movement to the hero to nudge the hero out of the NPC's path.
I'm assuming that I need to move the hero one pixel at a time so that if the hero gets pushed over a 16x16 teletransporter (say inside a doorway), that the hero doesn't get pushed too far and skip the teletransporter. Is that correct? Pixel movement also seems preferable over path movement so that the hero can be moved just a couple pixels out of the way of the NPC instead of multiples of 8 pixels.
So I got something setup to move the hero when an NPC walks into him, but now I'm running into problems with making sure the hero doesn't get pushed into an obstacle when nudged. As an example, consider an NPCs walking along a path in the North direction with the Hero to the North of the NPC. When a collision occurs, I want to nudge the hero to the NW because if I only nudge the hero N, then the NPC could end up pushing the hero for the entire length of the path.
To nudge the hero to the NW, I give the hero's pixel movement a trajectory with several entries of {-1, -1}. The problem now is if there is an obstruction on the map to the west of the hero, I still want the hero to be moved to the N. It seems the hero's movement just calls on_obstacle_reached() and doesn't move the hero at all, even though there is no obstacle to the North.
The workaround I then used for the above problem is to give a trajectory that only moves one pixel W then one pixel N, alternating (i.e. {{-1,0}, {0,-1}, {-1,0}, {0,-1}...etc.}). This actually works for the most part, but there are still a few corner cases that don't quite work.
See the example image below, where the green 16x16 box is the hero, the blue is the npc, who is walking to the north to the doorway in the building above. The grey pixels (and the doorway) are traversable. So then the first time the NPC and hero bounding boxes overlap, there are six pixels (cyan) where the overlap occurs. Now obviously nudging the hero to the north fails because there is a building in the way, but nudging the hero to the east also fails because if the hero is moved 1 pixel to the east, the hero still overlaps the NPC by 5 pixels.
I don't have a good solution to this problem. The only thing I can think of is to do set_ignore_obstacles(true) for the hero and do my own manual obstacle detection, but that's tricky because it runs the risk of pushing the hero into the side of a building and getting stuck. I'm assuming I'd have to use map:get_ground() to do my own collision text, but how does that work? With a "wall_top_right" tile, for example, the bottom left corner of the tile is traversable and the top right corner is not. So does that mean that a coordinate in the top right half of the tile returns "wall_top_right" whereas a coordinate in the bottom left half of the tile returns "traversable"?
Or does anyone have any better ideas?