- A* version: [latest]
- Unity version: [6]
I’m trying to find a solution to do pathfinding for a 2x2 cell sized agent on grid graphs. But I can’t find any concrete answers on a solution. because of the even size it would end up centred in-between the 4 cells it occupies. is there no way to do this with this asset?
I don’t just want the agent to start and end on the right cells, it needs to pathfind over the cells correctly too.
Hi
Here’s an alternative using the ITraversalProvider that can do this with some tweaking: Multiple agent types - A* Pathfinding Project
However, if at all possible, I would recommend using a graph with larger nodes or modified settings such that you can just use a regular path request.
I want the 2x2 agents to still be able to move 1 node at a time, if I increase the node size it would move 2 nodes at a time. Is there a way around that? Trying to overlay 2 large grids didn’t work.
The closest I got was this but I can’t get the agent collision to center properly
public class PreciseGridAgent : VersionedMonoBehaviour
{
[Header(“Movement Settings”)]
public float moveSpeed = 5f;
public float nextWaypointDistance = 0.1f;[Header("Agent Size")] public int agentWidth = 2; public int agentHeight = 2; private Seeker seeker; private Path path; private int currentWaypoint = 0; private bool reachedEndOfPath = false; private GridGraph gridGraph; private Vector3 lastValidPosition; void Awake() { seeker = GetComponent<Seeker>(); gridGraph = AstarPath.active.data.gridGraph; lastValidPosition = transform.position; SnapToValidPosition(); } public void SetDestination(Vector3 targetPosition) { // Find nearest valid 2x2 anchor point for destination var nearest = GetAnchorPosition(targetPosition); seeker.StartPath(transform.position, CalculateAgentCenter(nearest), OnPathComplete); } void OnPathComplete(Path p) { if (p.error) { Debug.LogWarning("Path failed: " + p.errorLog); return; } path = p; currentWaypoint = 0; reachedEndOfPath = false; } void Update() { if (path == null || reachedEndOfPath) return; // Get direction to next waypoint Vector3 direction = (path.vectorPath[currentWaypoint] - transform.position).normalized; direction.y = 0; // Calculate potential new position Vector3 movement = direction * moveSpeed * Time.deltaTime; Vector3 newPosition = transform.position + movement; // Check if new position is valid for 2x2 agent if (IsPositionValid(newPosition)) { // Move to valid position transform.position = newPosition; lastValidPosition = newPosition; // Check if we reached current waypoint float distanceToWaypoint = Vector3.Distance(transform.position, path.vectorPath[currentWaypoint]); if (distanceToWaypoint < nextWaypointDistance) { currentWaypoint++; if (currentWaypoint >= path.vectorPath.Count) { reachedEndOfPath = true; } } } else { // If movement is invalid, try to find alternative path Debug.Log("Blocked! Recalculating path..."); SetDestination(path.vectorPath[path.vectorPath.Count - 1]); } } bool IsPositionValid(Vector3 position) { // Get the base node (bottom-left of our 2x2 area) var nearest = GetAnchorPosition(position); // Check all nodes in 2x2 area for (int x = 0; x < agentWidth; x++) { for (int z = 0; z < agentHeight; z++) { GridNode node = (GridNode)gridGraph.GetNode(nearest.gridX + x, nearest.gridZ + z); if (node == null || !node.Walkable) { return false; } } } return true; } (Vector3 position, int gridX, int gridZ) GetAnchorPosition(Vector3 worldPosition) { // Get nearest node to the position var nearestInfo = AstarPath.active.GetNearest(worldPosition); // Convert to grid coordinates GridNode centerNode = nearestInfo.node as GridNode; int centerX = centerNode.XCoordinateInGrid; int centerZ = centerNode.ZCoordinateInGrid; // Calculate bottom-left node of 2x2 area // This ensures the agent center is at the intersection of 4 nodes int gridX = centerX - (agentWidth / 2); int gridZ = centerZ - (agentHeight / 2); // Adjust for even-sized agents (2x2) //if (agentWidth % 2 == 0) gridX += 1; //if (agentHeight % 2 == 0) gridZ += 1; // Clamp to grid boundaries gridX = Mathf.Clamp(gridX, 0, gridGraph.width - agentWidth); gridZ = Mathf.Clamp(gridZ, 0, gridGraph.depth - agentHeight); Vector3 anchorPos = (Vector3)gridGraph.GetNode(gridX, gridZ).position; // Adjust to bottom-left corner of the node anchorPos.x -= gridGraph.nodeSize * 0.5f; anchorPos.z -= gridGraph.nodeSize * 0.5f; return (anchorPos, gridX, gridZ); } void SnapToValidPosition() { var anchor = GetAnchorPosition(transform.position); transform.position = CalculateAgentCenter(anchor); lastValidPosition = transform.position; } Vector3 CalculateAgentCenter((Vector3 position, int gridX, int gridZ) anchor) { // Calculate center position of the agent based on bottom-left anchor Vector3 center = anchor.position; center.x += (agentWidth * gridGraph.nodeSize) * 0.5f; center.z += (agentHeight * gridGraph.nodeSize) * 0.5f; return center; } void OnDrawGizmosSelected() { if (!Application.isPlaying || gridGraph == null) return; // Draw current occupied nodes var anchor = GetAnchorPosition(transform.position); Gizmos.color = new Color(0, 1, 0, 0.5f); for (int x = 0; x < agentWidth; x++) { for (int z = 0; z < agentHeight; z++) { Vector3 nodePos = (Vector3)gridGraph.GetNode(anchor.gridX + x, anchor.gridZ + z).position; Gizmos.DrawCube(nodePos, Vector3.one * gridGraph.nodeSize * 0.9f); } } // Draw path if available if (path != null) { Gizmos.color = Color.yellow; for (int i = 0; i < path.vectorPath.Count - 1; i++) { Gizmos.DrawLine(path.vectorPath[i], path.vectorPath[i + 1]); } } }
Would it be possible to use multiple graphs on the agent to achieve this? I can’t think of a clean way to achieve it through larger nodes or modified settings
Hi
The 2x2 pathfinding you want is fundamentally equivalent to a graph which is offset by half a node in each direction, and which has a larger collision checking diameter. Does that not work?
Hmm, I could do it that way, this is for my enemy ai so they need to find targets. Currently this is done by incrementing through all the reachable nodes then I use a raycast to see if there’s a player character on the node. If the enemy is on a different grid i would have to change this system right? Then I’d have to convert where the player character is standing to the enemy ai’s grid to know where to set it’s move destination to. Or am I over complicating?
Not sure that I’m understanding what you are saying.
The destination is just a world position, and that will be the same regardless of graph.
I’m centring the destination on the node I want the agent to move to, so if I make the agent on the offset grid move to that destination, it will be in-between grid nodes for the offset right?
Then it will move to one of the nodes on the offset grid which could be one I don’t want it moving to, so i have to offset the destination first, is that right? So it takes into account the offset grid and moves exactly to the node I want it to.
Hi
A 2x2 agent has 4 positions that equally overlap any given 1x1 node, right? So if you give the agent a destination of a non-offset node, it is indeed ambiguous how to move for the 2x2 agent.