RTS-style AI using Goal-Oriented Action Planner
Longer Real-Time Simulation
The GOAP
Planning the Best Action
The FastPlanAction function is the entry point of the AI’s action planning. It takes in the current WorldModel and a Goal, then estimates the cost to reach the goal using a heuristic. Based on this estimate, it searches for the most efficient action by calling DoFastDepthFirst, which explores possible action sequences up to a defined depth. If a valid plan is found within the cost limit, it returns the best action. If not, it defaults to an idle action.
To keep this planner running every frame or very often, the depth has to be quite shallow.
Inputs:
World Model: The current state of the
world, including resources, units, etc.
Goal: The desired end state the AI is
trying to reach.
Transposition Table: A hash storage for
already visited states.
Heuristic: A cost calculating class.
Cutoff: Current estimated cost to goal.
Output:
The most optimal Action to take next based on current conditions and the goal.
Heuristic-Guided Action Search
DoFastDepthFirst performs a depth-limited search through possible actions, guided by a heuristic. At each depth level, it evaluates available actions, simulates the results, and calculates the cost to reach the goal. Actions that exceed the given cutoff are ignored to keep the plan efficient. A transposition table is used to skip already visited states, preventing redundant checks. The function returns the best alternative cost and the first action in the most promising sequence.
Purpose:
- Explore action sequences up to a max depth.
- Simulate outcomes, prune expensive paths early.
- Return the most cost-effective action toward the goal.
Influence / Heat Map
Soldiers, Farmers, and Goblins emit influence on the grid around them. This influence spreads out in a radius with a decay rate, forming a dynamic heat map that represents presence. The influence map is used to guide movement and behavior:
- Farmers avoid enemy influence while gathering resources.
- Soldiers move toward areas with high enemy influence to engage or defend. If no enemy influence is nearby, they prefer tiles with the lowest farmer influence, effectively patrolling vulnerable zones. If no farmer influence exists either, they move toward the nearest farmer.
- Goblins move randomly but avoid soldier influence and prefer tiles with high farmer presence, giving them unpredictable but purposeful movement.

Movement Decisions Example: Soldier
This function determines how soldiers choose their next move using the influence map. Other soldier-occupied tiles are filtered out first.
- 1. If enemies are nearby, the soldier sorts possible moves by enemy influence, preferring the tile with the highest threat to engage.
- 2. If no enemies are nearby, it looks for tiles with some farmer influence, then picks the one with the lowest farmer presence. This creates a border-patrol behavior, guarding less protected areas.
- 3. If there’s no farmer influence at all, it moves toward the closest farmer to stay near important units.
- Fallback: If no farmers exist, it picks a random valid move.
This creates a movement pattern where soldiers act defensively, prioritize threats, and naturally position themselves to protect the perimeter of farmer positions while avoiding collisions with other soldiers.
Terrain Example: Sheep Generation
This code generates the positions of terrain entities throughout the map while avoiding overlapping from previously positioned entities. This specific example is for sheep.
Mark Exclusion Zones:
It loops through nearby entities and marks a grid radius around each one where sheep should not be placed.
Generate Possible Positions:
It checks tiles around a start position within a set range (iterations), skipping some based on spacing rules (every 2nd, 3rd, or 5th tile) to control density.
Filter Valid Tiles:
It ensures each position is inside map bounds, is walkable, and not inside an exclusion zone.
Shuffle the Results:
All valid positions are randomly shuffled to allow for non-patterned, natural placement.
Challenges and What I Learned
Finding the Right Focus
One of the first challenges I faced was deciding what part of game AI I wanted to explore. I knew I wanted to work with AI systems in games, but I struggled to find something that felt both complex and meaningful. I initially came across the Iterative Deepening A* algorithm and was fascinated by how it differs from regular A*—it uses significantly less memory, which makes it a powerful tool in large data spaces with many actions, paths, or tasks. The idea of building an AI planner that could work in a sea of data and still find the optimal goal path really appealed to me.
However, the performance trade-offs became a problem. The algorithm restarts its search whenever it exceeds the current cost threshold, which added too much overhead for my use case in a real-time game. I ended up modifying it, steering the algorithm early on with a manipulated cost function to find quicker paths and skipping the repeated cutoff logic. This experience taught me a lot about algorithm design and how even small tweaks can drastically affect performance and behavior.
Creating the Game World
Because I decided to build an RTS-style game around the GOAP system, I needed assets that matched the idea. I found a free pixel art library by Pixel Frog , which was perfect for giving the project a stylized look. At the same time, building this game involved more than just the GOAP logic—I also had to handle terrain generation, rendering systems, and a range of behaviors unrelated to my AI focus.
Thankfully, I managed to implement the action planner fairly quickly. Once I had a working structure for actions, goals, and costs, I had enough time to expand the project. In many cases, I reused knowledge from previous projects—like grids, pathfinding, and procedural generation. But I also had to create new systems from scratch, like a simple entity inheritance system and rules for synchronized behaviors.
AI Coordination
One of my favorite challenges was coordinating different AI roles—farmers, guards, and goblins. I wanted farmers to act based on the GOAP system, focusing on their tasks while avoiding danger. Guards needed to protect them dynamically, while goblins would target unprotected farmers. This led me to explore concepts like influence maps and heat-based grid scoring.
I developed a system where each entity would scan nearby grid tiles and sort them based on a combination of influence values and distance to goal. This created more believable movement and less rigid behavior. It also had a positive impact on performance, since not every agent had to run a full pathfinding routine at every step. Instead, entities appeared to explore their surroundings more naturally.
Planner Limitations & Missed Opportunities
One thing I didn’t get around to improving was how the action planner handles future resource gains. Right now, it only plans based on the current world state. So if, for example, three farmers are already out gathering food, the planner doesn’t consider that upcoming food—it only reacts after the world state has actually changed.
In hindsight, it would’ve been great to add a layer of predictive planning. For instance, estimating the chance of incoming resources based on whether a farmer is carrying food back to base and not in danger. That way, the planner could make smarter decisions without waiting for a full update. Time constraints kept me from exploring it, but it's something I’d definitely like to implement in future projects.
Final Takeaways
In the end, I had essentially created my own small simulation game. This project gave me valuable insights into how to structure gameplay systems around AI, and how to make smart trade-offs between performance and behavior. I learned how important it is to scope your project carefully—while I’m proud of what I built, I realized that if my main goal was to specialize in AI, I could’ve chosen a system with fewer distractions outside of the core logic.
That said, the experience of combining GOAP planning with influence-based movement and entity interaction gave me a strong foundation for future AI systems. It helped me grow both as a programmer and as a systems thinker.