Exemplo n.º 1
0
    public bool PlaceObject(SimObjPhysics sop, ReceptacleSpawnPoint rsp, bool PlaceStationary, int degreeIncrement, bool AlwaysPlaceUpright)
    {
        if (rsp.ParentSimObjPhys == sop)
        {
            #if UNITY_EDITOR
            Debug.Log("Can't place object inside itself!");
            #endif
            return(false);
        }

        //remember the original rotation of the sim object if we need to reset it
        //Quaternion originalRot = sop.transform.rotation;
        Vector3    originalPos = sop.transform.position;
        Quaternion originalRot = sop.transform.rotation;

        //get the bounding box of the sim object we are trying to place
        BoxCollider oabb = sop.BoundingBox.GetComponent <BoxCollider>();

        //zero out rotation and velocity/angular velocity, then match the target receptacle's rotation
        sop.transform.rotation = rsp.ReceptacleBox.transform.rotation;
        Rigidbody sopRB = sop.GetComponent <Rigidbody>();
        sopRB.velocity        = Vector3.zero;
        sopRB.angularVelocity = Vector3.zero;


        //set 360 degree increment to only check one angle, set smaller increments to check more angles when trying to place (warning THIS WILL GET SLOWER)
        int   HowManyRotationsToCheck = 360 / degreeIncrement;
        Plane BoxBottom;
        float DistanceFromBoxBottomTosop;

        List <RotationAndDistanceValues> ToCheck = new List <RotationAndDistanceValues>(); //we'll check 8 rotations for now, replace the 45 later if we want to adjust the amount of checks

        //get rotations and distance values for 360/increment number of rotations around just the Y axis
        //we want to check all of these first so that the object is prioritized to be placed "upright"
        for (int i = 0; i < HowManyRotationsToCheck; i++)
        {
            oabb.enabled = true;

            if (i > 0)
            {
                sop.transform.Rotate(new Vector3(0, degreeIncrement, 0), Space.Self);
                //ToCheck[i].rotation = sop.transform.rotation;

                Vector3 Offset = oabb.ClosestPoint(oabb.transform.TransformPoint(oabb.center) + -rsp.ReceptacleBox.transform.up * 10);
                BoxBottom = new Plane(rsp.ReceptacleBox.transform.up, Offset);
                DistanceFromBoxBottomTosop = Math.Abs(BoxBottom.GetDistanceToPoint(sop.transform.position));

                ToCheck.Add(new RotationAndDistanceValues(DistanceFromBoxBottomTosop, sop.transform.rotation));
            }

            else
            {
                //no rotate change just yet, check the first position

                Vector3 Offset = oabb.ClosestPoint(oabb.transform.TransformPoint(oabb.center) + -rsp.ReceptacleBox.transform.up * 10); //was using rsp.point
                BoxBottom = new Plane(rsp.ReceptacleBox.transform.up, Offset);
                DistanceFromBoxBottomTosop = BoxBottom.GetDistanceToPoint(sop.transform.position);

                ToCheck.Add(new RotationAndDistanceValues(DistanceFromBoxBottomTosop, sop.transform.rotation));
            }

            oabb.enabled = false;
        }

        //continue to check rotations about the X and Z axes if the object doesn't have to be placed upright
        if (!AlwaysPlaceUpright)
        {
            //ok now try if the X and Z local axis are rotated if it'll fit
            //these values can cause the object to be placed at crazy angles, so we'll check these last
            for (int i = 0; i < HowManyRotationsToCheck; i++)
            {
                oabb.enabled = true;

                if (i > 0)
                {
                    sop.transform.Rotate(new Vector3(0, degreeIncrement, 0), Space.Self);
                    Quaternion oldRotation = sop.transform.rotation;

                    //now add more points by rotating the x axis at this current y rotation
                    for (int j = 0; j < HowManyRotationsToCheck; j++)
                    {
                        sop.transform.Rotate(new Vector3(degreeIncrement, 0, 0), Space.Self);

                        Vector3 Offset = oabb.ClosestPoint(oabb.transform.TransformPoint(oabb.center) + -rsp.ReceptacleBox.transform.up * 10);
                        BoxBottom = new Plane(rsp.ReceptacleBox.transform.up, Offset);
                        DistanceFromBoxBottomTosop = Math.Abs(BoxBottom.GetDistanceToPoint(sop.transform.position));

                        ToCheck.Add(new RotationAndDistanceValues(DistanceFromBoxBottomTosop, sop.transform.rotation));
                    }

                    sop.transform.rotation = oldRotation;

                    //now add EVEN more points by rotating the z axis at this current y rotation
                    for (int j = 0; j < HowManyRotationsToCheck; j++)
                    {
                        sop.transform.Rotate(new Vector3(0, 0, degreeIncrement), Space.Self);

                        Vector3 Offset = oabb.ClosestPoint(oabb.transform.TransformPoint(oabb.center) + -rsp.ReceptacleBox.transform.up * 10);
                        BoxBottom = new Plane(rsp.ReceptacleBox.transform.up, Offset);
                        DistanceFromBoxBottomTosop = Math.Abs(BoxBottom.GetDistanceToPoint(sop.transform.position));

                        ToCheck.Add(new RotationAndDistanceValues(DistanceFromBoxBottomTosop, sop.transform.rotation));
                    }

                    sop.transform.rotation = oldRotation;
                }

                oabb.enabled = false;
            }
        }


        foreach (RotationAndDistanceValues quat in ToCheck)
        {
            //if spawn area is clear, spawn it and return true that we spawned it
            if (CheckSpawnArea(sop, rsp.Point + rsp.ParentSimObjPhys.transform.up * (quat.distance + yoffset), quat.rotation, false))
            {
                //translate position of the target sim object to the rsp.Point and offset in local y up
                sop.transform.position = rsp.Point + rsp.ReceptacleBox.transform.up * (quat.distance + yoffset);//rsp.Point + sop.transform.up * DistanceFromBottomOfBoxToTransform;
                sop.transform.rotation = quat.rotation;

                //now to do a check to make sure the sim object is contained within the Receptacle box, and doesn't have
                //bits of it hanging out

                //Check the ReceptacleBox's Sim Object component to see what Type it is. Then check to
                //see if the type is the kind where the Object placed must be completely contained or just the bottom 4 corners contained
                int HowManyCornersToCheck = 0;
                if (ReceptacleRestrictions.OnReceptacles.Contains(rsp.ParentSimObjPhys.ObjType))
                {
                    //check that only the bottom 4 corners are in bounds
                    HowManyCornersToCheck = 4;
                }

                if (ReceptacleRestrictions.InReceptacles.Contains(rsp.ParentSimObjPhys.ObjType))
                {
                    //check that all 8 corners are within bounds
                    HowManyCornersToCheck = 8;
                }

                if (ReceptacleRestrictions.InReceptaclesThatOnlyCheckBottomFourCorners.Contains(rsp.ParentSimObjPhys.ObjType))
                {
                    //only check bottom 4 corners even though the action is PlaceIn
                    HowManyCornersToCheck = 4;
                }

                int CornerCount = 0;

                //Plane rspPlane = new Plane(rsp.Point, rsp.ParentSimObjPhys.transform.up);

                //now check the corner count for either the 4 lowest corners, or all 8 corners depending on Corner Count
                //attmpt to sort corners so that first four corners are the corners closest to the spawn point we are checking against
                SpawnCorners.Sort(delegate(Vector3 p1, Vector3 p2)
                {
                    //sort by making a plane where rsp.point is, find the four corners closest to that point
                    //return rspPlane.GetDistanceToPoint(p1).CompareTo(rspPlane.GetDistanceToPoint(p2));
                    //^ this ended up not working because if something is placed at an angle this no longer makes sense...

                    return(Vector3.Distance(p1, rsp.Point).CompareTo(Vector3.Distance(p2, rsp.Point)));

                    // return Vector3.Distance(new Vector3(0, p1.y, 0), new Vector3(0, rsp.Point.y, 0)).CompareTo(
                    // Vector3.Distance(new Vector3(0, p2.y, 0), new Vector3(0, rsp.Point.y, 0)));
                });

                //ok so this is just checking if there are enough corners in the Receptacle Zone to consider it placed correctly.
                //originally this looped up to i < HowManyCornersToCheck, but if we just check all the corners, regardless of
                //sort order, it seems to bypass the issue above of how to sort the corners to find the "bottom" 4 corners, so uh
                // i guess this might just work without fancy sorting to determine the bottom 4 corners... especially since the "bottom corners" starts to lose meaning as objects are rotated
                for (int i = 0; i < 8; i++)
                {
                    if (rsp.Script.CheckIfPointIsInsideReceptacleTriggerBox(SpawnCorners[i]))
                    {
                        CornerCount++;
                    }
                }

                //if not enough corners are inside the receptacle, abort
                if (CornerCount < HowManyCornersToCheck)
                {
                    sop.transform.rotation = originalRot;
                    sop.transform.position = originalPos;
                    return(false);
                }

                //one final check, make sure all corners of object are "above" the receptacle box in question, so we
                //dont spawn stuff half on a table and it falls over
                foreach (Vector3 v in SpawnCorners)
                {
                    if (!rsp.Script.CheckIfPointIsAboveReceptacleTriggerBox(v))
                    {
                        sop.transform.rotation = originalRot;
                        sop.transform.position = originalPos;
                        return(false);
                    }
                }

                //set true if we want objects to be stationary when placed. (if placed on uneven surface, object remains stationary)
                //if false, once placed the object will resolve with physics (if placed on uneven surface object might slide or roll)
                if (PlaceStationary == true)
                {
                    //make object being placed kinematic true
                    sop.GetComponent <Rigidbody>().collisionDetectionMode = CollisionDetectionMode.Discrete;
                    sop.GetComponent <Rigidbody>().isKinematic            = true;

                    //check if the parent sim object is one that moves like a drawer - and would require this to be parented
                    //if(rsp.ParentSimObjPhys.DoesThisObjectHaveThisSecondaryProperty(SimObjSecondaryProperty.CanOpen))
                    sop.transform.SetParent(rsp.ParentSimObjPhys.transform);

                    //if this object is a receptacle and it has other objects inside it, drop them all together
                    if (sop.DoesThisObjectHaveThisSecondaryProperty(SimObjSecondaryProperty.Receptacle))
                    {
                        PhysicsRemoteFPSAgentController agent = GameObject.Find("FPSController").GetComponent <PhysicsRemoteFPSAgentController>();
                        agent.DropContainedObjectsStationary(sop);//use stationary version so that colliders are turned back on, but kinematics remain true
                    }

                    //if the target receptacle is a pickupable receptacle, set it to kinematic true as will sence we are placing stationary
                    if (rsp.ParentSimObjPhys.PrimaryProperty == SimObjPrimaryProperty.CanPickup)
                    {
                        rsp.ParentSimObjPhys.GetComponent <Rigidbody>().isKinematic = true;
                    }
                }

                //place stationary false, let physics drop everything too
                else
                {
                    //if not placing stationary, put all objects under Objects game object
                    GameObject topObject = GameObject.Find("Objects");
                    //parent to the Objects transform
                    sop.transform.SetParent(topObject.transform);

                    Rigidbody rb = sop.GetComponent <Rigidbody>();
                    rb.isKinematic            = false;
                    rb.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
                    //if this object is a receptacle and it has other objects inside it, drop them all together
                    if (sop.DoesThisObjectHaveThisSecondaryProperty(SimObjSecondaryProperty.Receptacle))
                    {
                        PhysicsRemoteFPSAgentController agent = GameObject.Find("FPSController").GetComponent <PhysicsRemoteFPSAgentController>();
                        agent.DropContainedObjects(sop);
                    }
                }
                sop.isInAgentHand = false;//set agent hand flag

                // #if UNITY_EDITOR
                // Debug.Log(sop.name + " succesfully spawned in " +rsp.ParentSimObjPhys.name + " at coordinate " + rsp.Point);
                // #endif

                return(true);
            }
        }

        //reset rotation if no valid spawns found
        //oh now we couldn't spawn it, all the spawn areas were not clear
        sop.transform.rotation = originalRot;
        sop.transform.position = originalPos;
        return(false);
    }
Exemplo n.º 2
0
    // TODO: constructLayouts actually tries the layouts and updates dictionary with whether layout successful or not
    public IEnumerator constructLayouts(List <ReceptacleSpawnPoint> receptacleSpawnPoints, InstantiatePrefabTest spawner,
                                        GameObject anchor, GameObject target, bool PlaceStationary, int maxcount, int degreeIncrement, bool AlwaysPlaceUpright)
    {
        bool       anchorSpawned;
        bool       targetSpawned;
        Quaternion rotation;

        // radius of anchor
        Vector3 anchorSize = anchor.GetComponent <SimObjPhysics>().BoundingBox.GetComponent <BoxCollider>().size;
        float   r_a        = anchorSize[0] / 2; // radius_anchor

        // height of anchor
        float h_a = anchorSize[1];         // height_anchor

        // radius of target
        Vector3 targetSize = target.GetComponent <SimObjPhysics>().BoundingBox.GetComponent <BoxCollider>().size;
        float   r_t        = targetSize[0] / 2; // radius_target

        // construct list of distances
        List <float> distances = new List <float> {
            0, r_a + r_t, r_a + 2 * r_t, r_a + 4 * r_t, r_a + 8 * r_t
        };

        // construct list of heights
        List <float> heights = new List <float> {
            0, h_a, 2 * h_a
        };

        // construct list of angles
        List <int> angles = new List <int> {
            0, 45, 90, 135, 180, 225, 270, 315
        };

        List <ReceptacleSpawnPoint> pointList       = new List <ReceptacleSpawnPoint>(1);
        List <ReceptacleSpawnPoint> targetPointList = new List <ReceptacleSpawnPoint>(1);
        ReceptacleSpawnPoint        firstRSP        = receptacleSpawnPoints[0];

        pointList.Add(firstRSP);
        targetPointList.Add(new ReceptacleSpawnPoint(Vector3.zero, firstRSP.ReceptacleBox, firstRSP.Script, firstRSP.ParentSimObjPhys));
        foreach (ReceptacleSpawnPoint point in receptacleSpawnPoints)
        {
            pointList[0]  = point;
            anchorSpawned = spawner.PlaceObjectReceptacle(pointList, anchor.GetComponent <SimObjPhysics>(),
                                                          PlaceStationary, maxcount, degreeIncrement, AlwaysPlaceUpright, true);
            // if spawn successful, try placing target
            if (anchorSpawned)
            {
                foreach (int angle in angles)
                {
                    foreach (float distance in distances)
                    {
                        // ignoring height for now
                        rotation = Quaternion.AngleAxis(angle, Vector3.up);
                        targetPointList[0].Point = point.Point + rotation * Vector3.left * distance;
                        targetSpawned            = spawner.PlaceObjectReceptacle(targetPointList, target.GetComponent <SimObjPhysics>(),
                                                                                 PlaceStationary, maxcount, degreeIncrement, AlwaysPlaceUpright, true);
                        if (!targetSpawned)
                        {
                            break;
                        }
                        yield return(null); // put this after break, so frames where target doesn't spawn aren't rendered
                    }
                }
            }
//            if (!anchorSpawned) {
//                #if UNITY_EDITOR
//                Debug.Log(anchor.name + " could not be spawned.");
//                #endif
//            }
        }
    }