Advertisement
Guest User

Untitled

a guest
Feb 19th, 2019
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.66 KB | None | 0 0
  1. using FFF.Fuente.Gameplay.Entidades.Jugador;
  2. using FFF.Fuente.Gameplay.Reglas;
  3. using FFF.Fuente.Interfaz;
  4. using FFF.Fuente.Matematicas;
  5. using FFF.Fuente.Metadatos;
  6. using FFF.Fuente.Progreso;
  7. using FFF.Fuente.Progreso.Misiones.Tienda;
  8. using FFF.Herramientas;
  9. using Sirenix.OdinInspector;
  10. using System;
  11. using System.Collections;
  12. using System.Collections.Generic;
  13. using System.Diagnostics;
  14. using System.Linq;
  15. using System.Threading;
  16. using Unity.Jobs;
  17. using UnityEngine;
  18. using static FFF.Fuente.Matematicas.Probabilidad;
  19.  
  20. namespace FFF.Fuente.Generacion
  21. {
  22. public class Generador : MonoBehaviour
  23. {
  24.  
  25. private void Update()
  26. {
  27. if (Input.GetKeyDown(KeyCode.Q))
  28. {
  29. CargarBoss();
  30. }
  31. }
  32.  
  33. private void CargarBoss()
  34. {
  35. // Se oculta la sala de la que se sale y se guarda la nueva sala
  36. EscenaActual.Mapa.gameObject.SetActive(false);
  37.  
  38. // Se cambia la EscenaV2 en la que se encuentra al de la direccion deseada
  39. EscenaActual = EscenaLobbyBoss;
  40. EscenaActual.Cargar();
  41.  
  42. // Se mueve el personaje al punto de spawn
  43. var salaActual = EscenaActual.Mapa;
  44. var contrario = EscenaActual.Mapa.Reemplazos.First().Direccion;
  45.  
  46. Transform puntoTransicion;
  47. if (EscenaActual.Tipo != TipoReemplazo.Boss) puntoTransicion = salaActual.Transiciones.Find(x => x.Direccion == contrario).transform;
  48. else puntoTransicion = EscenaActual.Mapa.GetComponent<SalaBoss>().SpawnPointPersonaje.transform;
  49.  
  50. Personaje.Instancia.transform.position = puntoTransicion.position;
  51. Personaje.Instancia.Controlador.ProCamera2D.transform.position = new Vector3(puntoTransicion.position.x, puntoTransicion.position.y, -100);
  52.  
  53. // Evento Sala entrar
  54. Constantes.Instancia.EVENTO_SALA_ENTRANDO?.Invoke(EscenaActual, EventArgs.Empty);
  55.  
  56. Anchura(EscenaActual).ForEach(x =>
  57. {
  58. if (x.Item2 <= 2)
  59. {
  60. if (x.Item1 != EscenaActual)
  61. x.Item1.Cargar(false);
  62. }
  63. });
  64. }
  65.  
  66. #region Singleton
  67.  
  68. private static Generador _instancia;
  69.  
  70. public static Generador Instancia
  71. {
  72. get
  73. {
  74. if (_instancia == null)
  75. {
  76. _instancia = FindObjectOfType<Generador>();
  77. }
  78. return _instancia;
  79. }
  80. }
  81.  
  82. #endregion Singleton
  83.  
  84. [TabGroup("Generacion"), Space(15)]
  85. [Tooltip("Cantidad mínimo de salas a generar")]
  86. [MinMaxSlider(1, 50)]
  87. public Vector2 CantidadSalas = new Vector2(10, 25);
  88.  
  89. [Tooltip("Semilla para generar los numeros aleatorios")]
  90. [TabGroup("Generacion"), ReadOnly]
  91. public int Semilla = -1;
  92.  
  93. [Range(0, 5)]
  94. [TabGroup("Generacion")]
  95. [Tooltip("Cantidad de salas de bosses a generar")]
  96. public int CantidadSalasBosses = 1;
  97.  
  98. [Range(0, 5)]
  99. [TabGroup("Generacion")]
  100. [Tooltip("Cantidad de salas de tiendas a generar")]
  101. public int CantidadSalasTiendas = 1;
  102.  
  103. [Range(0, 5)]
  104. [TabGroup("Generacion")]
  105. [Tooltip("Cantidad de salas de recompensas a generar")]
  106. public int CantidadSalasRecompensas = 1;
  107.  
  108. [Header("Parametros de generación")]
  109. public List<MetadataSala> PoolSalas;
  110. public List<MetadataSala> PoolBosses;
  111. public List<MetadataSala> PoolTiendas;
  112. public List<MetadataSala> PoolInicios;
  113. public List<MetadataSala> PoolLobbys;
  114. public List<MetadataSala> PoolRecompensas;
  115.  
  116. [Header("Configuraciones de nivel")]
  117. public PoolEntidades PoolEntidades;
  118. public PoolItems PoolItems;
  119. public PoolObjetos PoolObjetos;
  120.  
  121. [HideInInspector]
  122. public Escena EscenaInicio, EscenaActual, EscenaLobbyBoss, EscenaRecompensa, EscenaBoss;
  123.  
  124. private int SalasGeneradas;
  125. private bool _generacionIniciada = false;
  126. public bool Generado { get; private set; }
  127.  
  128. private const int TAMAÑO_MATRIZ = 50;
  129.  
  130. private void OnValidate()
  131. {
  132. CantidadSalas.x = (int)CantidadSalas.x;
  133. CantidadSalas.y = (int)CantidadSalas.y;
  134. }
  135.  
  136. private void Awake()
  137. {
  138. Generado = false;
  139. // SOLO PUEDE EXISTIR UNA INSTANCIA
  140. if (Generador.Instancia != this) Destroy(this);
  141. }
  142.  
  143.  
  144. private void GenerarPreset()
  145. {
  146. _generacionIniciada = true;
  147.  
  148. // Eliminas las salas que no son validas
  149. PoolSalas.RemoveAll(x => !x.Desbloqueado());
  150. IniciarGeneracion();
  151. }
  152.  
  153.  
  154. private void IniciarGeneracion()
  155. {
  156. // Se escoge el numero de salas.
  157. int cantidadSalas = Constantes.Instancia.RANDOM_GENERACION.Generar((int)CantidadSalas.x, (int)CantidadSalas.y);
  158.  
  159. SalasGeneradas = cantidadSalas + CantidadSalasBosses + CantidadSalasRecompensas + CantidadSalasTiendas;
  160.  
  161. // Matriz de ocupacion
  162. Escena[,] matrizOcupacion = new Escena[TAMAÑO_MATRIZ, TAMAÑO_MATRIZ];
  163.  
  164. // De las pools se escoge una sala de inicio aleatoria segun la probabilidad de cada sala.
  165. EscenaInicio = new Escena(EventoAleatorioSala(BuscarTipo(TipoReemplazo.Inicio)), Constantes.Instancia.RANDOM_GENERACION.Generar(0, int.MaxValue));
  166.  
  167. // Se asigna a la mitad de toda la matriz la escena de inicio.
  168. Vector2Int posicionInicio = new Vector2Int(TAMAÑO_MATRIZ / 2, TAMAÑO_MATRIZ / 2);
  169. matrizOcupacion[posicionInicio.y, posicionInicio.x] = EscenaInicio;
  170.  
  171. // Se genera la salas, se suma uno mas como offset de la funcion, que genera n - 1 salas en realidad.
  172. // TODO 31/01/19 - Leonardo Arteaga: Por alguna razón por lo visto siempre se generan 2 salas menos de las que se deberían.
  173. Generar(EscenaInicio, null, cantidadSalas + 2, matrizOcupacion, posicionInicio);
  174. GenerarSalaBoss();
  175. GenerarSalaRecompensa();
  176. GenerarSalaTienda();
  177.  
  178. var recorrido = Anchura(EscenaInicio);
  179. recorrido.ForEach(x =>
  180. {
  181. //if (x.Item2 <= 2)
  182. x.Item1.Cargar(false);
  183. });
  184. Generado = true;
  185. }
  186.  
  187. // Metodo para la generación
  188. // Pregunta si la sala colindante puede generar una entrada a la sala actual (EJ: Izquierda en sala 1 NECESITA (->PUERTA<-) Derecha en sala 2)
  189. Func<Escena, Direcciones, bool> Posible = (x, y) => x.DireccionesNoGeneradas().Contains(Direccion.DireccionContraria(y));
  190.  
  191. private Vector2Int PosicionDireccion(Vector2Int posicionActual, Direcciones direccion)
  192. {
  193. switch (direccion)
  194. {
  195. case Direcciones.Arriba:
  196. return new Vector2Int(posicionActual.x, posicionActual.y - 1);
  197. case Direcciones.Derecha:
  198. return new Vector2Int(posicionActual.x + 1, posicionActual.y);
  199. case Direcciones.Abajo:
  200. return new Vector2Int(posicionActual.x, posicionActual.y + 1);
  201. case Direcciones.Izquierda:
  202. return new Vector2Int(posicionActual.x - 1, posicionActual.y);
  203. default:
  204. return posicionActual;
  205. }
  206. }
  207.  
  208. private List<Direcciones> DireccionesLibres(Escena[,] MatrizOcupacion, Vector2Int pos)
  209. {
  210. List<Direcciones> res = new List<Direcciones>();
  211. if (MatrizOcupacion[pos.y, pos.x + 1] == null) res.Add(Direcciones.Derecha);
  212. if (MatrizOcupacion[pos.y, pos.x - 1] == null) res.Add(Direcciones.Izquierda);
  213. if (MatrizOcupacion[pos.y + 1, pos.x] == null) res.Add(Direcciones.Abajo);
  214. if (MatrizOcupacion[pos.y - 1, pos.x] == null) res.Add(Direcciones.Arriba);
  215. return res;
  216. }
  217.  
  218. /// <summary>
  219. /// Genera el layout del nivel
  220. /// </summary>
  221. /// El metodo recursivo, devuelve la cantidad de salas que no se pudo generar.
  222. private void Generar(Escena EscenaGenerar, Escena EscenaAnterior, int CantidadSalas, Escena[,] MatrizOcupacion, Vector2Int Posicion)
  223. {
  224. if (CantidadSalas < 1) return;
  225.  
  226. // De las conexiones totales que se deben generar en esta sala, verificar del máximo real que se pueden generar se generarán.
  227. // Direcciones disponibles para generar conexiones
  228. var libres = DireccionesLibres(MatrizOcupacion, Posicion);
  229.  
  230. // Entre la cantidad de direcciones disponibles y las cantidad de salas que todavian faltan generar, cuanto debe generar?
  231. int minimax = Math.Min(libres.Count, CantidadSalas);
  232. // Cuantas conexiones se deben generar en esta sala
  233. if (minimax <= 0) return;
  234. // Escoge cuantas salas se deben generar
  235. int generarConexiones = Constantes.Instancia.RANDOM_GENERACION.Generar(1, minimax + 1);
  236.  
  237. for (int i = 0; i < generarConexiones; ++i)
  238. {
  239. // Se selecciona una direccion aleatoria y se elimina de las posibilidades.
  240. var direccion = Constantes.Instancia.RANDOM_GENERACION.EventoAleatorio(libres);
  241. libres.Remove(direccion);
  242.  
  243. // Se obtiene la posicion en la matriz de la direccion seleccionada
  244. var posicionDireccion = PosicionDireccion(Posicion, direccion);
  245.  
  246. // Se genera la sala adyacente
  247. var salaAleatoria = EventoAleatorioSala(PoolSalas);
  248. Escena nuevaEscena = new Escena(salaAleatoria, Constantes.Instancia.RANDOM_GENERACION.Generar(0, int.MaxValue));
  249. MatrizOcupacion[posicionDireccion.y, posicionDireccion.x] = nuevaEscena;
  250.  
  251. // Se 'conectan' las salas por sus adyacentes, el anterior conectada a la actual.
  252. EscenaGenerar.Adyacentes.Add(direccion, nuevaEscena);
  253. nuevaEscena.Adyacentes.Add(Direccion.DireccionContraria(direccion), EscenaGenerar);
  254. }
  255.  
  256. // Despues de generar todas las salas, se debe ir recursivamente por sus adyacentes
  257. var valores = Fuente.Matematicas.Operaciones.Separacion(CantidadSalas - generarConexiones, generarConexiones, Constantes.Instancia.RANDOM_GENERACION);
  258. // Se quita una adyacencia a cada sala, porque una de estas es la 'conexion' entre las dos salas (la generada y la que se esta generando)
  259. valores.ForEach(x => x--);
  260.  
  261. // Se visita recursivamente cada escena para proseguir la generación
  262. foreach (var val in EscenaGenerar.Adyacentes)
  263. {
  264. if (val.Value != EscenaAnterior)
  265. {
  266. // Se generará siempre y cuando se debe generar por lo menos una sala
  267. if (valores.Count > 0)
  268. {
  269. Generar(val.Value, EscenaGenerar, valores[0], MatrizOcupacion, PosicionDireccion(Posicion, val.Key));
  270. valores.RemoveAt(0);
  271. }
  272. }
  273. }
  274. }
  275.  
  276. /// <summary>
  277. /// De las salas existentes, busca una de las más lejanas y genera alli la sala del boss
  278. /// </summary>
  279. private void GenerarSalaBoss()
  280. {
  281. // Se escoge una sala de boss aleatoria para generar
  282. var salaLobbyBoss = EventoAleatorioSala(BuscarTipo(TipoReemplazo.LobbyBoss));
  283. // Se hace el recorrido del arbol para obtener las distancias a todas las salas desde el inicio
  284. var recorrido = Anchura(EscenaInicio);
  285. recorrido.RemoveAll(x => x.Item1 == EscenaInicio);
  286.  
  287. // Del recorrido busca cual es la mayor distancia
  288. var mayorDistancia = recorrido.Max(x => x.Item2);
  289. // Busca las salas con mayor distancia
  290. var salasMasLejanas = recorrido.FindAll(x => x.Item2 == mayorDistancia);
  291. // De las salas con mayor distancia escoge una aleatoriamente
  292. var escenaEscogida = Constantes.Instancia.RANDOM_GENERACION.EventoAleatorio(salasMasLejanas).Item1;
  293.  
  294. // Cambia la sala normal por la del boss
  295. escenaEscogida.Metadatos = salaLobbyBoss;
  296. EscenaLobbyBoss = escenaEscogida;
  297. EscenaLobbyBoss.Tipo = TipoReemplazo.LobbyBoss;
  298.  
  299. // Ahora sobre la sala del lobby boss, se debe generar el boss
  300. var salaBoss = EventoAleatorioSala(BuscarTipo(TipoReemplazo.Boss));
  301. EscenaBoss = new Escena(salaBoss, Constantes.Instancia.RANDOM_GENERACION.Generar(0, int.MaxValue));
  302.  
  303. }
  304.  
  305. /// <summary>
  306. /// De las salas existentes, busca la sala más lejana a la sala del boss y genera alli la sal de recompensa.
  307. /// </summary>
  308. private void GenerarSalaRecompensa()
  309. {
  310. // Se escoge una sala de boss aleatoria para generar
  311. var salaRecompensa = EventoAleatorioSala(BuscarTipo(TipoReemplazo.Recompensa));
  312. // Se hace el recorrido del arbol para obtener las distancias a todas las salas desde el inicio
  313. var recorrido = Anchura(EscenaLobbyBoss);
  314. recorrido.RemoveAll(x => x.Item1 == EscenaInicio);
  315.  
  316. // Del recorrido busca cual es la mayor distancia
  317. var mayorDistancia = recorrido.Max(x => x.Item2);
  318. // Busca las salas con mayor distancia
  319. var salasMasLejanas = recorrido.FindAll(x => x.Item2 == mayorDistancia);
  320. // De las salas con mayor distancia escoge una aleatoriamente
  321. var escenaEscogida = Constantes.Instancia.RANDOM_GENERACION.EventoAleatorio(salasMasLejanas).Item1;
  322.  
  323. // Cambia la sala normal por la del boss
  324. escenaEscogida.Metadatos = salaRecompensa;
  325. EscenaRecompensa = escenaEscogida;
  326. EscenaRecompensa.Tipo = TipoReemplazo.Recompensa;
  327. }
  328.  
  329. private void GenerarSalaTienda()
  330. {
  331. List<MetadataSala> salasPosibles = new List<MetadataSala>();
  332. MetadataSala salaEscogida;
  333. // Se hace el recorrido del arbol para obtener las distancias a todas las salas desde el inicio
  334. var recorrido = Anchura(EscenaLobbyBoss);
  335. recorrido.RemoveAll(x => x.Item1 == EscenaInicio);
  336.  
  337. // Busca que tienda se debe generar segun el progreso del jugador
  338. var nivel_2 = ControladorProgreso.Instancia.EstadoMision(Mision_Tienda_Nivel_2.CodigoMision);
  339. var nivel_3 = ControladorProgreso.Instancia.EstadoMision(Mision_Tienda_Nivel_3.CodigoMision);
  340.  
  341. // Se escoge una sala de boss aleatoria para generar
  342. var tiendas = BuscarTipo(TipoReemplazo.Tienda);
  343.  
  344. // La tienda es de nivel 3
  345. if (nivel_3) salasPosibles = tiendas.FindAll(x => x.Misiones.Exists(y => y == Mision_Tienda_Nivel_3.CodigoMision));
  346. // La tienda es de nivel 2
  347. else if (nivel_2) salasPosibles = tiendas.FindAll(x => x.Misiones.Exists(y => y == Mision_Tienda_Nivel_2.CodigoMision));
  348. // La tienda es de nivel 1
  349. else salasPosibles = tiendas.FindAll(x => x.Misiones.TrueForAll(y => y != Mision_Tienda_Nivel_2.CodigoMision && y != Mision_Tienda_Nivel_3.CodigoMision));
  350.  
  351. salaEscogida = EventoAleatorioSala(salasPosibles);
  352.  
  353. // Busca las salas con solo un adyacente
  354. var salasUnaEntrada = recorrido.FindAll(x => x.Item1.Adyacentes.Count == 1 && x.Item1.Tipo == TipoReemplazo.Normal);
  355.  
  356. // Validación por si no es posible generar una sala de tienda
  357. if (salasUnaEntrada.Count == 0) return;
  358. // De las salas con mayor distancia escoge una aleatoriamente
  359. var escenaEscogida = Constantes.Instancia.RANDOM_GENERACION.EventoAleatorio(salasUnaEntrada).Item1;
  360.  
  361. // Cambia la sala normal por la de la tienda
  362. escenaEscogida.Metadatos = salaEscogida;
  363. EscenaRecompensa = escenaEscogida;
  364. EscenaRecompensa.Tipo = TipoReemplazo.Tienda;
  365. }
  366.  
  367. /// <summary>
  368. /// Calcula las distancias desde un escenario de inicio a todos los puntos
  369. /// </summary>
  370. private List<Tuple<Escena, int>> Anchura(Escena inicio)
  371. {
  372. List<Tuple<Escena, int>> resultado = new List<Tuple<Escena, int>>();
  373.  
  374. // Cola para el recorrido
  375. Queue<Escena> nivel = new Queue<Escena>(), hijos = new Queue<Escena>();
  376. nivel.Enqueue(inicio);
  377. Escena tempEsc;
  378.  
  379. // El primer elemento siempre tiene distancia 0
  380. resultado.Add(new Tuple<Escena, int>(inicio, 0));
  381. int distancia = 1;
  382.  
  383. while (nivel.Count != 0)
  384. {
  385. tempEsc = nivel.Dequeue();
  386. foreach (var val in tempEsc.Adyacentes)
  387. {
  388. // Si no existe, quiere decir que no se ha calculado su distancia
  389. if (!resultado.Exists(x => x.Item1 == val.Value) && val.Value != inicio)
  390. {
  391. // Se añade la EscenaV2 con la distancia al punto
  392. resultado.Add(new Tuple<Escena, int>(val.Value, distancia));
  393.  
  394. // Se agregan todos los adyacentes de esta sala
  395. hijos.Enqueue(val.Value);
  396. }
  397. }
  398.  
  399. if (nivel.Count == 0 && hijos.Count != 0)
  400. {
  401. nivel = hijos;
  402. hijos = new Queue<Escena>();
  403. distancia++;
  404. }
  405. }
  406. return resultado;
  407. }
  408.  
  409. /// <summary>
  410. /// Instancia la sala o teletransporta a la primera sala del layout generado.
  411. /// </summary>
  412. public void Iniciar(int Semilla = -1)
  413. {
  414. // Inicia la generacion
  415. if (!_generacionIniciada) GenerarPreset();
  416. StartCoroutine(FinalizarGeneracion());
  417. }
  418.  
  419. private IEnumerator FinalizarGeneracion()
  420. {
  421. while (!EscenaInicio.Iniciado) yield return null;
  422. // La Escena actual es la de inicio
  423. EscenaActual = EscenaInicio;
  424.  
  425. // Se carga la sala, y se asigna la sala creada a la EscenaV2. Si habia una sala cargada, se desactiva.
  426. EscenaActual.Cargar();
  427.  
  428. while (Personaje.Instancia == null) yield return new WaitForEndOfFrame();
  429. Personaje.Instancia.transform.position = EscenaInicio.Mapa.GetComponent<SalaInicio>().SpawnPersonaje.position;
  430.  
  431. while (UI.Instancia.Juego_Instancia_HUD == null) yield return null;
  432. var hud = UI.Instancia.Juego_Instancia_HUD;
  433. hud.IniciarMinimapa();
  434. }
  435.  
  436. public void CambiarNivel(Direcciones direccion)
  437. {
  438. if (EscenaActual == null) return;
  439.  
  440. if (EscenaActual.Adyacentes.ContainsKey(direccion))
  441. {
  442. // Se oculta la sala de la que se sale y se guarda la nueva sala
  443. EscenaActual.Mapa.gameObject.SetActive(false);
  444.  
  445. // Se cambia la EscenaV2 en la que se encuentra al de la direccion deseada
  446. EscenaActual = EscenaActual.Adyacentes[direccion];
  447. EscenaActual.Cargar();
  448.  
  449. // Se mueve el personaje al punto de spawn
  450. var salaActual = EscenaActual.Mapa;
  451. var contrario = Direccion.DireccionContraria(direccion);
  452.  
  453. Transform puntoTransicion;
  454. if (EscenaActual.Tipo != TipoReemplazo.Boss) puntoTransicion = salaActual.Transiciones.Find(x => x.Direccion == contrario).transform;
  455. else puntoTransicion = EscenaActual.Mapa.GetComponent<SalaBoss>().SpawnPointPersonaje.transform;
  456.  
  457. Personaje.Instancia.transform.position = puntoTransicion.position;
  458. Personaje.Instancia.Controlador.ProCamera2D.transform.position = new Vector3(puntoTransicion.position.x, puntoTransicion.position.y, -100);
  459.  
  460. // Evento Sala entrar
  461. Constantes.Instancia.EVENTO_SALA_ENTRANDO?.Invoke(EscenaActual, EventArgs.Empty);
  462.  
  463. Anchura(EscenaActual).ForEach(x =>
  464. {
  465. if (x.Item2 <= 2)
  466. {
  467. if (x.Item1 != EscenaActual)
  468. x.Item1.Cargar(false);
  469. }
  470. });
  471. }
  472. }
  473.  
  474. public MetadataSala EventoAleatorioSala(List<MetadataSala> datos)
  475. {
  476. var prob = Constantes.Instancia.RANDOM_GENERACION;
  477. ListaEventos<MetadataSala> elementos = new ListaEventos<MetadataSala>();
  478. datos.ForEach(x => elementos.Add(new Evento<MetadataSala>(x, x.Probabilidad)));
  479. return prob.EventoAleatorio(elementos);
  480. }
  481.  
  482. public List<MetadataSala> BuscarTipo(TipoReemplazo tipo)
  483. {
  484. switch (tipo)
  485. {
  486. case TipoReemplazo.Normal: return PoolSalas;
  487. case TipoReemplazo.Boss: return PoolBosses;
  488. case TipoReemplazo.Tienda: return PoolTiendas;
  489. case TipoReemplazo.Recompensa: return PoolRecompensas;
  490. case TipoReemplazo.Secreta: return new List<MetadataSala>();
  491. case TipoReemplazo.Inicio: return PoolInicios;
  492. case TipoReemplazo.LobbyBoss: return PoolLobbys;
  493. default: return new List<MetadataSala>();
  494. }
  495. }
  496.  
  497. }
  498. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement