Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question What's the deal with CharacterController?

Discussion in 'Scripting' started by Falcoshin, May 31, 2021.

  1. Falcoshin

    Falcoshin

    Joined:
    May 31, 2017
    Posts:
    168
    What I'm trying to do is, as demonstrated here, have the blue unit push the red one out of the way as it's moving then have the red unit try to snap back to its original position if nothing is in its way (or at least move as close to it as it can without colliding with anything). While the entire thing is taking place, the red unit and the blue unit are always suppose to be <radiusum> distance away from each other. And, while the code works just fine when the colliders attached to the units are capsule colliders, everything falls apart as soon as I swap them for character controllers and I have no idea why.

    Shove demo.gif

    This is the relevant code for everything that's happening in the scene (assuming the colliders are character controllers)

    Blue move code
    Code (csharp):
    1.  
    2. void Update()
    3.         {
    4.             if (isSelected && transform.position != destination)
    5.             {
    6.                 //Set angle and magnitude
    7.                 float angle = AngleBetween(transform.position, destination);
    8.                 float magnitude = Time.deltaTime * speed;
    9.                 if (magnitude > Vector3.Distance(transform.position, destination))
    10.                 {
    11.                     magnitude = Vector3.Distance(transform.position, destination);
    12.                 }
    13.                 //Capsule cast
    14.                 float radius = cc.radius * transform.localScale.x + MARKER_EXTENSION * 2 + SUBJECT_CORRECTION;
    15.                 RaycastHit[] hits = Physics.CapsuleCastAll(transform.position, Top(transform.position), radius, AngleToVector(angle), magnitude);
    16.                 //Shove block
    17.                 foreach (RaycastHit hit in hits)
    18.                 {
    19.                     if (hit.collider != GetComponent<Collider>() && hit.collider.GetComponent<CharacterController>() != null)
    20.                     {
    21.                         hit.collider.GetComponent<TestScript>().Shove(gameObject, angle, magnitude);
    22.                     }
    23.                 }
    24.                 //Move block
    25.                 if (magnitude == Vector3.Distance(transform.position, destination))
    26.                 {
    27.                     transform.position = destination;
    28.                 }
    29.                 else
    30.                 {
    31.                     cc.Move(AngleToVector(angle) * magnitude);
    32.                 }
    33.             }
    34.         }
    Red move code
    Code (csharp):
    1.  
    2. void LateUpdate()
    3.         {
    4.             //Attempt to snapback
    5.             if (!isSelected && transform.position != anchoredPosition)
    6.             {
    7.                 //Set angle and magnitude
    8.                 float angle = AngleBetween(transform.position, anchoredPosition);
    9.                 float magnitude = Time.deltaTime * speed;
    10.                 if (magnitude > Vector3.Distance(transform.position, anchoredPosition))
    11.                 {
    12.                     magnitude = Vector3.Distance(transform.position, anchoredPosition);
    13.                 }
    14.                 //Overlap capsule to avoid snagging on anything behind this unit
    15.                 float radius = cc.radius * transform.localScale.x + MARKER_EXTENSION * 2 + OBJECT_CORRECTION;
    16.                 Collider[] hits = Physics.OverlapCapsule(transform.position + AngleToVector(angle) * magnitude, Top(transform.position) + AngleToVector(angle) * magnitude, radius);
    17.                 magnitude = AdjustMagnitude(hits, magnitude);
    18.                 //Move block
    19.                 if (magnitude == Vector3.Distance(transform.position, anchoredPosition))
    20.                 {
    21.                     transform.position = anchoredPosition;
    22.                 }
    23.                 else
    24.                 {
    25.                     cc.Move(AngleToVector(angle) * magnitude);
    26.                 }
    27.                 print(Vector3.Distance(transform.position, GameObject.Find("Evil Lich").transform.position));
    28.             }
    29.         }
    Shove function
    Code (csharp):
    1.  
    2. public void Shove(GameObject caller, float cAngle, float cMagnitude)
    3.     {
    4.         //Only works if the unit isn't selected
    5.         if (!isSelected)
    6.         {
    7.             //Zero out positions
    8.             Vector3 myPosition = new Vector3(transform.position.x, 0, transform.position.z);
    9.             Vector3 callerPosition = new Vector3(caller.transform.position.x, 0, caller.transform.position.z) + AngleToVector(cAngle) * cMagnitude;
    10.             //Calculate magnitude
    11.             float radiusum = cc.radius * transform.localScale.x + caller.GetComponent<CharacterController>().radius * caller.transform.localScale.x + MARKER_EXTENSION * 2;
    12.             float distance = Vector3.Distance(callerPosition, myPosition);
    13.             float angleBetween = Vector3.Angle(AngleToVector(cAngle), (myPosition - callerPosition).normalized);
    14.             float theta = 180 - (90 + angleBetween + Mathf.Asin(Mathf.Cos(Mathf.Deg2Rad * angleBetween) * distance / radiusum) * Mathf.Rad2Deg);
    15.             float magnitude = Mathf.Sqrt(Mathf.Pow(distance, 2) + Mathf.Pow(radiusum, 2) - 2 * distance * radiusum * Mathf.Cos(Mathf.Deg2Rad * theta));
    16.             //Decide direction
    17.             Vector3 rightPosition = myPosition + AngleToVector(cAngle + 90) * magnitude;
    18.             Vector3 leftPosition = myPosition + AngleToVector(cAngle - 90) * magnitude;
    19.             float shoveAngle;
    20.             if (Vector3.Distance(callerPosition, rightPosition) >= Vector3.Distance(callerPosition, leftPosition))
    21.             {
    22.                 shoveAngle = cAngle + 90;
    23.             }
    24.             else
    25.             {
    26.                 shoveAngle = cAngle - 90;
    27.             }
    28.             //cc.Move(AngleToVector(shoveAngle) * magnitude);
    29.             if (magnitude > 0)
    30.             {
    31.                 cc.Move(AngleToVector(shoveAngle) * magnitude);
    32.             }
    33.         }
    34.     }
    Adjust Magnitude function
    Code (csharp):
    1.  
    2. float AdjustMagnitude(Collider[] hits, float magnitude)
    3.     {
    4.         foreach (Collider hit in hits)
    5.         {
    6.             if (hit != GetComponent<Collider>() && hit.GetComponent<CharacterController>() != null)
    7.             {
    8.                 //Sides
    9.                 float radiusum = cc.radius * transform.localScale.x + hit.GetComponent<CharacterController>().radius * hit.transform.localScale.x + MARKER_EXTENSION * 2;
    10.                 float returnDistance = Vector3.Distance(transform.position, anchoredPosition);
    11.                 float actorTrajectory = Vector3.Distance(hit.transform.position, anchoredPosition);
    12.                 //Angles
    13.                 float theta = Mathf.Acos((Mathf.Pow(returnDistance, 2) + Mathf.Pow(actorTrajectory, 2) - Mathf.Pow(radiusum, 2)) / (2 * returnDistance * actorTrajectory));
    14.                 float phi = Mathf.Asin(Mathf.Sin(theta) * actorTrajectory / radiusum);
    15.                 //Magnitude
    16.                 float leftover = radiusum * Mathf.Sin(Mathf.PI - (theta + phi)) / Mathf.Sin(theta);
    17.                 float prospectiveMagnitude = returnDistance - leftover;
    18.                
    19.                 if (prospectiveMagnitude < magnitude)
    20.                 {
    21.                     magnitude = prospectiveMagnitude;
    22.                 }
    23.             }
    24.         }
    25.         return magnitude;
    26.     }
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,758
    I'm confused: The video looks reasonable to me... is the video showing what it does with colliders and what you WANT it to do with CC and it is doing something else?
     
  3. Falcoshin

    Falcoshin

    Joined:
    May 31, 2017
    Posts:
    168
    It's certainly close enough to what it's suppose to look like to get the basic picture of what the code is ultimately suppose to do, but there are still problems such as the distancing between the two units at any given time. There are frames where they're more than <radiusum> distance apart when they aren't suppose to be and there's even a frame where the red unit apparently doesn't see where the blue unit is when it's suppose to and refuses to no matter how big I set OBJECT_CORRECTION. Like I said, these problems completely disappear when I use capsule colliders instead of character controllers, but as soon as I swap back to character controllers then everything falls apart and I have to use those SUBJECT_CORRECTION/OBJECT_CORRECTION constants and even then they don't account for everything I want them to account for.