Jump to content
Sign in to follow this  
  • entries
    5
  • comments
    0
  • views
    341

Pool Object

Sign in to follow this  
francoe1

101 views

Problemática

La parte más compleja del desarrollo de un juego es mantener el rendimiento del mismo a medida que esté escala, la técnica del pool object nos permite reutilizar objetos ya creados, esto evita generar basura y omite los costos de creación del mismo. Se suele utilizar para cosas a groso modo, pero tambien se puede y debe utilizar cada vez que detectemos que en nuestro código se están creando y destruyendo objetos dentro del mismo bloque. 

Ejemplo

public void Method()
{
  for (int i = 0; i < Items.Count(); i ++)
  { 	
    ItemProcessor processor  = new ItemProcessor();
    Items[i].Process(processor);
  }
}

En el ejemplo se puede ver que ItemProcessor se crea en cada iteración del bucle, al finalizar esa iteración el objeto se marca para ser eliminado cuando pase el recolector de basura. Si esta función se utiliza muchas veces a lo largo del juego obtendremos como resultado bajadas de frames cada x cantidad de tiempo. 


Implementación

Existen múltiples formas de implementar un sistema de PoolObject, en este blog intentaré explicar la mas optima, abstracta y escalable. 

  1. Definimos una IRecyclable, esta tendrá la definición para saber si esta disponible, la función de reciclar y restaurar.
    public interface IRecyclable
    {
      bool IsAvailable();
      void Recycle();
      void Restore();
    }

     

  2. Creamos la clase PoolObject

    Spoiler
    
    public class PoolObject
    {
      private IRecyclable[] m_objects { get; set; }
    
      public delegate IRecyclable CreateObjectDelegate();
      public CreateObjectDelegate CreateObjectHanlder { private get; set; }
    
      public PoolObject(int capacity)
      {
        m_objects = new IRecyclable[capacity];            
      }
    
      public void RecicleAll()
      {
        foreach (IRecyclable element in Query(x => !x.IsAvailable()))
          element.Recycle();
      }
    
      public IRecyclable GetObject()
      {
        IRecyclable query = SingleOrDefault(x => x.IsAvailable());
        if (query is null)
        {
          int index = GetEmptyIndex();
          if (index == -1) throw new Exception("Poolobject se quedo sin espacio");
          query = CreateObjectHanlder();
          m_objects[index] = query;
        }
        return query;
      }
    
      public IEnumerable<IRecyclable> Query(Func<IRecyclable, bool> query)
      {
        for (int i = 0; i < m_objects.Length; i++)
          if (m_objects[i] is object && query(m_objects[i]))
          yield return m_objects[i];
      }
    
      private IRecyclable SingleOrDefault(Func<IRecyclable, bool> query)
      {
        for (int i = 0; i < m_objects.Length; i++)
          if (m_objects[i] is object && query(m_objects[i]))
          return m_objects[i];
        return default;
      }
    
      private int GetEmptyIndex()
      {
        for (int i = 0; i < m_objects.Length; i++)
          if (m_objects[i] is null)
          return i;
        return -1;
      }
    }

     

    La implementacion cuenta de un arreglo que define su tamaño dentro del constructor, Luego cuenta con funciones para trabajar con el arreglo de forma óptima y estructurada, la compresión del algoritmo no requiere más explicaciones. Cada vez que se crea un Objecto se llama el handler "CreateObjectHandler".

  3. Implementamos la interface IRecyclable según la necesidad del proyecto.


Ejemplos

Aplicado a ItemProcessor una clase limpia sin herencias.

public class ItemProccesor : IRecyclable
{
  private bool m_isAvailable { get; set; }
  public int Pass { get; set; }

  public bool IsAvailable()
  {
    return m_isAvailable;
  }

  public void Recycle()
  {
    m_isAvailable = true;
    Pass = 0;
  }

  public void Restore()
  {
    m_isAvailable = false;
  }
}

Usando PoolObject

PoolObject pool = new PoolObject(5);
pool.CreateObjectHanlder = () => new ItemProccesor();

for (int i = 0; i < 2; i++)
{
  ItemProccesor item = (ItemProccesor)pool.GetObject();
  item.Pass += 1;
}

for (int i = 0; i < 2; i++)
{
  ItemProccesor item = (ItemProccesor)pool.GetObject();
  item.Pass += 1;
  item.Recycle();
}

pool.RecicleAll();

 


Conclusión 

Esta implementación se mantiene abstracta lo que permite escalar y ser implementada en cualquier ámbito, la delegación del estado nos da un completo control.

 

 

Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

UnitySpain © Todos los derechos reservados 2020
×
×
  • Create New...