private static IEnumerable <Vector3> GetSide(bool hasSide, System.Func <JigsawPiece, int, IEnumerable <Vector2> > evaluation, JigsawPiece currentPiece, int edgeSmoothness, float halfDepth, Vector3[] fallback) { IEnumerable <Vector3> sideVertices; if (hasSide) { var twoDee = evaluation(currentPiece, edgeSmoothness); sideVertices = twoDee.Select(point => point.ToXZVector3(halfDepth)).Concat(twoDee.Select(point => point.ToXZVector3(-halfDepth))); } else { sideVertices = fallback; } return(sideVertices); }
public static IEnumerator Generate(int columns, int rows, float puzzleWidth, float puzzleHeight, float puzzleDepth, int edgeSmoothness = 5, float seed = 1337, Transform parent = null, GameObject[] piecesOutput = null, Material _faceMaterial = null, Material _sideMaterial = null, Material _bottomMaterial = null, bool addBoxCollider = false, System.Action <float> puzzleLoadingPercent = null, System.Action onPuzzleCompleted = null) { float pieceWidth = puzzleWidth / columns; float pieceHeight = puzzleHeight / rows; float halfWidth = pieceWidth / 2; float halfHeight = pieceHeight / 2; float halfDepth = puzzleDepth / 2; Vector3 topBackLeftCorner = new Vector3(-halfWidth, halfDepth, -halfHeight); Vector3 topBackRightCorner = new Vector3(halfWidth, halfDepth, -halfHeight); Vector3 topFrontRightCorner = new Vector3(halfWidth, halfDepth, halfHeight); Vector3 topFrontLeftCorner = new Vector3(-halfWidth, halfDepth, halfHeight); Vector3 bottomFrontLeftCorner = new Vector3(-halfWidth, -halfDepth, halfHeight); Vector3 bottomFrontRightCorner = new Vector3(halfWidth, -halfDepth, halfHeight); Vector3 bottomBackRightCorner = new Vector3(halfWidth, -halfDepth, -halfHeight); Vector3 bottomBackLeftCorner = new Vector3(-halfWidth, -halfDepth, -halfHeight); var backFlat = new Vector3[] { topBackRightCorner, topBackLeftCorner, bottomBackRightCorner, bottomBackLeftCorner }; var frontFlat = new Vector3[] { topFrontLeftCorner, topFrontRightCorner, bottomFrontLeftCorner, bottomFrontRightCorner }; var rightFlat = new Vector3[] { topFrontRightCorner, topBackRightCorner, bottomFrontRightCorner, bottomBackRightCorner }; var leftFlat = new Vector3[] { topBackLeftCorner, topFrontLeftCorner, bottomBackLeftCorner, bottomFrontLeftCorner }; var firstMaterial = _faceMaterial; var secondMaterial = _bottomMaterial; var thirdMaterial = _sideMaterial; if (firstMaterial == null) { firstMaterial = new Material(Shader.Find("Standard")); firstMaterial.color = Color.green; } if (secondMaterial == null) { secondMaterial = new Material(Shader.Find("Standard")); secondMaterial.color = Color.red; } if (thirdMaterial == null) { thirdMaterial = new Material(Shader.Find("Standard")); thirdMaterial.color = Color.yellow; } int totalPiecesCount = columns * rows; JigsawPiece[,] piecesMap = new JigsawPiece[columns, rows]; GameObject[] pieces = null; if (piecesOutput != null) { if (piecesOutput.Length == totalPiecesCount) { pieces = piecesOutput; } else { Debug.LogError("Given pieces array is not large enough to store all the jigsaw pieces, must be of length equal to " + columns + " * " + rows); } } Dictionary <int, Vector2[]> simpleUVs = new Dictionary <int, Vector2[]>(); Dictionary <int, List <int> > simpleTriangulations = new Dictionary <int, List <int> >(); for (int row = 0; row < rows; row++) { for (int col = 0; col < columns; col++) { float xOffset = (puzzleWidth / 2 - halfWidth); float zOffset = (puzzleHeight / 2 - halfHeight); float xPos = col * pieceWidth - xOffset; float zPos = row * pieceHeight - zOffset; JigsawPiece currentPiece = JigsawPiece.GenerateRandom(pieceWidth, pieceHeight, seed, xPos, zPos); if (col > 0) { currentPiece.left = piecesMap[col - 1, row].right.CreateSpouse(pieceWidth); } if (row > 0) { currentPiece.bottom = piecesMap[col, row - 1].top.CreateSpouse(pieceHeight); } piecesMap[col, row] = currentPiece; int pieceIndex = row * columns + col; GameObject pieceObject = new GameObject("Piece#" + pieceIndex); pieceObject.transform.localPosition = new Vector3(xPos, halfDepth, zPos); var meshPart = pieceObject.AddComponent <MeshPart>(); if (parent != null) { pieceObject.transform.SetParent(parent); } if (pieces != null) { pieces[pieceIndex] = pieceObject; } if (addBoxCollider) { var boxCollider = pieceObject.AddComponent <BoxCollider>(); boxCollider.size = new Vector3(pieceWidth, puzzleDepth, pieceHeight); } bool hasTop = row < rows - 1; bool hasRight = col < columns - 1; bool hasBottom = row > 0; bool hasLeft = col > 0; var twoDeePoints = currentPiece.EvaluateAll(pieceWidth, pieceHeight, edgeSmoothness, hasTop, hasRight, hasBottom, hasLeft); IEnumerable <int> indices; IEnumerable <Vector2> triangulatedVertices; twoDeePoints.TriangulateConcavePolygon(out indices, out triangulatedVertices); var faceUV = triangulatedVertices.Select(point => (point + new Vector2(xPos + (puzzleWidth / 2), zPos + (puzzleHeight / 2))).Multiply(new Vector2(1 / puzzleWidth, 1 / puzzleHeight))); //Top side meshPart.AddVertices(triangulatedVertices.Select((point) => point.ToXZVector3(halfDepth)), indices, faceUV); //Bottom side meshPart.AddVertices(triangulatedVertices.Select((point) => point.ToXZVector3(-halfDepth)), indices.Reverse(), faceUV, 1); IEnumerable <Vector3> sideVertices; List <int> sideTriangles; Vector2[] sideUVs; //Back side sideVertices = GetSide(hasBottom, (piece, smoothness) => piece.EvaluateBottom(smoothness), currentPiece, edgeSmoothness, halfDepth, backFlat); sideUVs = GetSimpleUVNation(simpleUVs, sideVertices.Count()); sideTriangles = GetSimpleTriangulation(simpleTriangulations, sideUVs.Length / 2); meshPart.AddVertices(sideVertices, sideTriangles, sideUVs, 2); //Front side sideVertices = GetSide(hasTop, (piece, smoothness) => piece.EvaluateTop(smoothness), currentPiece, edgeSmoothness, halfDepth, frontFlat); sideUVs = GetSimpleUVNation(simpleUVs, sideVertices.Count()); sideTriangles = GetSimpleTriangulation(simpleTriangulations, sideUVs.Length / 2); meshPart.AddVertices(sideVertices, sideTriangles, sideUVs, 2); //Right side sideVertices = GetSide(hasRight, (piece, smoothness) => piece.EvaluateRight(smoothness), currentPiece, edgeSmoothness, halfDepth, rightFlat); sideUVs = GetSimpleUVNation(simpleUVs, sideVertices.Count()); sideTriangles = GetSimpleTriangulation(simpleTriangulations, sideUVs.Length / 2); meshPart.AddVertices(sideVertices, sideTriangles, sideUVs, 2); //Left side sideVertices = GetSide(hasLeft, (piece, smoothness) => piece.EvaluateLeft(smoothness), currentPiece, edgeSmoothness, halfDepth, leftFlat); sideUVs = GetSimpleUVNation(simpleUVs, sideVertices.Count()); sideTriangles = GetSimpleTriangulation(simpleTriangulations, sideUVs.Length / 2); meshPart.AddVertices(sideVertices, sideTriangles, sideUVs, 2); Dictionary <int, Material> matsDick = new Dictionary <int, Material>(); matsDick[0] = firstMaterial; matsDick[1] = secondMaterial; matsDick[2] = thirdMaterial; meshPart.SetMaterials(matsDick); puzzleLoadingPercent?.Invoke((pieceIndex + 1) / (float)totalPiecesCount); yield return(null); } } onPuzzleCompleted?.Invoke(); }
//Good Ranges dip[0.08, 0.5] girth[0.06, 0.3] growth[0.5, 1] length[0.3, 0.6] dipP[0.2, 1] growthP[0.88, 1] public static JigsawPiece GenerateRandom(float pieceWidth, float pieceHeight, float seed = 1337, float posX = 0, float posY = 0, float dipRangeStart = 0.08f, float dipRangeEnd = 0.5f, float girthRangeStart = 0.06f, float girthRangeEnd = 0.3f, float growthRangeStart = 0.5f, float growthRangeEnd = 1, float lenghRangeStart = 0.3f, float lengthRangeEnd = 0.6f, float dipPRangeStart = 0.2f, float dipPRangeEnd = 1, float growthPRangeStart = 0.88f, float growthPRangeEnd = 1 ) { JigsawPiece randomizedBizaz = new JigsawPiece(); var pieceNoise = Mathf.PerlinNoise(posX + pieceWidth * seed * 1879, posY + pieceHeight * seed * 1033); var bizProtrude = Mathf.RoundToInt(pieceNoise * 10) % 2 == 0; var bizDip = (dipRangeEnd - dipRangeStart) * pieceNoise + dipRangeStart; var bizGirth = (girthRangeEnd - girthRangeStart) * pieceNoise + girthRangeStart; var bizGrowth = (growthPRangeEnd - growthRangeStart) * pieceNoise + growthRangeStart; var bizLength = (lengthRangeEnd - lenghRangeStart) * pieceNoise + lenghRangeStart; var bizDipP = (dipPRangeEnd - dipPRangeStart) * pieceNoise + dipPRangeStart; var bizGrowthP = (growthPRangeEnd - growthPRangeStart) * pieceNoise + growthPRangeStart; randomizedBizaz.left = JigsawSide.CreateGenitalia ( pieceHeight, pieceWidth, bizProtrude, bizDip, bizGirth, bizGrowth, bizLength, bizDipP, bizGrowthP ); pieceNoise = Mathf.PerlinNoise(posX + pieceWidth * seed * 1607, posY + pieceHeight * seed * 1571); bizProtrude = Mathf.RoundToInt(pieceNoise * 10) % 2 == 0; bizDip = (dipRangeEnd - dipRangeStart) * pieceNoise + dipRangeStart; bizGirth = (girthRangeEnd - girthRangeStart) * pieceNoise + girthRangeStart; bizGrowth = (growthPRangeEnd - growthRangeStart) * pieceNoise + growthRangeStart; bizLength = (lengthRangeEnd - lenghRangeStart) * pieceNoise + lenghRangeStart; bizDipP = (dipPRangeEnd - dipPRangeStart) * pieceNoise + dipPRangeStart; bizGrowthP = (growthPRangeEnd - growthPRangeStart) * pieceNoise + growthPRangeStart; randomizedBizaz.right = JigsawSide.CreateGenitalia ( pieceHeight, pieceWidth, bizProtrude, bizDip, bizGirth, bizGrowth, bizLength, bizDipP, bizGrowthP ); pieceNoise = Mathf.PerlinNoise(posX + pieceWidth * seed * 2113, posY + pieceHeight * seed * 461); bizProtrude = Mathf.RoundToInt(pieceNoise * 10) % 2 == 0; bizDip = (dipRangeEnd - dipRangeStart) * pieceNoise + dipRangeStart; bizGirth = (girthRangeEnd - girthRangeStart) * pieceNoise + girthRangeStart; bizGrowth = (growthPRangeEnd - growthRangeStart) * pieceNoise + growthRangeStart; bizLength = (lengthRangeEnd - lenghRangeStart) * pieceNoise + lenghRangeStart; bizDipP = (dipPRangeEnd - dipPRangeStart) * pieceNoise + dipPRangeStart; bizGrowthP = (growthPRangeEnd - growthPRangeStart) * pieceNoise + growthPRangeStart; randomizedBizaz.top = JigsawSide.CreateGenitalia ( pieceWidth, pieceHeight, bizProtrude, bizDip, bizGirth, bizGrowth, bizLength, bizDipP, bizGrowthP ); pieceNoise = Mathf.PerlinNoise(posX + pieceWidth * seed * 569, posY + pieceHeight * seed * 3209); bizProtrude = Mathf.RoundToInt(pieceNoise * 10) % 2 == 0; bizDip = (dipRangeEnd - dipRangeStart) * pieceNoise + dipRangeStart; bizGirth = (girthRangeEnd - girthRangeStart) * pieceNoise + girthRangeStart; bizGrowth = (growthPRangeEnd - growthRangeStart) * pieceNoise + growthRangeStart; bizLength = (lengthRangeEnd - lenghRangeStart) * pieceNoise + lenghRangeStart; bizDipP = (dipPRangeEnd - dipPRangeStart) * pieceNoise + dipPRangeStart; bizGrowthP = (growthPRangeEnd - growthPRangeStart) * pieceNoise + growthPRangeStart; randomizedBizaz.bottom = JigsawSide.CreateGenitalia ( pieceWidth, pieceHeight, bizProtrude, bizDip, bizGirth, bizGrowth, bizLength, bizDipP, bizGrowthP ); return(randomizedBizaz); }