With a collider attached to the object, we can use a method like this to skim along its surface:
void MoveAroundObstacle(
Vector3 destination,
float speed,
Collider obstacle,
float bufferRadius) {
// How far can we move this frame?
float range = speed * Time.deltaTime;
if(obstacle != null) {
// Check if we hit the obstacle on this move.
Vector3 direction = destination - transform.position;
Ray ray = new Ray(transform.position, direction);
RaycastHit hit;
if(obstacle.Raycast(ray, out hit, range + bufferRadius)) {
direction = direction.normalized;
// Project the direction we want to go onto the surface.
Vector3 parallel = direction
- Vector3.Dot(hit.normal, direction) * hit.normal;
// Ensure we have a sensible unit vector parallel to the surface.
if(Mathf.Approximately(parallel.sqrMagnitude, 0f)) {
parallel = Quaternion.LookRotation(hit.normal) * Vector3.right;
} else {
parallel = parallel.normalized;
}
// Divvy-up our movement for the frame between movement toward the destination,
// and movement along the surface in the closest direction available.
float forwardMovement = hit.distance - bufferRadius;
float sidewaysMovement = Mathf.Max(range - Mathf.Abs(forwardMovement), 0f);
// Make the move.
transform.Translate(
forwardMovement * direction
+ sidewaysMovement * parallel,
Space.World);
return;
}
}
// No obstacle in range. Let's use our full movement to travel toward the destination.
transform.position = Vector3.MoveTowards(
transform.position,
destination,
range);
}
Some things to note:
a bufferRadius
greater than zero helps keep our object from penetrating into the obstacle visually, and also helps keep our raycast start point slightly outside the object, so we never miss it by starting our scan from inside its skin already.
this method uses naive hill-climbing based on the current closest intersection point alone - it doesn't know anything about the global structure of the shape. If the object is mostly convex, this shouldn't pose a problem. But if it has a valley or divot exactly opposite the destination, this following logic can get stuck there.
(From one side of the valley, it looks like descending deeper into the valley brings us closer to the destination, so we descend until we start to climb the far side, at which point it looks like the closest path to the destination is to turn around and go back down into the valley)
This method fires just one ray, assuming that the overall surface behaviour in this region will be well represented by a single ray hit. ie. It posits that the collider doesn't have extremely small crevices & sharp corners that might give a misleading result. The buffer radius gives us some protection against these issues, but it's not bulletproof.
If you need a more robust result, you can use a SphereCast or other shapecast instead, and fire a secondary cast after computing the move from the first hit to ensure it's not taking us into an adjacent wall.