public void Populate(List <Ship> ships) { List <ShipRectangleGroup> unfinishedGroups = new List <ShipRectangleGroup>(); List <Ship> toAdd = new List <Ship>(); ShipRectangleGroup currentGroup = new ShipRectangleGroup(); foreach (Ship ship in ships) { ship.transform.SetParent(transform); if (toAdd.Count == 0) { toAdd.Add(ship); continue; } if (toAdd[0].GetType() == ship.GetType() && forceIdenticalShipTypesToGroupTogether) { toAdd.Add(ship); } else { currentGroup.ships = toAdd.ToArray(); toAdd = new List <Ship>(); toAdd.Add(ship); unfinishedGroups.Add(currentGroup); currentGroup = new ShipRectangleGroup(); } } currentGroup.ships = toAdd.ToArray(); unfinishedGroups.Add(currentGroup); groups = unfinishedGroups.ToArray(); for (int i = 0; i < groups.Length; i++) { groups[i].rect.height = groups[i].ships[0].maxHealth + shipGroupPadding; groups[i].rect.width = (groups[i].ships[0].transform.localScale.x + 0.5f) * groups[i].ships.Length + shipGroupPadding; groups[i].horizontalCorners = CalculateCorners(groups[i].rect, false); groups[i].verticalCorners = CalculateCorners(groups[i].rect, true); } ArrangeShipGroupsOnSquarePlane(); MoldPlate(); }
void ArrangeShipGroupsOnSquarePlane() { Vector2 footprint = Vector2.zero; List <int> addedGroupIDs = new List <int>(); List <AttachmentPoint> attachmentPoints = new List <AttachmentPoint>(); attachmentPoints.Add(new AttachmentPoint(Vector2.zero, new Vector2[] { Vector2.one *Mathf.Infinity, Vector2.one *Mathf.Infinity, Vector2.one *Mathf.Infinity, Vector2.one *Mathf.Infinity })); NextStepCandidate bestCandidate = new NextStepCandidate(0, Vector2.zero, false, Vector2.one, Mathf.Infinity); for (int i = 0; i < groups.Length; i++) { //DETERMINE BEST CANDIDATE STEP for (int candidateGroupID = 0; candidateGroupID < groups.Length; candidateGroupID++) { if (!addedGroupIDs.Contains(candidateGroupID)) { for (int verticalIndex = 0; verticalIndex < 2; verticalIndex++) { //CALCULATE CORNER POSITIONS Vector2[] groupCorners = verticalIndex == 1 ? groups[candidateGroupID].verticalCorners : groups[candidateGroupID].horizontalCorners; //CALCULATE FOOTPRINT Vector2 size = groupCorners[2] - groupCorners[1]; //TRY ALL POSITIONING OPTIONS foreach (AttachmentPoint attachmentPoint in attachmentPoints) { for (int examinedCorner = 0; examinedCorner < 4; examinedCorner++) { Vector2 sizeLimitation = attachmentPoint.quadrantSizeLimits[examinedCorner]; if (size.x <= sizeLimitation.x && size.y <= sizeLimitation.y) { NextStepCandidate newCandidate; newCandidate.groupID = candidateGroupID; newCandidate.position = attachmentPoint.position - groupCorners[examinedCorner]; newCandidate.vertical = verticalIndex == 1; Vector4 boundaries = Vector4.zero; for (int newCandidateCornerID = 0; newCandidateCornerID < groupCorners.Length; newCandidateCornerID++) { boundaries = PushBoundaries(boundaries, newCandidate.position + groupCorners[newCandidateCornerID]); } foreach (int addedGroupID in addedGroupIDs) { Vector2[] addedGroupCorners = groups[addedGroupID].Corners; for (int cornerID = 0; cornerID < 4; cornerID++) { boundaries = PushBoundaries(boundaries, groups[addedGroupID].rect.position + addedGroupCorners[cornerID]); } } newCandidate.wholeFootprint = new Vector2(Mathf.Abs(boundaries.x - boundaries.z), Mathf.Abs(boundaries.y - boundaries.w)); newCandidate.balance = newCandidate.wholeFootprint.x / newCandidate.wholeFootprint.y; if (newCandidate.wholeFootprint.x < 0.9f * plateSize && newCandidate.wholeFootprint.y < 0.9f * plateSize) { if (Mathf.Abs(1 - newCandidate.balance) < Mathf.Abs(1 - bestCandidate.balance)) { bestCandidate = newCandidate; } } } } } } } } //APPLY BEST STEP addedGroupIDs.Add(bestCandidate.groupID); ShipRectangleGroup positionedGroup = groups[bestCandidate.groupID]; positionedGroup.rect.position = bestCandidate.position; positionedGroup.vertical = bestCandidate.vertical; groups[bestCandidate.groupID] = positionedGroup; footprint = bestCandidate.wholeFootprint; // Debug.Log("Cycle: " + i); // Debug.Log("Group ID: " + bestCandidate.groupID); // Debug.Log("Position: " + positionedGroup.rect.position); // Debug.Log("Vertical: " + positionedGroup.vertical); bestCandidate = new NextStepCandidate(0, Vector2.zero, false, Vector2.one, Mathf.Infinity); //RECALCULATE ATTACHMENT POINTS attachmentPoints = new List <AttachmentPoint>(); foreach (int groupID in addedGroupIDs) { ShipRectangleGroup managedGroup = groups[groupID]; for (int cornerIndex = 0; cornerIndex < 4; cornerIndex++) { AttachmentPoint potentialAttachmentPoint = new AttachmentPoint(Vector2.zero, new Vector2[4]); potentialAttachmentPoint.position = managedGroup.rect.position + managedGroup.Corners[cornerIndex]; Vector2[] calculatedQuadrants = new Vector2[4]; for (int quadrantID = 0; quadrantID < 4; quadrantID++) { Vector2 quadrantDirectional = new Vector2((quadrantID == 0 || quadrantID == 1) ? 1 : -1, (quadrantID == 1 || quadrantID == 3) ? 1 : -1); Vector2 size = Vector2.one * Mathf.Infinity; foreach (int potentialIntersectorIndex in addedGroupIDs) { ShipRectangleGroup potentialIntersector = groups[potentialIntersectorIndex]; for (int intersectorCornerIndex = 0; intersectorCornerIndex < 4; intersectorCornerIndex++) { Vector2 cornerGlobalPosition = potentialIntersector.rect.position + potentialIntersector.Corners[intersectorCornerIndex]; Vector2 cornerPositionRelativeToAttachmentPoint = cornerGlobalPosition - potentialAttachmentPoint.position; Vector2 cornerNormalizedQuadrantPosition = Vector2.Scale(cornerPositionRelativeToAttachmentPoint, quadrantDirectional); if (cornerNormalizedQuadrantPosition.x >= -0.000015f && cornerNormalizedQuadrantPosition.y >= -0.000015f && cornerNormalizedQuadrantPosition.x <= size.x && cornerNormalizedQuadrantPosition.y <= size.y) { Vector2 oppositeCornerNormalizedQuadrantPosition = Vector2.Scale(potentialIntersector.rect.position - potentialIntersector.Corners[intersectorCornerIndex] - potentialAttachmentPoint.position, quadrantDirectional); Vector2 sides = oppositeCornerNormalizedQuadrantPosition - cornerNormalizedQuadrantPosition; sides = sides - Vector2.Scale(new Vector2(Mathf.Clamp(-oppositeCornerNormalizedQuadrantPosition.x, 0, Mathf.Abs(sides.x)), Mathf.Clamp(-oppositeCornerNormalizedQuadrantPosition.y, 0, Mathf.Abs(sides.y))), new Vector2(Mathf.Sign(sides.x), Mathf.Sign(sides.y))); if (sides.y != 0 && sides.x != 0) { if (sides.x > 0) { size.x = cornerNormalizedQuadrantPosition.x < size.x ? cornerNormalizedQuadrantPosition.x : size.x; } else { size.y = cornerNormalizedQuadrantPosition.y < size.y ? cornerNormalizedQuadrantPosition.y : size.y; } } } } } //TEST // Debug.Log("Cycle: " + i); // Debug.Log("Group: " + groupID + " Corner: " + cornerIndex + " Quadrant: " + quadrantID); // Debug.Log("Size: " + size); //TEST // if (groupID == 3 && cornerIndex == 2 && quadrantID == 2) // { // Debug.Log("Conflicting Quadrant Size: " + size); // } calculatedQuadrants[quadrantID] = size; } potentialAttachmentPoint.quadrantSizeLimits = calculatedQuadrants; attachmentPoints.Add(potentialAttachmentPoint); } } } //NORMALIZE RECTANGLE POSITIONS Vector2 topRightCorner = Vector2.one * Mathf.NegativeInfinity; Vector2 bottomLeftCorner = Vector2.one * Mathf.Infinity; for (int i = 0; i < groups.Length; i++) { Vector2[] corners = groups[i].Corners; Vector2 groupTopRightCorner = corners[2] + groups[i].rect.position; Vector2 groupBottomLeftCorner = corners[1] + groups[i].rect.position; topRightCorner.x = groupTopRightCorner.x > topRightCorner.x ? groupTopRightCorner.x : topRightCorner.x; topRightCorner.y = groupTopRightCorner.y > topRightCorner.y ? groupTopRightCorner.y : topRightCorner.y; bottomLeftCorner.x = groupBottomLeftCorner.x < bottomLeftCorner.x ? groupBottomLeftCorner.x : bottomLeftCorner.x; bottomLeftCorner.y = groupBottomLeftCorner.y < bottomLeftCorner.y ? groupBottomLeftCorner.y : bottomLeftCorner.y; } Vector2 positionAdjustment = (bottomLeftCorner + topRightCorner) / 2.0f; for (int i = 0; i < groups.Length; i++) { groups[i].rect.position -= positionAdjustment; } //POSITION SHIPS ON RECTANGLE GROUPS for (int groupIndex = 0; groupIndex < groups.Length; groupIndex++) { ShipRectangleGroup group = groups[groupIndex]; float shipSpacing = group.rect.width / group.ships.Length * 0.8f; float reservedSpace = shipSpacing * (group.ships.Length - 1); Vector3 startingPosition = new Vector3(group.rect.x, 0, group.rect.y) + (group.vertical ? Vector3.forward : Vector3.right) * (reservedSpace / 2.0f); Vector3 positionStep = (group.vertical ? Vector3.back : Vector3.left) * shipSpacing; for (int shipIndex = 0; shipIndex < group.ships.Length; shipIndex++) { Ship ship = group.ships[shipIndex]; ship.transform.localPosition = startingPosition + positionStep * shipIndex; ship.transform.localRotation = new Quaternion(0, 1, 0, group.vertical ? 1 : 0); ship.placementInfo.localShipboxPosition = ship.transform.localPosition; ship.placementInfo.localShipboxRotation = ship.transform.localRotation; } // GameObject tmp = GameObject.CreatePrimitive(PrimitiveType.Cube); // tmp.transform.localScale = new Vector3(group.vertical ? group.rect.height : group.rect.width, 0.1f, group.vertical ? group.rect.width : group.rect.height); // tmp.transform.position = new Vector3(group.rect.x, 0, group.rect.y); } }