示例#1
0
    /// <summary>
    /// Attempts to satisfy one connector in the current phase or advance to the next phase
    /// Returns true if generation is still in progress, false if it is complete or has failed
    /// </summary>
    public bool StepGeneration()
    {
        if (Generating)
        {
            var oldRandomState = Random.state;
            Random.state = randomState;

            if (currentPhaseStatus.RemainingPartCount > 0 && currentPhaseStatus.OpenOutbound.Count > 0)
            {
                //DungeonConnector outboundConnector = currentPhaseStatus.OpenOutbound.RandomElement();
                DungeonConnector outboundConnector = currentPhaseStatus.OpenOutbound[0];

                // Try to place each potentially connectable part (in random order)
                currentPhaseStatus.PartPool.Shuffle();

                foreach (var candPart in currentPhaseStatus.PartPool)
                {
                    if (candPart.HasInboundConnector(outboundConnector.ConnectionTag) && candPart.CanCombineWith(outboundConnector.ParentPart))
                    {
                        if (TryPlacePart(candPart, outboundConnector))
                        {
                            currentPhaseStatus.RemainingPartCount--;
                            break;
                        }
                    }
                }

                // Store failed connectors to be attempted in later phases
                if (currentPhaseStatus.OpenOutbound.Remove(outboundConnector))
                {
                    currentPhaseStatus.FailedOutbound.Add(outboundConnector);
                }
            }
            else
            {
                //var placedPhaseParts = currentPhaseStatus.Config.PartLimit - currentPhaseStatus.RemainingPartCount;
                //Debug.Log($"Phase '{currentPhaseStatus.Config.PhaseName}' complete: {placedPhaseParts} parts placed, " +
                //    $"{currentPhaseStatus.FailedOutbound.Count + currentPhaseStatus.OpenOutbound.Count} open connectors");

                Generating = AdvanceGenerationPhase();
            }

            randomState  = Random.state;
            Random.state = oldRandomState;

            if (!Generating)
            {
                if (OnGenerationComplete != null)
                {
                    OnGenerationComplete.Invoke();
                }

                CurrentDungeonBounds.Expand(BoundsPadding);
            }
        }

        return(Generating);
    }
示例#2
0
 public bool CanConnectTo(DungeonConnector other)
 {
     return(other != this &&
            (ConnectionTag == other.ConnectionTag) &&
            ((AllowOutbound && other.AllowInbound) || (AllowInbound && other.AllowOutbound)));
 }
示例#3
0
 public List <DungeonConnector> InboundConnectorsFor(DungeonConnector outboundConnector)
 {
     return(connectors.Where(c => c.AllowInbound && c.CanConnectTo(outboundConnector)).ToList());
 }
示例#4
0
    /// <summary>
    /// Attempts to attach the specified part to the specified outbound connector, performing bounds
    /// checks as appropriate. Will attempt placement with all valid matching inbound connectors
    /// Returns true if the part was placed successfully, false if not
    /// </summary>
    private bool TryPlacePart(DungeonPart partPrefab, DungeonConnector outboundConnector)
    {
        Quaternion targetOrientation  = new Quaternion();
        Vector3    targetPosition     = Vector3.zero;
        int?       inboundConnectorId = null;

        var prefabICs = partPrefab.InboundConnectorsFor(outboundConnector);

        prefabICs.Shuffle();

        foreach (var prefabIC in prefabICs)
        {
            // calculate prospective orientation and position for part instance
            targetOrientation = Quaternion.AngleAxis(180, outboundConnector.transform.up) * outboundConnector.transform.rotation * Quaternion.Inverse(prefabIC.transform.localRotation);
            targetPosition    = outboundConnector.transform.position - targetOrientation * prefabIC.transform.localPosition;

            bool canPlace = partPrefab.SkipBoundsCheck || partPrefab.BoundsCheck(outboundConnector.transform, prefabIC.ConnectorId);

            if (canPlace)
            {
                inboundConnectorId = prefabIC.ConnectorId;
                break;
            }
            else
            {
                //Debug.Log($"Bounds check failed! Can't connect {outboundConnector.gameObject.name} (outbound) to {partPrefab.PartName} {prefabIC.gameObject.name} (inbound)");
            }
        }

        if (!inboundConnectorId.HasValue)
        {
            return(false);
        }

        var partInstance = Instantiate(partPrefab.gameObject, transform).GetComponent <DungeonPart>();

        currentDungeonPartInstances.Add(partInstance);

        var inboundConnector = partInstance.GetConnector(inboundConnectorId.Value);

        // random rotation added separately from bounds check so that bounds check is deterministic
        if (inboundConnector.RandomRotation || outboundConnector.RandomRotation)
        {
            float rotateDegrees = Random.Range(0, 360);
            targetOrientation = Quaternion.AngleAxis(180, outboundConnector.transform.up)
                                * Quaternion.AngleAxis(rotateDegrees, outboundConnector.transform.forward)
                                * outboundConnector.transform.rotation
                                * Quaternion.Inverse(inboundConnector.transform.localRotation);
            targetPosition = outboundConnector.transform.position - targetOrientation * inboundConnector.transform.localPosition;
        }

        partInstance.transform.localRotation = targetOrientation;
        partInstance.transform.position      = targetPosition;

        //Debug.Log($"Connected {outboundConnector.gameObject.name} (outbound) to {partPrefab.PartName} {inboundConnector.gameObject.name} (inbound)");

        var nextOutboundConnectors = partInstance.OutboundConnectors();

        nextOutboundConnectors.Remove(inboundConnector);
        currentPhaseStatus.OpenOutbound.Remove(outboundConnector);

        // check whether this part makes additional connections to other open connectors
        for (var i = nextOutboundConnectors.Count - 1; i > 0; i--)
        {
            var connA = nextOutboundConnectors[i];
            for (var j = currentPhaseStatus.OpenOutbound.Count - 1; j > 0; j--)
            {
                var connB = currentPhaseStatus.OpenOutbound[j];
                if (connA.CanConnectTo(connB))
                {
                    if ((connA.transform.position - connB.transform.position).sqrMagnitude < 0.01f)
                    {
                        nextOutboundConnectors.RemoveAt(i);
                        currentPhaseStatus.OpenOutbound.RemoveAt(j);
                        //Debug.Log($"Detected additional connection at {connA.transform.position} between {connA.gameObject.name} and {connB.gameObject.name}, closing both.");
                    }
                }
            }
        }

        currentPhaseStatus.OpenOutbound.AddRange(nextOutboundConnectors);

        return(true);
    }