Jump to content
UnitySpain

Aceptamos donaciones vía Paypal.

UnitySpain.com es un servicio gratuito, pero mantener la Comunidad conlleva una serie de gastos.

Fondo Anual Unityspain: Donados 15,00€ de 150,00€

  • Servidor: Dominio.com y Hosting Web
  • Mantenimiento de los Foros
  • Contenido y Servicios Extras
  • Mantenimiento para Redes Sociales

Search the Community

Showing results for tags 'object pooling'.



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

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 2 results

  1. 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!
  2. 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
×
×
  • Create New...