Showing posts with label Xna. Show all posts
Showing posts with label Xna. Show all posts

Friday, October 19, 2012

Intrusive linked node

Dealing with large number of objects can be tasking, specially in games, traditionally we have our objects living in some sort of collection, and then we traverse this collection to perform a task (like Update() or Draw()).

Collections work amazingly, traditionally I seen that the generic List is used the most, I use them often, but I stopped using them to managed my objects, simply because of how slow and tasking the "Remove()" function was, let me explain this:

when you have a collection of 10 elements in a List, and you decide to remove element 4, you would have to shift the following 6 elements down a slot to keep the list continuous, since the list is just a glorified "array", this can be very expensive, imagine if you were to remove element 1 in a list that contains 10,000 elements, not fun.

Linked list in the other hand do a much nicer job for removing elements, since they know what's next and what was previously, I would suggest to use linked list when you don't need to access an specific element in a collection, linked list do not work nicely when trying to "find" things inside them, because they are not indexed, you would have to check from start to end for an element using some comparison check on every single element, not fun.

Currently in my game, I use my own "collections" which are very specific, I have an "Actor Node" which takes care of the actors, like this:

public class ActorNode
    {
        public IActor Subject;
        public ActorNode SelfReference;
        public ActorNode NextActor;
        public ActorNode PreviousActor;

        public static ActorNode Head;

        public ActorNode(IActor subject)
        {
            SelfReference = this;
            Subject = subject;
        }

        public void Activate()
        {
            if (Head != null)
            {
                Head.PreviousActor = SelfReference;
                NextActor = Head;
            }
            Head = SelfReference;
        }

        public void Deactivate()
        {
            if (PreviousActor == null) //check for head
            {
                if (NextActor != null)
                {
                    Head = NextActor;
                    NextActor.PreviousActor = null;
                }
                else
                {
                    Head = null;
                }
            }
            else
            {
                if (NextActor != null) //check for tail
                {
                    NextActor.PreviousActor = PreviousActor;
                    PreviousActor.NextActor = NextActor;

                    NextActor = null;
                    PreviousActor = null;
                }
                else
                {
                    PreviousActor.NextActor = null;
                }
            }

            PreviousActor = null;
            NextActor = null;
        }
    }


This Node is a "component" of my actors, meaning that they live inside my actor class, using my factory design pattern (check last post for reference) I easily activate them, and using my Recycle method (also last post) I deactivate them before returning them to the pool, like this:

public class AnActor: PooleanNode<AnActor>, IActor, Irecycle
{
    LinkedPoolean<AnActor> Pool = new LinkedPoolean<AnActor>();
    
    ActorNode ActorLink;    

    public AnActor()
    {
        ActorLink = new ActorNode(this);
    }

    public static void Create()
    {   
        AnActor Vessel;
        Pool.Get(out Vessel);
        Vessel.ActorLink.Activate(); //Activates the node so it is in the collection
    }

    public void Recycle()
    {
        ActorLink.Deactivate(); //deactivates the node so it is taken out.
        Pool.ReturnPoolable(this);
    }
}


Now, let's assume that the "IActor" interface contains a method called "Update()", we can use this collection to update all the currently activated actors like this:

public static void UpdateAll() //function that updates all the actors
{
     ActorNode Current = ActorNode.Head; //gets the current head
     if(Current == null) //make sure there are elements in the collection
     {
         return; //if there's nothing, then get out.
     }
     IActor CurrentActor; //container for the current subject that needs to update

     do
     {
          CurrentActor = Current.Subject; //get the first subject
          
          CurrentActor.Update(); //Update it and then

          Current = Current.NextActor; //check for the next node

     } while (Current != null); //and if that node is not null, then repeat.
}

That function will make sure that all the activated nodes will update.

Thanks for reading.







My Factory Design Pattern

I will talk a bit about how I create my "Game objects".

The first thing you need to know is that I do not use the keyword "New" to instantiate a new object, this is because I need to have control over my game objects (coming from the pools), Let's create a quick example, I am going to assume that you know about my pool system, but if you don't please take a look at the previous post.

We will start with the body of the class.

public class Slime: PooleanNode<Slime> 
{
    static LinkedPoolean<Slime> Pool = new LinkedPoolean<Slime>();

    public Slime()
    {
    }
}

Here we have declared a "Slime class" that can be pooled with my pool class, as you can see the constructor is public so we can instantiate them with the activator class, also there's a static pool of slimes living inside this class, this will mean that in every single slime object you will have access to the same pool, this is important cause all the slimes need to come from the pool, now moving into the "creational" method.

public static Slime Create() //this function must live inside the slime class.
{
    Slime Vessel;
    Pool.Get(out Vessel); //if it doesn't live inside the class, the pool wouldn't be
    return Vessel;        //visible, you would have to make it public and access it
}                         //like "Slime.Pool", I don't recommend that. 

And done, we have create an static method that will take slimes out of the pool and return them, simple as that! now for some logic on why I do this, by making a new slime this way I make sure they come from the pool and that they are not generated outside of the pool, this is handy when we want to manage them and when we want to avoid tasking the garbage collector, since we are not allocating new memory.

Now let's expand on it, to make it useful, you can declare multiple creation methods to obtain different results, let's say that the Slime has some fields like position or maybe current hit points, etc, we can modify these elements like this:

public class Slime: PooleanNode<Slime> 
{
    static LinkedPoolean<Slime> Pool = new LinkedPoolean<Slime>();

    Vector2 Position;
    int HP;

    public Slime()
    {
        Position = Vector2.Zero;
        HP = 1;
    }

    public static Slime Create(Vector2 Position, int HP) 
    {
        Slime Vessel;
        Pool.Get(out Vessel); 
        Vessel.Position = Position;
        Vessel.HP = HP;
        return Vessel;       
    } 
}

By default the slime starts at position 0,0 and with 1 HP, but we can create any slime anywhere we want as well as giving it any amount of HP we want, we can create more methods to define things ever further.

Lastly I define a recycle method that I use when I need to get rid of the object and sent it back to the pool, like this:

public void Recycle()
{
    Pool.ReturnPoolable(this);
}

That makes sure that the object is sent back into the pool to be reused by the factory method, this is an overly simplified version of what I use in my current game, if you would like to check the game out, here:

Game

Thanks for reading!

Monday, October 15, 2012

Taking casting out of the picture

Once again! I have done another revision to the way I am doing pools, it is almost like an obsession, in any case, it has proven to be fantastic, onto the code:

public class LinkedPoolean<T> where T : PooleanNode<T>, new()
    {
        public T Head;

        public LinkedPoolean()
        {
            Head = Activator.CreateInstance<T>();
        }

        public void Get(out T Vessel)
        {
            if (Head != null)
            {
                Vessel = Head;
                Head = Head.Next;
            }
            else
            {
                Vessel = Activator.CreateInstance<T>();
            }
         
        }

        public void ReturnPoolable(T Return)
        {
            Return.Next = Head;
            Head = Return;
        }
    }

The Key change here is the way we access the "Activator", you see, there's a function to create an instance that takes a Generic parameter T, and there's another version of the function that takes an argument "Type" and returns an "Object", the object returned by the second function is sadly not the right type, so in order to use it I used to cast it, this would create a hit on the performance. The function that takes a parameter of type T returns an object of type T, making casting unnecessary.

This improvement was only possible though if the PooleanNode knew which "kind of poolean node" it was, new Poolean node class:

public class PooleanNode<T> where T: PooleanNode<T>
    {
        public T Next;
    }


This in turn makes the poolean node type safe, before hand it was potentially possible to subscribe a poolean node into a pool of another type, it was kind of weird at the beginning to see a class expecting itself to be the template, but it is kind of cool the way it works.

Thanks for reading~

Friday, August 17, 2012

New Poolean

Looking back to when I made my first "Pool" (called Poolean) and the reasons why I made it the way it was I came to realize I was trying to avoid using "List.Remove(T)" besides avoiding to create new elements every time something was needed.
Some time after that I stumbled upon a performance problem that was going to 
hinder my game if the number of elements to be managed was going to be big, let'ssay that a pool is used a lot, meaning that the elements within the pool are
almost always "In use" and often the pool requires to expand (create new elementsto accommodate demand). Following the way the pool used to work, I would have to check if the "next" element was free, and if it was not continue until I ran out of space, then I started back from 0 to right before the element I just used, andif nothing was available then expand the pool.
The problem with this is that if I want something that requires big numbers (likeparticles) it would get hairy real quick.
I was trying to make a class that could hold a collection of objects and be able to remove the objects without having to shift things around (like List.Remove(T) does) because once again that would be very slow, I came with the idea of removing the certain element and swapping the last element in the collection to the position of the element we just removed, putting the count down by one and that would be all, in order to do this, the object I wanted to use in this "Collection" would have to contain an interface that allows access to certain index number, just a simple property to know in which position the element is in the collection. This methodology could fix my Poolean issue, by knowing how many items are in the pool, and knowing I always remove the last one, this made the entire "Searching for the next element" completely obsolete, which made me happy, so now the new Poolean looks like this:    


public class Poolean<T> where T: new()
    {
        public T[] Pool;
        public int Size;
        public int GrowthAmount;
        public int CurrentFreeIndex;
        public Type TypeOfT;

        public Poolean(int size, int Growth)
        {
            CurrentFreeIndex = size - 1;
            GrowthAmount = Growth;
            TypeOfT = typeof(T);

            Pool = new T[size];

            Size = size;

            for (int i = 0; i < Size; i++)
            {
                T NewElement = (T)Activator.CreateInstance(TypeOfT);
                Pool[i] = NewElement;
            }
        }

        public void Get(out T Vessel)
        {
            if (CurrentFreeIndex > -1)
            {
                Vessel = (T)Pool[CurrentFreeIndex];
                Pool[CurrentFreeIndex] = default(T);
                CurrentFreeIndex--;
            }
            else
            {
                //Expand
                CurrentFreeIndex += GrowthAmount;
                Size += GrowthAmount;
                Pool = new T[Size];
                for (int i = 0; i < GrowthAmount; i++)
                {
                    T NewItem = (T)Activator.CreateInstance(TypeOfT);
                    Pool[i] = NewItem;
                }

                //try again
                Vessel = (T)Pool[CurrentFreeIndex];
                Pool[CurrentFreeIndex] = default(T);
                CurrentFreeIndex--;
            }
        }

        public void ReturnPoolable(T Poolable)
        {
            CurrentFreeIndex++;
            Pool[CurrentFreeIndex] = Poolable;
        }
    }


As you can see it is a lot shorted and easier to understand, let's go over the Constructor first, in the constructor you specify how many elements do you want in the pool to begin with and in the event that the pool runs out of space, how many elements you want to add, pretty simple, there we define what type T is and then we populate the array of Ts with objects of type T. Then we have the "Get" function which takes an element out of the pool if it has any left and if it doesn't it expands, and finally we have the "ReturnPoolable" which adds the element back to the pool and gets the count up by one.

This made the pool lightning faster, but I hope I come up with an idea to make it even faster.

Monday, April 16, 2012

Entity Pooling

Memory allocation in run time can be pretty heavy depending on how much you do it, getting rid of objects every loop will trigger the garbage collector (at 1 MB in the Xbox) often making you get lag spikes once in a while.

I encountered this issue with my engine, where entities were being created and deleted almost every frame, this made the lag unbearable. I knew from the start I had to pool the entities, so I did using this method:

static List EntityList = new List();

public static void GetEntity(out Entity Returnee)
{
        int Count = EntityList.Count;
        if(Count > 0)
        {
                  Returnee = EntityList[Count - 1];
                  EntityList.Remove(Returnee);
         }
         else
         {
                  Returnee = new Entity();
          }
}


Something I am not showing here is the way to return the entities to the list, that's by simply re adding them to list of entities, trivial.



The main issue with this way of pooling is that you are required to remove things from a list, this could get heavy if the list gets bigger, but for the time this method did improve my overall performance I thought I was happy with the results, until one day one of my class mates said something about how a pool can know what the next available index was instead of taking things out of a list, this made me really curious and I went on that to find a better way of pooling.

What I found is that removing things from the list was just wasteful and not necessarily, if I knew the next available index I could use that instead of removing the ones that were being used, this was possible by creating a base object that represents an item that can be activated when in the pool and "deactivated" or "unavailable" when "not" in the pool ("" because it is always in the pool at all times), the new pool looks like this:

public class Poolean where T: Poolable, new()
    {
        private List Pool;
        int MaxCount;
        int CurrentFreeIndex;
        bool SpecificType;
        Type ElementType;

        public Poolean(int BufferSize)
        {
            SpecificType = false;
            Pool = new List(BufferSize);
            MaxCount = 0;
            CurrentFreeIndex = 0;
            ExpandPool(BufferSize);
            
        }

        public Poolean(int BufferSize, Type typeOfElement)
        {
            ElementType = typeOfElement;
            SpecificType = true;
            Pool = new List(BufferSize);
            MaxCount = 0;
            CurrentFreeIndex = 0;
            ExpandPool(BufferSize);
        }

        private void ExpandPool(int size)
        {
            int start = MaxCount;
            MaxCount += size;

            if (SpecificType)
            {
                for (int i = start; i < MaxCount; i++)
                {
                    T NewPoolElement = (T)Activator.CreateInstance(ElementType);
                    NewPoolElement.Index = i;
                    NewPoolElement.InUse = false;
                    Pool.Add(NewPoolElement);
                }
            }
            else
            {
                
                for (int i = start; i < MaxCount; i++)
                {
                    T NewPoolElement = new T();
                    NewPoolElement.Index = i;
                    NewPoolElement.InUse = false;
                    Pool.Add(NewPoolElement);
                }
            }
        }

        public void ReturnPoolable(Poolable returnee)
        {
            returnee.InUse = false;
        }

        public void GetPoolable(out T vessel)
        {
            vessel = (T)Pool[CurrentFreeIndex];
            vessel.InUse = true;

            //find ther next available item
            int Next = vessel.Index + 1;
            GetNextAvailableElement(Next);
        }

        private void GetNextAvailableElement(int LastPlusOne)
        {
            for (int NextInLine = LastPlusOne; NextInLine < MaxCount; NextInLine++)
            {
                Poolable Current = Pool[NextInLine];
                if (!Current.InUse)
                {
                    CurrentFreeIndex = Current.Index;
                    return;
                }
            }

            //if it gets here then we need to start from the beginning of the list until we reach the last "Next", if this happens, 
            //then all elements are being used in the list, we need to increase the size of the list.

            for (int Start = 0; Start < LastPlusOne - 1; Start++)
            {
                Poolable Current = Pool[Start];
                if (!Current.InUse)
                {
                    CurrentFreeIndex = Current.Index;
                    return;
                }
            }

            //if we still here... then yes all the elements are being use, you need to inscrease the size of the pool.

            ExpandPool(MaxCount);
            GetNextAvailableElement(LastPlusOne);
        }
   
    }

As you can see, the new pool return references to the element in the pool, but it never ever removes that reference from the pool itself, instead it makes its "used" tag true, and looks for the next available from the index that was just taken out, in case the pool ever runs out of elements, it will double its size to continue working properly. A poolable base class looks like this:
public class Poolable
    {
        public int Index;
        public bool InUse;

        public Poolable()
        {

        }
    }


Real simple!


Well that's the cool thing I learned today, now all my entities are created really much much faster.