Jump to content
UnitySpain

Search the Community

Showing results for tags 'optimización'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Inicio
    • Proyectos
    • Offtopic
    • Unity Feeds
    • Website
  • Mesa de ayuda
    • Unity
    • Arte
    • Otras Especialidades
    • Builds & Dispositivos
  • Aportes de la Comunidad
    • Recursos
    • Eventos
    • Buenas Prácticas
  • Bolsa de trabajo & Colaboraciones
    • Ofertas y Demandas
  • Post Antiguos
    • General (Antiguo)

Blogs

  • byGui
  • El Blog de Pioj

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Especialidad

Found 12 results

  1. Voy a reunir pequeños tips de Unity que se pueden resumir en pocas frases. Esta lista se irá agrandando poco a poco en el futuro. Podéis añadir los vuestros si queréis. La idea es TIP + imagen representativa. Puede usar el atributo MenuItem para agregar menús contextuales que pueden llamar a funciones estáticas. Además, si desea crear teclas de acceso rápido, puede agregar caracteres especiales ("%" para ctrl, "#" para shift, "&" para alt) Recuerde guardar las cadenas repetidas en una variable constante. Verifique que su sistema de partículas tenga un culling automático. Si no tiene,revise las razones o use CullingGroup Puede usar el atributo ContextMenu para probar su código en la ventana del editor No olvide optimizar sus Animators con el modo de selección. Esto deshabilita la animación cuando no son visibles.
  2. Guest

    Materiales, texturas y optimización

    Buenas a todos. Llevo tiempo con una duda rondándome la cabeza. Estoy creando un escenario para mi videojuego para PC. Esto es una casa donde además todo el juego se desarrollaría aquí dentro. Quiero conseguir una buena optimización y tengo entendido que no se recomiendan muchos materiales para la misma escena ya que resulta costoso para la GPU. El caso es que no se cuándo estoy ejerciendo una buena práctica en materia de optimización. Cogí el escenario, con sus objetos repartidos por los distintos espacios, y lo convertí en un solo objeto. Entonces, desplegué las UVs con proyección inteligente para pintar sobre estas en substance Painter. La calidad baja mucho cuanto más grande es el objeto y menos espacio ocupa en el cuadro de UV. Entonces empecé a pintar y se vio borroso. La solución que vi era la de dividir el escenario en objetos independientes (pasillo, sala de estar, cocina...) para aplicarles un material distinto y de esta manera la calidad de las texturas aumentaría al expandir sus UVs por un espacio más amplio. También pensé en hacer de todos los objetos del escenario (sillas, lámparas, mesas...) un mismo objeto para así aplicarles el mismo material, habiendo antes desplegado las UVs y pintando luego para obtener la textura. Sin embargo, no se si voy a pasarme con los materiales en la escena. Podría probar y ver qué tal corre con varios materiales repartidos a los que además pensaba darles reflectividad y dotarlos de más realismo. Entonces ya nos metemos en tema de luces y también tengo entendido que no es muy recomendado meterle muchas luces a la misma escena porque resulta muy costoso para la GPU. Me gustaría que me recomendaran, si pudieran y la hubiera, una mejor práctica para poder obtener el detalle que estoy buscando con los materiales y texturas dentro del marco de una buena optimización. Muchas gracias y un saludo.
  3. Buenos días una pregunta es posible en Unity realizar "campos de visión"? Por ejemplo cuando uno se encuentra dentro de la caja de la izquierda no ve la caja de la derecha ("Esta no existe") hasta que llega a otro campo donde si aparece el objeto y el personaje lo ve. (lo del medio es una pared) Existe algún script o algo similar para hacerlo a distintos niveles, como por ejemplo le doy un nivel 1 y este no puede ver el "a1". Gracias,
  4. Hola! Os dejo por aquí el último post en mi blog sobre "Optimización en Unity". En él hablo sobre algunas técnicas básicas para hacer nuestro juego más óptimo. Espero que os guste! LINK: https://histeriagamedev.wordpress.com/2017/06/16/optimizacion-en-unity/ Saludos!
  5. Óptimización mediante script. Ya termine mi proyecto creo que lo subire aquí, queria lanzarlo a steam pero creo que no será el caso(más que todo porque tiene bugs xD), lo que me falta es el level desing.. pero en fin. La DUDA Tengo un spawn de enemigos y se supone que el player tiene que aguantar 5 min pero los enemigos spawnean cada 5 seg. y bueno se van juntando y despues de cierto tiempo me da un bajon de fps(laggg..) y no quiero que pase eso, por si alguien se lo pregunta el player tiene armas.. pero y si el player no quiere disparar? se juntan enemigos y pasa lo del lag, lo que queria es que me den algunas técnicas de óptimización mediante script yo conosco muy poquitas, pienso que para cada juego es diferente la optimización debido a las técnicas de scripting que se utiliza para el juego, así que las tecnicas que más use son: -RayCast() -Random.insideUnitySphere -Physics.overlapSphere(); -7 animaciones para el enemigo -SystemParticles -y algunos arboles xD Así es el juego.. Creo que el problemas puede ser el sistema de particulas? los desgraciados(enemigos) se curan xD aparte de que el jugador puede hacer esto Lo que quiero es óptimzarlo sin quitar nada, pero que sea de un nivel bajo que algunas cosas no me las sé :C PD: disculpen si es largo pero no sabia como ponerlo xD, la motivación tambien ayuda :)
  6. Cuando ya has dado tus primeros pasos en Multiplayer, te empiezas a dar cuenta de que la respuesta de los clientes durante una partida no es todo lo suave o fluída que debería ser. Esto es porque hace falta predecir el movimiento de los clientes del juego. Esta guía cubre todos los pasos para conseguirlo. http://gamasutra.com/blogs/ChristianArellano/20160329/269065/UNET_Unity_5_Networking_Entity_Interpolation_Part_1_of_6__Break_Into_Components.php?utm_source=dlvr.it&utm_medium=twitter
  7. Buenos Días a todos, hace poco estaba siguiendo los primeros tutoriales de Catlike Coding http://catlikecoding.com/unity/tutorials/ en las lecciones básicas 2 y 3, es una especie benchmark para probar el rendimiento del dispositivo en el que el juego esta compilado. estuve probando una herramienta de optimización que hice algún tiempo y que voy actualizando poco a poco cada vez, sin embargo el rendimiento que obtengo no es mucho. la razón es que el benchmark instancia esferas desde 2 prefabs, generando demasiados drawcalls, a pesar de que provienen de los mismos prefabs, se crean copias de las mismas mallas y copias de los mismos materiales. he hecho pruebas con 2 esferas usando MeshFilter.sharedMesh y MeshRenderer.sharedMaterial, y esto lo unico que hace es duplicar aun mas los materiales y las mallas using UnityEngine; public class ComparadorMeshes : MonoBehaviour { public MeshFilter mesh1, mesh2; public MeshRenderer render1, render2; // Use this for initialization void Awake () { if (mesh1.mesh != mesh2.mesh) mesh2.sharedMesh = mesh1.mesh; if (mesh1.mesh == mesh2.mesh) Debug.Log("Mesh1 es igual al mesh2"); else Debug.Log("Mesh1 es diferente al Mesh2"); if (render1.material != render2.material) render2.sharedMaterial = render1.material; if (render1.material == render2.material) Debug.Log("Render1 es igual al Render2"); else Debug.Log("Render1 es diferente al Render2"); } }Como verán estoy confundido, no encuentro una manera de que compartan el mismo mesh y el mismo material y hacer que se reduzcan los drawcalls Gracias de antemano
  8. https://www.assetstore.unity3d.com/en/#!/content/37687 Hola a todos, para estas vacaciones se que muchos empezaran un nuevo proyecto o continuaran los que ya han empezado hace mucho, para todos los que han de tener problemas de rendimiento en sus juegos ofrezco esta solución Dynamic Occlusion es una herramienta que va mas allá que el uso de static batch, o static occlusion. Ademas que incluye muchos tipos de componentes a ser ocluidos como son trailRenderer, line Renderes, billboards incluye partículas, luces, sonidos y terrenos. controla la calidad del juego automáticamente para garantizar un buen desempeño y una experiencia suave para el usuario final. esta hecho para unity 4.5 free y pro o superior dc2851a2-3828-4b56-95dd-4684a10b6d48.xcf
  9. Primero que nada debes saber que esto no es una característica o función de Unity en realidad se trata de una TÉCNICA de optimización. En que consiste?Esta técnica consiste en instanciar un numero determinado de objetos al iniciar o cargar el nivel, luego desactivarlos para activarlos parcial o totalmente. Y esto tiene un impacto positivo en el rendimiento del videojuego ya que es mas barato en recursos activar y desactivar un objeto ya instanciado, que instanciar un objeto nuevo y destruirlo posteriormente. OJO que sea mas barato en recursos no quiere decir que deba usarse sin medida, ya que al activar el objeto el motor debe renderizar nuevamente el objeto como si de un objeto nuevo se tratase, pero con esto nos ahorramos la carga del objeto en memoria. Veamos un poco de código para aplicar esta técnica… 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144using System.Collections.Generic;using UnityEngine; namespace EMCore{ public abstract class PooledObject : MonoBehaviour, IPoolableObject { public static PooledObject current; public GameObject pooledObject; public bool willGrow = true; public int pooledAmount = 20; public List<GameObject> pooledObjects; public virtual void Awake() { current = this; } public virtual void Start() { pooledObjects = new List<GameObject>(); for (int i = 0; i < pooledAmount; i++) { GameObject obj = (GameObject)Instantiate(pooledObject); obj.transform.parent = transform.parent; obj.SetActive(false); pooledObjects.Add(obj); } } public virtual GameObject GetPooledObject(Vector3? position = null, Quaternion? rotation = null) { Vector3 _pos = Vector3.zero; Quaternion _rot = Quaternion.identity; if (position.HasValue) _pos = position.Value; if (rotation.HasValue) _rot = rotation.Value; for (int i = 0; i < pooledObjects.Count; i++) { if (pooledObjects == null) { GameObject obj = (GameObject)Instantiate(pooledObject, _pos, _rot); obj.transform.parent = transform.parent; if (obj) { PooledItem pooledItem = obj.GetComponent<PooledItem>(); if (pooledItem && pooledItem.noParent) { obj.transform.parent = null; } } obj.SetActive(false); pooledObjects = obj; return pooledObjects; } if (!pooledObjects.activeInHierarchy) { pooledObjects.transform.position = _pos; pooledObjects.transform.rotation = _rot; pooledObjects.transform.parent = transform.parent; if (pooledObjects) { PooledItem pooledItem = pooledObjects.GetComponent<PooledItem>(); if (pooledItem && pooledItem.noParent) { pooledObjects.transform.parent = null; } } return pooledObjects; } } if (willGrow) { GameObject obj = (GameObject)Instantiate(pooledObject, _pos, _rot); obj.transform.parent = transform.parent; if (obj) { PooledItem pooledItem = obj.GetComponent<PooledItem>(); if (pooledItem && pooledItem.noParent) { obj.transform.parent = null; } } pooledObjects.Add(obj); return obj; } return null; } GameObject IPoolableObject.pooledObject { get { return this.pooledObject; } set { this.pooledObject = value; } } bool IPoolableObject.willGrow { get { return this.willGrow; } set { this.willGrow = value; } } int IPoolableObject.pooledAmount { get { return this.pooledAmount; } set { this.pooledAmount = value; } } List<GameObject> IPoolableObject.pooledObjects { get { return this.pooledObjects; } set { this.pooledObjects = value; } } }}Podemos crear una clase la cual herede de esta y la adjuntamos en un objeto “vacío” en la escena y esta sera la encargada de manejar o gestionar la lista (variable de clase llamada “pooledObjects“) de objetos instanciados. Como podrán notar esta clase es abstracta, lo que nos obligara a usarla como padre de otra clase, es decir como dije anteriormente se debe crear una clase (BulletsManager por ejemplo) que herede de esta para usarla. Ademas también implementa una interface llamada “IPoolableObject” lo cual nos servirá, como mencione en el articulo “Porque usar POO(Programacion Orientada a Objetos) en la programación de videojuegos”, para tratar varias clases que también la implementen (BulletsManager y MuzzleManager) sin importar que clase sea, esto nos sera útil para reciclar código. También esta clase implementa un patrón “Singleton” de manera que se puede acceder a la instancia a través del miembro estático “current” de la siguiente manera, por ejemplo: 12BulletsManager bm = BulletsManager.current;Debug.Log(bm.pooledObjects.Count());La clase PooledObject también usa una clase llamada “PooledItem” que la muestro a continuación: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172using UnityEngine; namespace EMCore{ public abstract class PooledItem : MonoBehaviour, IPoolableItem { public bool autoDisable = true; public float timeToDisable = 2f; public bool noParent = false; public virtual void OnEnable() { if (autoDisable) { Invoke("Disable", timeToDisable); } if (noParent && transform.parent) { transform.parent = null; } } public virtual void Disable() { gameObject.SetActive(false); } public virtual void OnDisable() { if (autoDisable) { CancelInvoke(); } } bool IPoolableItem.autoDisable { get { return this.autoDisable; } set { this.autoDisable = value; } } float IPoolableItem.timeToDisable { get { return this.timeToDisable; } set { this.timeToDisable = value; } } bool IPoolableItem.noParent { get { return this.noParent; } set { this.noParent = value; } } }}Como pueden notar esta clase es abstracta y también implementa una interface llamada “IPoolableItem“, de igual forma se debera crear una clase que herede de esta para poder usarla. Ejemplifiquemos un poco como se podrían utilizar estas clases, imaginemos el entorno tal y como lo plantea la siguiente imagen:No voy a detenerme mucho a explicar el entorno porque es sencillo, básicamente es un FPSController con una capsula, donde el objeto weapon es un rectángulo, tag_bullet_spawn es un objeto vació de solo referencia, también podemos ver un objeto llamado “PoolingManager” en este podemos adjuntar todas nuestras clases que hereden de “PooledObject” de manera de tener nuestra escena organizada. Crearemos una clase llamada “BulletsManager” de la siguiente manera: 12345678910using System.Collections.Generic;using UnityEngine; namespace EMCore{ public class BulletsManager : PooledObject { }}Esta clase contendrá el listado de balas en la escena y se encargara de activarlas cuando el usuario lo necesite, ademas de esto no necesita implementar mas nada para el funcionamiento básico de esta técnica ya que hereda de “PooledObject“, pero también pudieran incluir su propio código en ella para añadirle funcionalidad especifica para gestionar las balas, noten que al ser una clase singleton esta debe ser única en la escena esto nos facilitara acceder y ademas nos permitirá tener en un mismo sitio el encargado de las balas en toda la escena, es decir que todos los actores que disparen lo harán a través de esta única clase e instancia (punto a favor de la optimización!). Ahora crearemos una clase que se deberá adjuntar en la bala, es decir el objeto que se repetirá y reciclara: 12345678910111213using UnityEngine; namespace EMCore{ public class Bullet : PooledItem { public float speed = 2; void Update() { transform.Translate(transform.forward * speed, Space.World); } }}Esta clase hereda de la clase “PooledItem” esta sera la encargada de desactivar el objeto y también implementa una funcionalidad en particular para el movimiento continuo hacia adelante de la bala. Por ultimo necesitaremos el arma para ello crearemos una clase llamadaWeapon: 12345678910111213141516171819202122232425262728293031using UnityEngine;using EMCore; public class Weapon : MonoBehaviour{ public Transform tagSpawn; public float fireTime = 0.05f; private bool firing = false; void Start () { InvokeRepeating("Fire", fireTime, fireTime); } void Update() { firing = Input.GetButton("Fire1"); } public void Fire() { if (firing) { GameObject obj = BulletsManager.current.GetPooledObject(tagSpawn.position, tagSpawn.rotation); if (obj == null) return; obj.SetActive(true); } }}Esta clase usa el método InvokeRepeating para, como se puede intuir de su nombre, llamar otra función cada cierto tiempo, ademas como mencione anteriormente se llama a la única instancia de BulletsManagera través de su miembro estático y el método “GetPooledObject” lo que hará es darnos el siguiente objeto disponible en el listado, recuerden que al iniciar el script se instancian la cantidad especificada en la propiedad “pooledAmount” de “BulletsManager” y el “prefab” se especifica en la propiedad “pooledObject” de “BulletsManager” y a medida queInvokeRepeating llame al método Fire de “Weapon” se irán activando, ademas si coloca en true la propiedad willGrow, esta lista podrá aumentar a medida de la demanda, ya que si la demanda es mayor al lo que especifique en pooledAmount habrá momentos en que se interrumpirá el reciclado ya que al estar todos los objetos en el listado (pooledObjects) activos, la clase debe espera a que un objeto PooledItem (es decir la bala) se desactive a si mismo. Espero hayan entendido la explicación y les sirva, les dejo a continuacion las interfaces IPoolableObject, y IPoolableItem usadas en este articulo: IPoolableObject 1234567891011121314151617181920using System.Collections.Generic;using UnityEngine; namespace EMCore{ public interface IPoolableObject { GameObject pooledObject { get; set; } bool willGrow { get; set; } int pooledAmount { get; set; } List<GameObject> pooledObjects { get; set; } void Awake(); void Start(); GameObject GetPooledObject(Vector3? position = null, Quaternion? rotation = null); }}IPoolableItem 123456789101112131415namespace EMCore{ public interface IPoolableItem { bool autoDisable { get; set; } float timeToDisable { get; set; } bool noParent { get; set; } void OnEnable(); void Disable(); void OnDisable(); }}Ademas les dejo materiales extras donde podrán ver con mayor detalle esta técnica o complementar la información: Modulo de Unity:https://unity3d.com/es/learn/tutorials/modules/beginner/live-training-archive/object-pooling Blog Recomendado:https://gamedevn.wordpress.com/2015/09/27/optimizacion-rendimiento-videojuego-object-pool-pattern/ Cualquier duda, sugerencia o corrección dejen su comentario! Saludos… fuente: https://eleazarcelis.wordpress.com/2015/11/20/comprendiendo-el-concepto-de-object-pooling
  10. Hola uniteros. Estaba estudiando la forma de crear un inventario para mi juego. Es un inventario grande, y subdividido en muchas categorias. Carga datos de archivos XML, al menos en la primera vez, quedando esta información guardada en memoria. Detecta el estado "Hover/Encima de", en sus botones para que muestre información con el puntero del mouse. Elejí hacerlo con elementos UI, ya que me permiten entre muchas cosas, detectar el estado Hover. Cargo alrededor de 50 casillas con la información de sus distintos objetos y 5 pestañas que me llevan a otros inventarios, destruyendo los anteriores y generando los posteriores. El caso que quizas lo vea pesado en rendimiento, ya que el juego pega un bajón de FPS aunque solo sea en un segundo, cuando lo invoco y/o cuando destruye todos los objetos. - Quería saber la mejor forma de optimización, con inventarios complejos. (UI...GUI...etc..) - ¿Cuando cierro el inventario, o cambio de pestañas, es mejor destruir los objetos o desactivarlos? - La información obtenida de todos los objetos, ¿es mejor tenerla en memoria una vez cerrado el inventario? En algunos casos no necesito retener en memoria toda la información de los objetos y he pensado que cada vez guarde esa info en un XML para su posterior leida. Un saludo.
  11. Hola a todos. Hace ya un tiempo que uso unity, soy programador y con la api de unity me es mas que suficiente para poder hacer lo que deseo. Trato de optimizar recursos lo mas que puedo en uso de gpu en los scripts por ejemplo haciendo algoritmos de orden constante y evitando que el recolector de basura pase muy seguido. Sin embargo, si bien puedo hacer juegos para pc, al momento de compilar mi juego para dispositivo android todo anda super lento, las texturas y demás no mantienen un color fijo(como que por ahi salen rallas en el juego o puntos negros). Cuando muevo un objeto por ejemplo en la pc se mueve suabemente pero en el teléfono no. Se que esto es porque yo hago que se mueva 1 unidad por segundo por ejemplo(usando Time.deltaTime) y en la pc tengo entre 60-70 fps mientras que en un SO android esto se hace en 30 fps. -Para no instanciar objetos constantemente(como podrian ser las balas de las torres en el TD que estoy haciendo) uso pools de objetos, asi lo unico que hago es moverlos dentro o fuera de la ecena segun los necesito. -Se que los terrenos consumen muchísimos recursos por la cantidad de polígonos que tienen asi que no los uso(por ahora este td lo estoy haciendo solo con las formas geométricas que trae unity y luego haré los modelos 3d con la menor cantidad de polígonos posibles) -etc O sea me trato de cuidar con los recursos lo máximo posible pero sin embargo el desempeño de mis juego es asqueroso comparado con otros juegos en la tienda de google Las preguntas serian: 1-Veo que los juegos en la tienda logran un desplazamiento agradable a la vista y que no va a tirones.Como puedo lograr eso con mis juegos? 2-cual seria la cantidad de polígonos totales en la escena para que el juego corra bien en un dispositivo android? 3-Imágenes y texturas(todo lo que puedan explicarme acerca de que texturas tengo que usar para que se vean bien en android y a la vez que no gasten recursos excesivos). Por ejemplo resoluciones y formatos de imagenes, y como tratarlas dentro de unity para lograr un rendimiento óptimo 4-Musica:que formato usar? habia usado para uno de mis juegos musica en diferentes formatos pero hacian que la escena tardara mucho en cargarse.Si les bajaba la calidad se escuchaban muy feo aunque tardaban menos en cargarse 5-Partículas: Seria genial poder hacer que algunas torretas disparen balas de fuego por ejemplo, pero cuando le pongo el sistema de partículas a las balas, como se podrán imaginar el juego en el teléfono va super lento. Como tengo que hacer para poder usar un sistema de partículas en android? o sea con que cosas me tengo que cuidar para que no consuma tantos recursos?Veo que muchos juegos usan partículas o ciertas animaciones que parecen partículas en forma continua y andan muy bien. 6- Sombras luces y demas.Hasta que punto y cantidades puedo usar estos elementos? Todo lo que sepan que puedan explicarme sobre como hacer que un juego ande bien en android y poder desarrollar a nivel profecional es agradecido desde ya. Muchas gracias desde ya a todos los que respondan.Todo lo que sepan y puedan decirme siempre viene bien!!! PD: Los juegos los pruebo en mi telefono android que es un telefono promedio de gama media-alta.
  12. Buenas, quería aportar algo. Tal vez lo sepan, pero yo no lo sabía, y probando las cosas logré aumentar los FPS de mi juego de 60 a 80. Recomiendo esto en juegos orientados a dispositivos móviles, porque puede afectar un poco a la calidad gráfica pero incrementa drásticamente el rendimiento. Mi juego es un MOBA, lo que hice son varios prefabs, y para que se distinga el color de las torres y demás según el equipo utilicé luces. El tema de las luces es que consumen mucho rendimiento. Es ahí cuando descubrí el baking. El baking básicamente consiste en pre-renderizar las luces estáticas, generando una textura que se aplica al juego, simulando las luces previamente creadas. ¿Por qué aumenta el rendimiento? Porque no está renderizando dichas luces en tiempo real, sino que lo hace una vez. Es recomendable usar Baking con luces de cosas estáticas, como edificios, ambiente, etc. ¿Cómo hice para usar baking? En primer lugar, a las quichicientas luces estáticas que creé, les modifiqué "Baking", por default es "Mixed", lo cambié a "Baked". En segundo lugar, lo que hice fue abrir la ventana de luces "Window -> Lighting", luego ir a la pestaña Scenes de esa ventana y modificar la forma de Iluminación Global (dado que en este tipo de juegos no hace mucha diferencia que sea en tiempo real, sobre todo porque quiero destinarlo a dispositivos móviles).En donde dice "Ambient GI" modifiqué de "Realtime" a "Baked". Finalmente, construí el Lightmap de mi nivel, el Lightmap sería plasmar en archivos el pre-procesamiento de la iluminación global del nivel. Para ello, en la misma ventana de Lighting vas a la pestaña "Lightmaps", desactivás el check de abajo a la derecha que dice "Continuous baking", y luego hacés click en "Build". Esto puede llevar un rato. Luego de eso, corran el juego y verán la diferencia de rendimiento. Importante: si modifican las propiedades de las luces, agregan o quitan luces, deben otra vez hacer "Build" al Lightmap. Nada más, espero su feedback! y obviamente que les sirva! Saludos!
×
×
  • Create New...