Skip to main content
GameDev.net gamedev.net
🔒 Locked

Looking for an algorithm to build an influence map

Started by Narf the Mouse Dec 16, 2009 at 1:48 PM 7 replies 4.3k views
Original Post
Narf the Mouse
Narf the Mouse
The concept: Each "Thing of interest" on the map has an influence map. The AI looks at the info for the thing and responds (Or not) accordingly, either following the influence map towards it or away from it. The problem: How to build the influence map. I'm currently using "Breadth-first" search, but it's not optimal. The influence map has to spread, following the pathable sections of the map in the same way a character would move. The AI, the plan: Love and Fear/Hate based. It desires what it loves (Moves towards; activates; picks up), flees the "center of mass" of fear and attacks the greatest source of hate. It chooses which based on which has the greatest influence on it. Other characters will have influence maps, but probably not more than a 10 radius. The map: Typical room-and-hallway dungeon map with doors. The doors are currently the only points of interest; the AI seeks them out, opens them and then moves on to the next closest known door. It follows the influence maps to each door. Thanks for any and all help.
captain_crunch
captain_crunch
If you are on a tile map, then, to draw the influence from an object out to the radius of 10 tiles, you start at coordinates (x - 10, y - 10), clamped to the map dimensions, then use two for loops to set the influence value on each of the 400 (2 * 10 * 2 * 10) tiles.

something like:


for (y = startY; y < endY; y++)
{
for (x = startX; x < endX; x++)
{
// make influence fall of with distance:
map[x, y] = 100 / Math.Distance(Point(x, y), entity.Position)
}
}
alexjc
alexjc
To spread the influence, a common technique is to repeatedly blur the map. The main advantage of this approach is that you can do it once every frame (or so). Another advantage is that you can have many influence sources.

However, it wouldn't spread single influence as fast as say, Dijstra's algorithm.
Join us in Vienna for the nucl.ai Conference 2015, on July 20-22... Don't miss it!
Narf the Mouse
Narf the Mouse
Quote:
Original post by captain_crunch
If you are on a tile map, then, to draw the influence from an object out to the radius of 10 tiles, you start at coordinates (x - 10, y - 10), clamped to the map dimensions, then use two for loops to set the influence value on each of the 400 (2 * 10 * 2 * 10) tiles.

something like:


for (y = startY; y < endY; y++)
{
for (x = startX; x < endX; x++)
{
// make influence fall of with distance:
map[x, y] = 100 / Math.Distance(Point(x, y), entity.Position)
}
}

The problem with that is that the distance is "As the crow flies", not "As the adventurer wanders through a maze" - Following that influence map will end with the AI pushing against a corner, relatively quickly. The map needs to follow the flow of the maze.
Quote:
Original post by alexjc
To spread the influence, a common technique is to repeatedly blur the map. The main advantage of this approach is that you can do it once every frame (or so). Another advantage is that you can have many influence sources.

However, it wouldn't spread single influence as fast as say, Dijstra's algorithm.

Dijkstra's algorithm looks like it'll work well and exactly - Thanks. :)
Narf the Mouse
Narf the Mouse
Ok, here's what I've got. It works and well - Just wondering if anyone can spot improvements I missed.
            public static bool FloodFill(            int fromX, int fromY, bool[,] pathability,            out double[,] influenceMap            )        {            // Set initial data            int x, y,                tPosX, tPosY,                sizeX = pathability.GetLength(0),                sizeY = pathability.GetLength(1);            influenceMap = new double[sizeX, sizeY];            for (x = 0; x < sizeX; ++x)                for (y = 0; y < sizeY; ++y)                    influenceMap[x,y] = double.PositiveInfinity;            // Create node queue            Queue<FloodFillNode> nodeQueue = new Queue<FloodFillNode>(sizeX * sizeY);            // Add initial node            nodeQueue.Enqueue(new FloodFillNode(fromX, fromY, 0));            // Temporary distance variable, current node and a temporary node.            double tempDistance;            FloodFillNode node, tempNode = new FloodFillNode();            do            {                // Get first node.                node = nodeQueue.Dequeue();                // Check the surounding area                for (x = -1; x <= 1; ++x)                    for (y = -1; y <= 1; ++y)                    {                        if (x != 0 || y != 0)                        {                            // Map position                            tPosX = node.X + x;                            tPosY = node.Y + y;                            // If it's pathable,                            if (pathability[tPosX, tPosY])                            {                                // Get a temporary distance value                                tempDistance = node.D + Math.Sqrt((x * x) + (y * y));                                // if its less than the recorded value,                                if (tempDistance < influenceMap[tPosX, tPosY])                                {                                    // Set the recored value to that value                                    influenceMap[tPosX, tPosY] = tempDistance;                                    // Set the temporary node data. Not creating a new one speeds things up.                                    tempNode.X = tPosX;                                    tempNode.Y = tPosY;                                    tempNode.D = tempDistance;                                    // Add the temporary node to the queue                                    nodeQueue.Enqueue(tempNode); // Struct, so passed by value.                                }                            }                        }                    }            } while (nodeQueue.Count > 0); // If there's no more nodes, we're done.                        return true;        }
ID Merlin
ID Merlin
You can optimize this by keeping track of the distance in the queue. Increment it each time you move a step, which will always be one square/hex/move away from where you were.
Narf the Mouse
Narf the Mouse
Quote:
Original post by ID Merlin
You can optimize this by keeping track of the distance in the queue. Increment it each time you move a step, which will always be one square/hex/move away from where you were.

You mean in FloodFillNode? Yeah, that holds distance, too. I simply use the map, too, so that I don't have to go searching for the right node in the Queue to see if the distance is shorter.

So it both flood-fills and finds the shortest path.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.