Exemplo n.º 1
0
 /// <summary>
 /// Is the use of colours specified in this ruleset?
 /// </summary>
 /// <param name="rules">The ruleset to check for color usage.</param>
 /// <returns>True if this ruleset uses colors, false otherwise.</returns>
 public static bool UseColours(this SnapRules rules)
 => (rules & SnapRules.Colours) == SnapRules.Colours;
Exemplo n.º 2
0
 /// <summary>
 /// Is the use of pins specified in this ruleset?
 /// </summary>
 /// <param name="rules">The ruleset to check for pin usage.</param>
 /// <returns>True if this ruleset uses pins, false otherwise.</returns>
 public static bool UsePins(this SnapRules rules)
 => (rules & SnapRules.Pins) == SnapRules.Pins;
Exemplo n.º 3
0
        /// <summary>
        /// Try and snap a piece with the current piece.
        /// </summary>
        /// <param name="rules">Current matching rules.</param>
        /// <param name="other">
        /// The piece to check for possible connection with.
        /// </param>
        /// <param name="checkOverlaps">Check for overlaps?</param>
        /// <param name="collidersLayer">
        /// Overlap layer to use if <paramref name="checkOverlaps"/> is
        /// true.
        /// </param>
        /// <param name="pieceDistance">
        /// Distance between two connected connectors.
        /// </param>
        /// <param name="pinTolerance">
        /// Maximum allowed difference between pin counts in two connectors to
        /// allow them to be paired up.
        /// </param>
        /// <param name="colorMatrix">
        /// Valid color combinations for matching connectors.
        /// </param>
        /// <returns>True if snap was successful, false otherwise.</returns>
        public bool TrySnapWith(
            SnapRules rules, MapPiece other,
            bool checkOverlaps, LayerMask collidersLayer,
            float pieceDistance = 0.00f, uint pinTolerance = 0,
            bool[,] colorMatrix = null)
        {
            // List of valid connector combinations
            List <(Connector curr, Connector other)> validCombos =
                new List <(Connector curr, Connector other)>();

            // Create a list of valid connections between this piece and the
            // other piece
            foreach (Connector co in other._Connectors)
            {
                foreach (Connector cc in _Connectors)
                {
                    // Only check for matching if both connectors are unused
                    if (!co.IsUsed && !cc.IsUsed)
                    {
                        // By default we assume there's a pin match and a color
                        // match
                        bool pinMatch   = true;
                        bool colorMatch = true;

                        // If we're using pins count as criteria, check pins
                        if (rules.UsePins())
                        {
                            // Pin match is verified if the pin difference
                            // between connectors is below the pin tolerance
                            pinMatch = Mathf.Abs(co.Pins - cc.Pins) <= pinTolerance;
                        }

                        // If we're using colour as criteria, check colour matrix
                        if (rules.UseColours())
                        {
                            // Get the validity of the connectors color
                            // combination from the color matrix
                            colorMatch =
                                colorMatrix?[(int)cc.ConnColor, (int)co.ConnColor]
                                ?? true;
                        }

                        // If we have a match, then this is a valid connection
                        if (pinMatch && colorMatch)
                        {
                            validCombos.Add((cc, co));
                        }
                    }
                }
            }

            // If there are valid connections, try to enable one of them
            // This might fail if we're checking for overlaps
            while (validCombos.Count > 0)
            {
                // Get a random connection from the valid connections list
                int chosenIndex = UnityEngine.Random.Range(0, validCombos.Count);

                // Get connectors from the randomly selected connection
                (Connector curr, Connector other)chosenCombo =
                    validCombos[chosenIndex];

                // Get current PRS components from the other piece, since it
                // may be necessary to undo the transformation if we're checking
                // for overlaps
                Vector3    prevPos   = other.transform.position;
                Quaternion prevRot   = other.transform.rotation;
                Vector3    prevScale = other.transform.localScale;

                // Set the correct position and rotation of the other piece so
                // its connector matches this piece's connector
                SetOtherPiecePosRot(
                    chosenCombo.curr, chosenCombo.other, other, pieceDistance);

                // Apply Transform changes to the physics engine
                Physics.SyncTransforms();

                // If checking for overlaps, verify if there are any with the
                // existing geometry, using this transform
                if (checkOverlaps)
                {
                    // Assume there are no overlaps
                    bool overlaps = false;

                    // Get box colliders in layer and loop through them
                    foreach (BoxCollider boxCollider in GetBoxColliders(other, collidersLayer))
                    {
                        // Get the center and extents of the current box collider
                        Vector3 center  = boxCollider.transform.rotation * boxCollider.center + boxCollider.transform.position;
                        Vector3 extents = new Vector3(0.5f * boxCollider.size.x * boxCollider.transform.lossyScale.x,
                                                      0.5f * boxCollider.size.y * boxCollider.transform.lossyScale.y,
                                                      0.5f * boxCollider.size.z * boxCollider.transform.lossyScale.z);

                        // Get colliders that overlap with the current box
                        Collider[] hits = Physics.OverlapBox(
                            center, extents, boxCollider.transform.rotation, collidersLayer);

                        // Loop through the colliders that overlap with the
                        // current box
                        foreach (Collider hit in hits)
                        {
                            // Check for self overlap, or overlaps with the connected piece
                            // Ignore the collision in those cases
                            MapPiece parentMapPiece = hit.GetComponentInParent <MapPiece>();
                            if ((parentMapPiece == other) || (parentMapPiece == this))
                            {
                                continue;
                            }

#if DEBUG_OVERLAPS
                            Debug.Log($"Can't connect {name} with {other.name}");
                            Debug.Log($"Connector {chosenCombo.chosenMine.name} / {chosenCombo.chosenOther.name}");
                            Debug.Log($"Overlap detected with {parentMapPiece.name}");

                            // Create a copy for later debug
                            MapPiece newObject = Instantiate(other);
                            newObject.name = $"OverlapError {interError++}";
                            newObject.transform.position += Vector3.up * 20;
                            newObject.transform.SetParent(null);
                            newObject.gameObject.SetActive(false);
                            Debug.Log($"New object = {newObject.name}");
#endif

                            // It auto-overlaps, so remove this possibility and retry
                            validCombos.Remove(chosenCombo);

                            overlaps = true;
                            break; // hit found, not need to check more hits
                        } // for each hit/collision

                        if (overlaps)
                        {
                            break;           // hit found, not need to check more box colliders
                        }
                    } // for each box collider

                    if (overlaps)
                    {
                        // Undo transform, so we can do it again...
                        other.transform.position   = prevPos;
                        other.transform.rotation   = prevRot;
                        other.transform.localScale = prevScale;
                        continue; // to next valid combo, if any
                    }
                } // if (checkOverlaps)

                // If we get here, then the connector match is definitively
                // validated, and we can carry on with it
                chosenCombo.curr.SnapWith(chosenCombo.other);

                // Return true, indicating that a match was found and piece
                // snapping was successful
                return(true);
            } // while (validCombos.Count > 0)

            // Return false, indicating the piece snapping was not successful
            return(false);
        }