I don’t have “mention” notification enabled, so tagging me is not very useful. For the future reference. I wander around forum randomly, respond to things I find interesting and tend to hang out in general.
Regarding the car.
This is a 2d problem, pretty much.
I would create two components: “ParkingLot” and “ParkingCar”, each representing a rectangle with configurable width and length, and each would draw a wireframe rectangle gizmo in OnDrawGizmos/OnDrawGizmosSelected.
https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnDrawGizmos.html
It would look like this in scene view:
Then I’d place a trigger around the parking lot, and while a car is touching the trigger, I would poll the car for “ParkingCar” component and then solve the problem in 2d by hand:
(car is green, parking lot is blue)
Basically, both parking lot store width and length, and you want car to be oriented in specific way.
If you merely place colliders around the parking box, this will be a valid parking placement:
Upside-down, wrong direction, on the side, stuck into ground nose down, and so on. As long as colliders aren’t touched.
Hence I’d prefer to solve it in 2d with debug visualization.
To solve it in 2d, transform orientation vecotrs of “ParkingCar” (front/right/up) into parking lot space. This can be done by using parkingLot.transform.worldToLocalMatrix or by calling parkingLot.transform.InverseTransformPoint for position (of ParkingCar), and parkingLot.transform.InverseTransformDirection for directions.
https://docs.unity3d.com/ScriptReference/Transform-worldToLocalMatrix.html
https://docs.unity3d.com/ScriptReference/Transform.InverseTransformDirection.html
https://docs.unity3d.com/ScriptReference/Transform.html
By doing that you get basis vectors of the car in parking lot space.
var carVectorUp = parkingLot.transform.InverseTransformDirection(car.transform.up);
var carVectorForward = parkginLot.transform.InverseTransformDirection(car.transform.forward);
var carVectorRight = parkingLot.transform.InverseTransformDirection(car.transform.right);
var carVectorPos = parkingLot.transform.InverseTransformPosition(car.transform.position);
Past that point.
If carVectorUp.y < 0 (or Vector3.Dot(car.transform.up, parkingLot.transform.up), then the car is upside down.
By calling Mathf.Atan(carVectorUp.y) (or Mathf.Atan(Vector3.Dot(car.transfomr.up, parkingLot.transform.up))) you can calculate if the car is tilted and how much (doesn’t tell you in which direction, though).
Next. If Vector3.dot(car.transform.forward, parkingLot.transform.forward) OR Vector3.dot(car.transform.right, parkingLot.transform.right) are less than zero, then the car is facing wrong direction. If they’re both less than zero, then the car is facing in wrong direction, if only one, then it is flipped upside down.
If the car is aligned to ground and ground is perfectly flat, you can compute angle between car and parking lot by calculating Acos(Mathf.dot(car.transform.forward, parkingLot.transform.forward)).
Next. To verify whether the car is within the lot square, I’d perform simple boundary test. Because the car is within parkingLot space, and space is axis-aligned, we can calculate bounding box in 2d space of the car, and then check against lot boundaries:
Green is the car, blue is box boundaries, red is AABB of the car within the box.
In this case we’d go like this:
Vector3 carVectorForward... ((car vector forward within parking lot space
Vector3 carVectorRight ((car vector pointing right within parking lot space
Vector3 carVectorPos ((car component positio in parking lot space
ParkingCar carComponent ((component representing car
ParkingLot lotComponent ((component representing lot
var halfWidthVector = carVectorRight * carComponent.width * 0.5f;
var halfLengthVector = carVectorForward * carComponent.length * 0.5f;
//Corners of the car.
var a = carVectorPos + halfWidthVector + halfLengthVector;
var b = carVectorPos - halfWidthVector + halfLengthVector;
var c = carVectorPos + halfWidthVector - halfLengthVector;
var d = carVectorPos - halfWidthVector - halfLengthVector;
var aabbMin = Vector3.Min(Vector3.Min(a,b), Vector3.Min(c, d));
var aabbMax = Vector3.Max(Vector3.Max(a,b), Vector3.Max(c, d));
//Actual overlap test:
bool noOverlap =
(aabbMin.x > -lotComponent.width * 0.5f)
&& (aabbMax.x < lotComponent.width * 0.5f)
&& (aabbMin.z > -lotComponent.length * 0.5f)
&& (aabbMax.z < lotComponent.length * 0.5f);
bool collision = !noOverlap;
I’m using .x component, because “right” corresponds to parkingLot x axis in local space, and z corresponds to forward axis.
The reason why I’d go with this approach rather than placing colliders is because it gives me greater control over what is “acceptable” car orientation. For example, you could specify that even if no boundaries are touched, the car should be parallel to lot boundaries. Additionally, for a new car and a new lot I’d simply need to add one component and specify their width/length, there will be visualization in the debug with DrawGizmos and so on.
Of course that’s not the only way to do it.
Have fun.