Example #1
0
        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();
        }
Example #2
0
        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);
            }
        }