コード例 #1
0
    /// <summary>
    /// Clears the current dungeon and Destroy all pieces. A new dungeon cannot be generated
    /// until after the next physics update clears colliders for these destroyed objects
    /// </summary>
    public void Clear()
    {
        CurrentDungeonBounds = new Bounds(transform.position, Vector3.zero);
        for (var i = 0; i < CurrentDungeonPartInstances.Count; i++)
        {
            Destroy(CurrentDungeonPartInstances[i].gameObject);
        }
        CurrentDungeonPartInstances.Clear();

        Generating         = false;
        currentPhaseStatus = null;
    }
コード例 #2
0
    /// <summary>
    /// Triggers generation of a new dungeon. If synchronous is true, the generation will be
    /// completed synchronously. If false, generation will need to be advanced by repeated
    /// calls to StepGeneration (until StepGeneration returns false)
    /// </summary>
    public void Generate(bool synchronous = true)
    {
        if (StartParts.Count == 0)
        {
            Debug.LogError("Generation failed: no Start Parts configured!");
            return;
        }
        else if (Phases.Length == 0)
        {
            Debug.LogError("Generation failed: no Phases configured!");
            return;
        }

        Generating = true;

        if (UseRandomSeed)
        {
            Seed = Random.Range(int.MinValue, int.MaxValue);
        }

        var oldRandomState = Random.state;

        Random.InitState(Seed);

        DungeonPart startPart         = StartParts.RandomElement();
        var         startPartInstance = Instantiate(startPart.gameObject, transform).GetComponent <DungeonPart>();

        CurrentDungeonPartInstances.Add(startPartInstance);

        currentPhaseStatus = new DungeonGenerationPhaseStatus(Phases[0]);
        currentPhaseStatus.OpenOutbound.AddRange(startPartInstance.OutboundConnectors());

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

        if (synchronous)
        {
            while (Generating)
            {
                StepGeneration();
            }
        }
    }
コード例 #3
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(rotateDegrees, outboundConnector.transform.forward)
                                * Quaternion.AngleAxis(180, outboundConnector.transform.up)
                                * outboundConnector.transform.rotation
                                * Quaternion.Inverse(inboundConnector.transform.localRotation);
            targetPosition = outboundConnector.transform.position - targetOrientation * inboundConnector.transform.localPosition;
        }

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

        CurrentDungeonBounds.Encapsulate(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);
    }