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 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.
This is the relevant code for everything that’s happening in the scene (assuming the colliders are character controllers)
Blue move code
void Update()
{
if (isSelected && transform.position != destination)
{
//Set angle and magnitude
float angle = AngleBetween(transform.position, destination);
float magnitude = Time.deltaTime * speed;
if (magnitude > Vector3.Distance(transform.position, destination))
{
magnitude = Vector3.Distance(transform.position, destination);
}
//Capsule cast
float radius = cc.radius * transform.localScale.x + MARKER_EXTENSION * 2 + SUBJECT_CORRECTION;
RaycastHit[] hits = Physics.CapsuleCastAll(transform.position, Top(transform.position), radius, AngleToVector(angle), magnitude);
//Shove block
foreach (RaycastHit hit in hits)
{
if (hit.collider != GetComponent<Collider>() && hit.collider.GetComponent<CharacterController>() != null)
{
hit.collider.GetComponent<TestScript>().Shove(gameObject, angle, magnitude);
}
}
//Move block
if (magnitude == Vector3.Distance(transform.position, destination))
{
transform.position = destination;
}
else
{
cc.Move(AngleToVector(angle) * magnitude);
}
}
}
Red move code
void LateUpdate()
{
//Attempt to snapback
if (!isSelected && transform.position != anchoredPosition)
{
//Set angle and magnitude
float angle = AngleBetween(transform.position, anchoredPosition);
float magnitude = Time.deltaTime * speed;
if (magnitude > Vector3.Distance(transform.position, anchoredPosition))
{
magnitude = Vector3.Distance(transform.position, anchoredPosition);
}
//Overlap capsule to avoid snagging on anything behind this unit
float radius = cc.radius * transform.localScale.x + MARKER_EXTENSION * 2 + OBJECT_CORRECTION;
Collider[] hits = Physics.OverlapCapsule(transform.position + AngleToVector(angle) * magnitude, Top(transform.position) + AngleToVector(angle) * magnitude, radius);
magnitude = AdjustMagnitude(hits, magnitude);
//Move block
if (magnitude == Vector3.Distance(transform.position, anchoredPosition))
{
transform.position = anchoredPosition;
}
else
{
cc.Move(AngleToVector(angle) * magnitude);
}
print(Vector3.Distance(transform.position, GameObject.Find("Evil Lich").transform.position));
}
}
Shove function
public void Shove(GameObject caller, float cAngle, float cMagnitude)
{
//Only works if the unit isn't selected
if (!isSelected)
{
//Zero out positions
Vector3 myPosition = new Vector3(transform.position.x, 0, transform.position.z);
Vector3 callerPosition = new Vector3(caller.transform.position.x, 0, caller.transform.position.z) + AngleToVector(cAngle) * cMagnitude;
//Calculate magnitude
float radiusum = cc.radius * transform.localScale.x + caller.GetComponent<CharacterController>().radius * caller.transform.localScale.x + MARKER_EXTENSION * 2;
float distance = Vector3.Distance(callerPosition, myPosition);
float angleBetween = Vector3.Angle(AngleToVector(cAngle), (myPosition - callerPosition).normalized);
float theta = 180 - (90 + angleBetween + Mathf.Asin(Mathf.Cos(Mathf.Deg2Rad * angleBetween) * distance / radiusum) * Mathf.Rad2Deg);
float magnitude = Mathf.Sqrt(Mathf.Pow(distance, 2) + Mathf.Pow(radiusum, 2) - 2 * distance * radiusum * Mathf.Cos(Mathf.Deg2Rad * theta));
//Decide direction
Vector3 rightPosition = myPosition + AngleToVector(cAngle + 90) * magnitude;
Vector3 leftPosition = myPosition + AngleToVector(cAngle - 90) * magnitude;
float shoveAngle;
if (Vector3.Distance(callerPosition, rightPosition) >= Vector3.Distance(callerPosition, leftPosition))
{
shoveAngle = cAngle + 90;
}
else
{
shoveAngle = cAngle - 90;
}
//cc.Move(AngleToVector(shoveAngle) * magnitude);
if (magnitude > 0)
{
cc.Move(AngleToVector(shoveAngle) * magnitude);
}
}
}
Adjust Magnitude function
float AdjustMagnitude(Collider[] hits, float magnitude)
{
foreach (Collider hit in hits)
{
if (hit != GetComponent<Collider>() && hit.GetComponent<CharacterController>() != null)
{
//Sides
float radiusum = cc.radius * transform.localScale.x + hit.GetComponent<CharacterController>().radius * hit.transform.localScale.x + MARKER_EXTENSION * 2;
float returnDistance = Vector3.Distance(transform.position, anchoredPosition);
float actorTrajectory = Vector3.Distance(hit.transform.position, anchoredPosition);
//Angles
float theta = Mathf.Acos((Mathf.Pow(returnDistance, 2) + Mathf.Pow(actorTrajectory, 2) - Mathf.Pow(radiusum, 2)) / (2 * returnDistance * actorTrajectory));
float phi = Mathf.Asin(Mathf.Sin(theta) * actorTrajectory / radiusum);
//Magnitude
float leftover = radiusum * Mathf.Sin(Mathf.PI - (theta + phi)) / Mathf.Sin(theta);
float prospectiveMagnitude = returnDistance - leftover;
if (prospectiveMagnitude < magnitude)
{
magnitude = prospectiveMagnitude;
}
}
}
return magnitude;
}