- Home /
Obstacle avoidance fine tuning assistance.
Hello.
I have created a simple system of character obstacle avoidance via ray casting. This is an old technique which most people understand already. But I'm trying to fine tune the movements a bit so they're more natural. Please see the YouTube video linked below. This is my sandbox scene which contains 24 'Ethan' characters walking around attempting to avoid each other, as well as a number of static objects. All animation is done via RootMotion.
https://www.youtube.com/watch?v=uGa6rPYIm3k
This is ~mostly~ working okay, but as you can see there's a considerable amount of jittery rotation as the rays collide with other objects. The other issue is that when two character collide they try to turn towards each other to get around rather than turning away from each other (if both characters turned to their right, they'd go around each other).
The function call for this is below;
/// <summary>
/// This function is used to get a movement angle for a player to walk/jog towards a target while avoiding static and moving objects.
/// </summary>
public bool MoveToPosition(Transform _PlayerTransform, Vector3 _TargetVector)
{
Vector3 PlayerPosition = _PlayerTransform.position;
PlayerPosition.y = 0.5f;
Vector3 PlayerForward = _PlayerTransform.forward;
//PlayerForward.y = 0.5f;
Vector3 TargetPosition = _TargetVector;
TargetPosition.y = 0.5f;
float DeflectionAmount = 20.0f;
float ShoulderRayDistance = 1.0f;
float ForwardRayDistance = 1.5f;
float Targetdistance = Vector3.Distance(PlayerPosition, TargetPosition);
//Send back a notice that we've reached the target...
if (Targetdistance < 0.5f)
return true;
//If I'm closer to my target than the default ray distance, make the ray distance my target distance and ignore my shoulders.
if (Targetdistance < ForwardRayDistance)
{
ForwardRayDistance = Targetdistance;
ShoulderRayDistance = 0;
}
Vector3 dir = (TargetPosition - PlayerPosition).normalized;
RaycastHit hit;
float ShoulderDistance = 0.25f;
Vector3 leftRay = PlayerPosition - (_PlayerTransform.right * ShoulderDistance);
Vector3 rightRay = PlayerPosition + (_PlayerTransform.right * ShoulderDistance);
if (Physics.Raycast(PlayerPosition, PlayerForward, out hit, ForwardRayDistance))
{
Debug.DrawLine(PlayerPosition, hit.point, Color.red);
if(hit.transform != _PlayerTransform)
dir += hit.normal * DeflectionAmount;
}
if (Physics.Raycast(leftRay, PlayerForward, out hit, ShoulderRayDistance))
{
Debug.DrawLine(leftRay, hit.point, Color.red);
if (hit.transform != _PlayerTransform)
dir += hit.normal * DeflectionAmount;
}
if (Physics.Raycast(rightRay, PlayerForward, out hit, ShoulderRayDistance))
{
Debug.DrawLine(rightRay, hit.point, Color.red);
if (hit.transform != _PlayerTransform)
dir += hit.normal * DeflectionAmount;
}
else
{
Debug.DrawRay(PlayerPosition, PlayerForward * ForwardRayDistance, Color.blue);
Debug.DrawRay(leftRay, PlayerForward * ShoulderRayDistance, Color.green);
Debug.DrawRay(rightRay, PlayerForward * ShoulderRayDistance, Color.green);
}
dir.y = 0; //Make sure we kill the y before we rotate to look that way otherwise we rotate up and down too.
TurnTowardsAngle(Quaternion.LookRotation(dir).eulerAngles.y, 5.0f);
return false;
}
/// <summary>
/// Makes the player rotate smoothly so that he's facing an angle from 0 to 359
/// </summary>
public void TurnTowardsAngle(float _Angle, float _TurnSpeed)
{
Quaternion target = Quaternion.Euler(0, _Angle, 0);
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, target, Time.deltaTime * _TurnSpeed);
}
As you can see above, it's just the same raycast direction change used in a lot of places, but I'm trying to smooth out the rotation of the character so that he doesn't jitter from collision/not colliding from frame to frame.
I've tried reducing the turn amount (in the TurnTowardsAngle() call) but this results in the character missing his target if he's very close to it. He can no longer turn fast enough to get to a target that's right beside him.
Any suggestions on how to improve this so that the movement around static objects and other characters is smoother, would be appreciated.
thanks David
It does look like your turnspeed is generally a bit too fast. Just something that might help. Try adding a collider to the actors, if they're colliding with other actors or static objects dampen the turn speed more.
All the actors have capsule colliders. Raycasting collision detection doesn't work without them.
But that's an interesting idea to adjust the turnrate based on collisions. I'll give that a go.
thanks
It may also be worth varying the speed of actors, slowing them or accelerating them depending on the collision detection vector & magnitude. At the moment because their travel speed is not adjusted they're fighting, bouncing off one another until one eventually breaks free.
The same as you would walking through a busy street. Unless of course there's a gameplay reason why you wish for them to remain at a constant speed.
Yes, that's one of the things I'm working on. Good idea.
The bigger issue I see is that sometimes a character will get caught up by another character walking in front of him. What I mean is;
Character A is walking North (up) towards his target.
Character B is walking West (to the left) and passing infront of Character A.
Character A gets a collision but doesn't know that he should walk behind Character B. Ins$$anonymous$$d he ends up turning along the same path as Character B and they end up walking in step beside each other. I need to find a way to allow Character A to walk behind Character B if that is the best option to get to the target.
(yet all the while still walking around the static objects that won't move).
thanks $$anonymous$$
Your answer
Follow this Question
Related Questions
AI bug issue 0 Answers
180 Degree raycast 1 Answer
How can I make the I see the player better? 1 Answer
raycast hit not detecting && Nav mesh agent ai stealth 1 Answer
Enemy Line of Sight 1 Answer