Пример #1
0
    public void GenerateDungeon(string _fileName)
    {
        if (!AssetDatabase.FindAssets($"{_fileName}", new[] { "Assets/Resources/FinalGraphs" }).Any())
        {
            Debug.Log($"Caution! There is no graph with the name '{_fileName}' on the Resources/FinalGraphs folder");
            return;
        }

        m_parent      = new GameObject();
        m_parent.name = "Dungeon " + _fileName;
        m_graphToLoad = Resources.Load <RoomInfoContainer>($"FinalGraphs/{_fileName}");
        LoadRoomsInfo();
    }
    }//cargar info del grafico

    private void ExpandNonTerminalNodes()//expandir los nodos NO MARCADOS con isTerminal -> nodos Non-Terminal
    {
        if (m_graphView.nodes.ToList().Cast <RoomNode>().Where(x => x.isTerminal == false).Count() > 0)
        {
            foreach (RoomNode rn in m_graphView.nodes.ToList().Cast <RoomNode>().Where(x => x.isTerminal == false))
            {
                if (rn.outputContainer.Q <Port>() == null)
                {
                    m_resourcesRulesLoaded = Resources.LoadAll <RoomInfoContainer>("Rules").ToList();                                     //cargo todas las reglas disponibles

                    if (m_resourcesRulesLoaded.Exists(x => x.name.Contains(rn.roomType)))                                                 //si existe una regla que contenga el nombre del nodo que quiero expandir;
                    {
                        RoomInfoContainer[] l_candidateRules = m_resourcesRulesLoaded.Where(x => x.name.Contains(rn.roomType)).ToArray(); //cojo las reglas que coincidan

                        int l_randomRuleSelection      = Random.Range(0, l_candidateRules.Length);                                        //escojo una regla al azar
                        RoomInfoContainer l_ruleToLoad = l_candidateRules[l_randomRuleSelection];

                        CreateExpandedNodes(l_ruleToLoad, rn); //expando el nodo dependiendo de la regla
                        m_graphView.RemoveElement(rn);         //elimino el nodo expandido para dejar sitio a los nuevos

                        //elimino los edges que pertenezcan al nodo expandido
                        foreach (Edge e in m_graphView.edges.ToList())
                        {
                            if ((e.input.node as RoomNode) == rn)
                            {
                                m_graphView.RemoveElement(e);
                            }
                        }
                    }
                    else
                    {
                        Debug.Log($"The node '{rn.roomType}' you'r trying to expand doesn't have a rule specified");
                    }
                }
                else
                {
                    Debug.Log("Non-terminal nodes must have 0 outputs (should be placed at the end of the graph)");
                }
            }
        }
        else
        {
            Debug.Log("0 Nodes to expand found. Only non-terminal nodes can be expanded. You should dismark 'isTerminal' from any node to expand it");
        }
    }
    public void LoadGraph(string _fileName, bool isFinalGraph = false)
    {
        if (!isFinalGraph)
        {
            m_graphToLoadCache = Resources.Load <RoomInfoContainer>($"Rules/{_fileName}");
        }
        else
        {
            m_graphToLoadCache = Resources.Load <RoomInfoContainer>($"FinalGraphs/{_fileName}");
        }

        if (m_graphToLoadCache == null)
        {
            Debug.Log("Error, no existing Graph to load");
            return;
        }

        ClearCurrentGraph();
        CreateLoadedNodes();
        ConnectLoadedNodes();
    }
    private void CreateExpandedNodes(RoomInfoContainer _graphToLoadCache, RoomNode roomToExpand)
    {
        List <RoomNode> l_newInstantiatedRoomsList = new List <RoomNode>();

        foreach (RoomNodeData rData in _graphToLoadCache.m_roomNodeDataList)                    //para cada nodo en el nuevo grafico (la regla que acabo de cargar);
        {
            RoomNode l_tempRoom = m_graphView.CreateRoomNode(rData.nodeType, rData.isTerminal); //instancio el nodo
            l_newInstantiatedRoomsList.Add(l_tempRoom);                                         //lo añado a la lista de "nuevas salas"
            l_tempRoom.roomID = rData.nodeID;                                                   //le asigno su ID
            m_graphView.AddElement(l_tempRoom);                                                 //añado el elemento al grafico

            //creo los puertos de entrada y salida que le tocan al nodo
            List <RoomNodeConnectionsData> l_tempOutRoomPorts = _graphToLoadCache.m_roomConnectionsDataList.Where(x => x.baseNodeId == rData.nodeID).ToList();
            l_tempOutRoomPorts.ForEach(x => m_graphView.GenerateOutputPortsOnNode(l_tempRoom, x.basePortName));

            List <RoomNodeConnectionsData> l_tempInputRoomPorts = _graphToLoadCache.m_roomConnectionsDataList.Where(x => x.targetNodeId == rData.nodeID).ToList();
            l_tempInputRoomPorts.ForEach(x => m_graphView.GenerateInputPortsOnNode(l_tempRoom, x.targetPortName));
        }
        for (int i = 0; i < l_newInstantiatedRoomsList.Count; i++)// para cada nodo que acabo de instanciar
        {
            //busco las conexiones que tiene
            List <RoomNodeConnectionsData> l_connectionDataCache = _graphToLoadCache.m_roomConnectionsDataList.Where(x => x.baseNodeId == l_newInstantiatedRoomsList[i].roomID).ToList();

            for (int j = 0; j < l_connectionDataCache.Count; j++)
            {
                string   l_targetNodeId = l_connectionDataCache[j].targetNodeId;                                                                            //guardo el id del nodo target
                RoomNode l_targetRoom   = l_newInstantiatedRoomsList.First(x => x.roomID == l_targetNodeId);                                                //busco la sala que conicida con ese ID

                string l_targetPortName = l_connectionDataCache[j].targetPortName;                                                                          //guardo el nombre del puerto target

                Port l_targetPortToConnect = m_graphView.ports.ToList().First(x => (x.node as RoomNode) == l_targetRoom && x.portName == l_targetPortName); //busco el puerto al que me tengo que conectar

                //si es un nodo 'begin', marco este nodo como el beginNodeInstantiated (en el begin node empieza la regla) -> sirve como referencia para saber donde empezar a conectar el puerto q quiero expandir
                if (l_newInstantiatedRoomsList[i].roomType == "begin")
                {
                    m_beginNodeInstantiated = l_newInstantiatedRoomsList[i];
                }

                //conecto el puerto del nodo [i] con el targetPort -> en este primer linkado asigno el tempEdge a una variable m_currentBeginNodeEdge
                //que luego me servira para encontrar el nodo conectado al nodo 'begin'
                LinkRoomPorts(l_newInstantiatedRoomsList[i].outputContainer[j].Q <Port>(), l_targetPortToConnect);

                //seteo su position basadome en la posicion del nodo expandido
                l_targetRoom.SetPosition(new Rect(_graphToLoadCache.m_roomNodeDataList.First(x => x.nodeID == l_targetRoom.roomID).position +
                                                  roomToExpand.GetPosition().position, m_graphView.defaultNodeSize));
            } //end for
        }     //end of for loop

        //busco el puerto de entrada al que esta conectado la habitacion que quiero expandir
        Port l_basePort = m_graphView.edges.ToList().Find(x => (x.input.node as RoomNode) == roomToExpand).output;

        l_basePort.portColor = new Color(0, 0, 200);//blue

        //el puerto target será el que hemos marcado previamente al conectar los nodos de la regla que acabamos de cargar
        //el currentBeginNodeEdge es la conexion del nodo 'begin' -> cojemos el input, que es el puerto q pertenece al nodo 'begin'
        Port l_targetPort = m_currentBeginNodeEdge.input;

        l_targetPort.portColor = new Color(200, 0, 0);                                                     //red
        l_targetPort.portName  = m_UtilitiesInstance.ReturnConnectionNameByReference(l_basePort.portName); //asignar el nuevo nombre del puerto dependiendo del puerto base conectado

        //elimino el nodo 'begin' -> solo sirve como referencia para saber donde conectar el nodo que queremos expandir
        m_graphView.RemoveElement(m_beginNodeInstantiated);

        //conecto los puertos
        LinkRoomPorts(l_basePort, l_targetPort);

        List <RoomNode> l_currentNodesOnGraph = m_graphView.nodes.ToList().Cast <RoomNode>().ToList();

        //asignar nuevas id a cada nodo
        for (int i = 0; i < l_currentNodesOnGraph.Count; i++)
        {
            for (int j = 0; j < l_newInstantiatedRoomsList.Count(); j++)
            {
                if (l_currentNodesOnGraph[i] == l_newInstantiatedRoomsList[j])
                {
                    List <Edge> l_currentOutputRoomEdges = m_graphView.edges.ToList().Where(x => (x.output.node as RoomNode) == l_currentNodesOnGraph[i]).ToList();
                    List <Edge> l_currentInputRoomEdges  = m_graphView.edges.ToList().Where(x => (x.input.node as RoomNode) == l_currentNodesOnGraph[i]).ToList();

                    string l_newRoomID = l_currentNodesOnGraph[i].roomID = System.Guid.NewGuid().ToString();

                    foreach (Edge e in l_currentOutputRoomEdges)
                    {
                        e.output.name = l_newRoomID;
                    }
                    foreach (Edge e in l_currentInputRoomEdges)
                    {
                        e.input.name = l_newRoomID;
                    }
                }
            }
        } //end of for loop
    }     //end expand nodes function
    public void SaveGraph(string _fileName, bool isFinalGraph = false)
    {
        if (!m_roomsList.Any())
        {
            Debug.Log("No nodes to save found"); return;
        }                                                                        // si no hay rooms que guardar, no hacemos nada

        //evitar crear un nodo en el final graph que no exista en la lista de habitaciones
        if (isFinalGraph == true)
        {
            foreach (RoomNode roomNode in m_roomsList)
            {
                if (roomNode.roomType != "Start" && roomNode.roomType != "End" && !m_UtilitiesInstance.m_typesOfRoomsList.Exists(x => x.Contains(roomNode.roomType)))
                {
                    Debug.Log($"Caution! The room type '{roomNode.roomType}' doesn't exist in the list of room prefabs. Change the node type or add a prefab to the dungeon generation list");
                    return;
                }
            }
        }

        Edge[] l_edgesConnected = m_edgesList.Where(x => x.output.node != null).ToArray();

        foreach (Edge edge in l_edgesConnected)
        {
            if (!m_UtilitiesInstance.m_myConnectionsDictionary.ContainsKey(edge.output.portName))
            {
                Debug.Log($"The connection name '{edge.output.portName}' doesn't appears in the Connections Dictionary (UtilitiesAndReferences Class). Please use a name from the Dictionary");
                return;
            }
        }

        RoomInfoContainer l_nodeContainerData = ScriptableObject.CreateInstance <RoomInfoContainer>();


        foreach (RoomNode r in m_roomsList)//guardamos cada nodo, su id, el tipo, y la posicion,
        {
            l_nodeContainerData.m_roomNodeDataList.Add(new RoomNodeData
            {
                nodeID     = r.roomID,
                nodeType   = r.roomType,
                position   = r.GetPosition().position,
                isTerminal = r.isTerminal
            });
        }
        for (int i = 0; i < l_edgesConnected.Length; i++)                        //para cada conexion del grafico, guardamos
        {
            RoomNode l_baseRoom   = l_edgesConnected[i].output.node as RoomNode; //nodo de salida
            RoomNode l_targetRoom = l_edgesConnected[i].input.node as RoomNode;  //nodo de entrada


            l_nodeContainerData.m_roomConnectionsDataList.Add(new RoomNodeConnectionsData
            {
                baseNodeId   = l_baseRoom.roomID,
                targetNodeId = l_targetRoom.roomID,

                basePortName   = l_edgesConnected[i].output.portName,
                targetPortName = m_UtilitiesInstance.ReturnConnectionNameByReference(l_edgesConnected[i].output.portName),
            }
                                                              );
        }

        if (!isFinalGraph)
        {
            if (!m_roomsList.Exists(x => x.roomType == "begin"))
            {
                Debug.Log("You need to create a 'begin'(NO capital 'b') node to save a Rule");
                return;
            }
            else
            {
                if (m_roomsList.Find(x => x.roomType == "begin").outputContainer.childCount > 1)
                {
                    Debug.Log("'begin' node must have only 1 output connection");
                }
                else
                {
                    AssetDatabase.CreateAsset(l_nodeContainerData, $"Assets/Resources/Rules/{_fileName}.asset");//generamos un asset con la informacion
                }
            }
        }
        else
        if (!m_roomsList.Exists(x => x.roomType == "Start"))
        {
            Debug.Log("You need to create a 'Start' (WITH capital 'S') node to save a FinalGraph"); return;
        }
        else
        {
            AssetDatabase.CreateAsset(l_nodeContainerData, $"Assets/Resources/FinalGraphs/{_fileName}.asset");//generamos un asset con la informacion
        }

        AssetDatabase.SaveAssets();
    }