I'm working on RTS game and got stuck on a pretty simple question I think, but I'm not skilled enough to find the proper answer. I don't want to use Unity built-in physics to do the job for me and I think I have reasons for that, so my units won't use Rigidbody and such (however I am using box colliders to get informed about collisions).
The question is how to align the unit with the slope of the terrain so that it appears to move up and down or sideways?
Let me describe the approach I've taken so far. I use following method to get height on each edge of the collider:
private Vector3 GetTerrainHeightAtPoint(Vector3 point)
{
var height = Terrain.activeTerrain.SampleHeight(new Vector3(point.x, 0, point.z));
return new Vector3(point.x, height, point.z);
}
Then I use these vectors (topLeft, topRight, bottomLeft and bottomRight) to make two triangles out of them and calculate their normals. That's just in case if terrain height is different on every edge. Then I calculate slope vector (not on each frame, I use coroutine to update the value every tenth of a second, but moving the code to FixedUpdate doesn't make any changes) by getting these normals combined.
Vector3 normal1 = Vector3.Cross(topRight - topLeft, bottomRight - topLeft).normalized;
Vector3 normal2 = Vector3.Cross(bottomRight - topLeft, bottomLeft - topLeft).normalized;
_slopeVector = (normal1 + normal2).normalized;
Finally I apply _slopeVector
to the rotation:
Quaternion targetRotation = Quaternion.LookRotation(target, _slopeVector);
_transform.localRotation = Quaternion.RotateTowards(_transform.localRotation, targetRotation, _turnSpeed * Time.fixedDeltaTime);
It all seems fine and results in this (aligns pretty well imho):
but not when the tank goes up or down:
I was debugging it a bit and most propably slope vector calculation is done wrong. I've tried some other approaches with no luck. There's no constraint on any axis and rotation is changed only in this one place in the code. However the unit rotates a little around X axis from time to time but it's almost not noticeable. I've also added small "debug squares" on the edges of the unit's collider just to see if height of all four points is calculated properly and it does. Just the slope calculation fails for some reason I think.
Do you know what I am doing wrong? Maybe there's better solution for my problem? Tried working this out with ChatGPT but it fails like totaly xD
FYI: tank and the terrain looks like sh*t because rn I am focused on movement, pathfinding, grouping, orders and so on.
EDIT: I've added debug line that told me that _slopeVector
is calculated correctly (see the red line). So I created completly new monobehaviour class and attached it to a box. No changes:
The problem has to be somewhere here:
Quaternion targetRotation = Quaternion.LookRotation(target, _slopeVector);
Debug.DrawLine(transform.position, transform.position + _slopeVector * 6, Color.red);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, turnSpeed * Time.fixedDeltaTime);
I've also tried Quaternion.Lerp
and Slerp
with no success.
EDIT2: It somehow started to work better when I set it that way:
targetRotation.x = _slopeVector.x;
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
but I don't think this is the right solution, right? :)