/// <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;
/// <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;
/// <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); }