Search Unity

How to park my car completely?

Discussion in 'General Discussion' started by shez561, May 4, 2020.

Thread Status:
Not open for further replies.
  1. shez561

    shez561

    Joined:
    Sep 19, 2019
    Posts:
    20
    Hi dev,

    Im new here and trying to learn unity. Im actually working on a car parking game and was wondering if someone could help me in how to park the car completely within the lines rather than just adding an OnTrigger/OnCollision function which I believe wouldn't be satisfactory for me.
    So if anyone could help me in how to code this specific function would be highly appreciated.

    Thanks.


    car parking.png
     
  2. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    Well, if you want to avoid doing things more in code, you could surround the parking spot with thick box triggers. Then wait until the car doesn’t touch any if the four sides. That would mean that the car is either completely without the bounds, or completely outside the trigger zone... So naturally you have to think about the entry situation too (i.e. when you enter the spot area), maybe use triggers for it, too. Just a quick idea.
     
  3. shez561

    shez561

    Joined:
    Sep 19, 2019
    Posts:
    20
    Thanks for the idea.

    btw is there any way I could code as the function shouldn't called untill the object is completely inside the box collider. I mean Im thinking of to add a full box collider to the parking slot and until the car is completely not entered in the box collider the window shouldn't pop up that yes the car is parked.
     
    AlanMattano likes this.
  4. shez561

    shez561

    Joined:
    Sep 19, 2019
    Posts:
    20
  5. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    @shez561 I think you're either thinking it a bit backwards, or not thinking about all the solutions.
    If you want to go the way you're seemingly going, why can't you then put small corner/boundary markers in your car. Then check when each and every one of them is inside a collider?
     
  6. shez561

    shez561

    Joined:
    Sep 19, 2019
    Posts:
    20
    Actually Im not so good in coding. its not about thinking backwards, its about the easiest way to solve it. Your idea was superb but Im basically weak in how to write specific code according to your idea by adding thick colliders.
     
  7. SINePrime

    SINePrime

    Joined:
    Jan 24, 2019
    Posts:
    54
  8. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    @SINePrime there's many ways to doing this. But something as simple as this will work fine and is easier to customize (imo):

    Code (CSharp):
    1. public class DetectVehicle : MonoBehaviour
    2. {
    3.     int collisionCount;
    4.  
    5.     void Update()
    6.     {
    7.         if (collisionCount >= 4) {
    8.             Debug.Log("Vehicle parked successfully.");
    9.         }
    10.     }
    11.  
    12.     void OnTriggerEnter(Collider coll)
    13.     {
    14.         if (coll.tag == "Wheel") {
    15.             collisionCount++;
    16.         }
    17.     }
    18.  
    19.     void OnTriggerExit(Collider coll)
    20.     {
    21.         if (coll.tag == "Wheel") {
    22.             collisionCount--;
    23.         }
    24.     }
    25. }
    Anyway, then just add small colliders to wheels, or maybe the extents of the vehicle, and just wait until the collision count is high enough. If it was some 18-wheeler or something like that, you would probably add more colliders and watch for the count needed.

    EDIT:
    Here's a mock scene to visualize the setup in case it's still unclear after my code snippet:

    car_parking.PNG
     
    Last edited: May 4, 2020
    ryanm007 likes this.
  9. shez561

    shez561

    Joined:
    Sep 19, 2019
    Posts:
    20

    Thank you so much @Olmi . You really made it easy for me.
    Thanks again
     
  10. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    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:
    upload_2020-5-4_18-26-18.png


    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:
    upload_2020-5-4_18-29-8.png
    (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.
    Code (csharp):
    1.  
    2. var carVectorUp = parkingLot.transform.InverseTransformDirection(car.transform.up);
    3. var carVectorForward = parkginLot.transform.InverseTransformDirection(car.transform.forward);
    4. var carVectorRight = parkingLot.transform.InverseTransformDirection(car.transform.right);
    5. var carVectorPos = parkingLot.transform.InverseTransformPosition(car.transform.position);
    6.  
    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:
    upload_2020-5-4_18-42-37.png
    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:
    Code (csharp):
    1.  
    2. Vector3 carVectorForward... ((car vector forward within parking lot space
    3. Vector3 carVectorRight ((car vector pointing right within parking lot space
    4. Vector3 carVectorPos ((car component positio in parking lot space
    5. ParkingCar carComponent ((component representing car
    6. ParkingLot lotComponent ((component representing lot
    7.  
    8. var halfWidthVector = carVectorRight * carComponent.width * 0.5f;
    9. var halfLengthVector = carVectorForward * carComponent.length * 0.5f;
    10.  
    11. //Corners of the car.
    12. var a = carVectorPos + halfWidthVector + halfLengthVector;
    13. var b = carVectorPos - halfWidthVector + halfLengthVector;
    14. var c = carVectorPos + halfWidthVector - halfLengthVector;
    15. var d = carVectorPos - halfWidthVector - halfLengthVector;
    16.  
    17. var aabbMin = Vector3.Min(Vector3.Min(a,b), Vector3.Min(c, d));
    18. var aabbMax = Vector3.Max(Vector3.Max(a,b), Vector3.Max(c, d));
    19.  
    20. //Actual overlap test:
    21. bool noOverlap =
    22.     (aabbMin.x > -lotComponent.width * 0.5f)
    23.     && (aabbMax.x < lotComponent.width * 0.5f)
    24.     && (aabbMin.z > -lotComponent.length * 0.5f)
    25.     && (aabbMax.z < lotComponent.length * 0.5f);
    26.  
    27. bool collision = !noOverlap;
    28.  
    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.
     
  11. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    One more thing. @shez561

    4 colliders thing @Olmi posted earlier is also a perfectly acceptable solution, but it all depends on how fancy do you want to get.

    My approach would allow the game to be as pedantic as you want, meaning you could say "20 centimeters from car side to the edge of parking lot on each side, and perfectly parallel".

    Olmi's approach would detect car inside the box, but the car can be facing wrong way, be flipped over and so on, and it will still count.

    So depending on needs you could do it this or that way. Or some other way.
     
  12. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    @neginfinity a simple up vector check would fix the problem with being upside down :). But I thought that as a simple starting point. You are of course right about those parallel checks etc. But those too could be implemented easily with my hacky, less-math approach by just measuring distance to the sides of the parking zone. That way it would be easy to calculate the angle from one side wheels, for example.
     
  13. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    True, I just prefer more math-oriented appraoch which gives me a component with 2 parameters and cool wireframe visual in the scene view.

    Either way there's more than one way to do it.

    There's also a small matter of those corner colliders technically affecting physical behavior of the car (IIRC triggers don't collide with triggers, so they'll end up as a part of a rigidbody somewhere)
     
  14. shez561

    shez561

    Joined:
    Sep 19, 2019
    Posts:
    20
    Thank you so much @neginfinity & @Olmi
    You guys rock. I appreciate that both of you gave me wonderful ideas.


    @neginfinity Is there any way I can approach you sometime?
     
  15. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Personally, I'd start with a marker in the middle of the parking lot and use Vector3.Distance(...) and Quaternion.Angle(...), because I could get a first pass in under a minute. However, once I started tweaking things I think I'd ultimately end up with pretty much exactly what @neginfinity posted.

    Great write-up, by the way, @neginfinity.
     
    neginfinity likes this.
  16. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    It was an interesting problem, hence the larger writeup.

    I have PMs enabled, but, uh, I don't exactly dedicate my time to free tutoring, and usually respond to things that draw my attention in some way or are interesting to me. No offense intended.
     
    shez561, Ryiah and angrypenguin like this.
  17. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    I would do something like this, pseud code

    Code (CSharp):
    1.  
    2. if(!(zone.bounds.Contains(car.bounds.max) && zone.bounds.Contains(car.bounds.min)) return;
    3.  
    4. if(Quaternion.Angle(car.transform.rotation, zone.transform.rotation) > 10) return;
     
  18. shez561

    shez561

    Joined:
    Sep 19, 2019
    Posts:
    20
    Thanks again guys.

    When I was creating this thread trust me I had nothing in my mind how exactly do I tackle this problem cause Im a bit weak in writing code.
    But now with everybody's suggestion and ideas, Im very much clear about all this.
    Big thanks to @Olmi and @neginfinity as both of you gave me two different but wonderful way of solving this.
     
  19. ansi_here03

    ansi_here03

    Joined:
    Jan 7, 2021
    Posts:
    2
    but the wheels of rcc dont have rigid body on them how to detect collison if body dont have rigidbody
     
  20. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,769
    Old topic, but seems proposed solutions are unneccesairly over complicating, for such simplistic game.

    Just get position tolerance of parking slot and a car. Then calculate dot product of parking slot direction and car direction.
    Make a tolerance of let's say 5-10%, which is somehow around +-0.95 depending on facing direction.

    No colliers, no bounding boxes are required.

    That ensures car must be parked in proper manner.

    Done.
     
Thread Status:
Not open for further replies.