{"id":347,"date":"2011-09-10T15:48:36","date_gmt":"2011-09-10T14:48:36","guid":{"rendered":"http:\/\/www.aymericlamboley.fr\/blog\/?p=347"},"modified":"2014-11-01T15:03:22","modified_gmt":"2014-11-01T14:03:22","slug":"doubly-linked-list-and-object-pooling","status":"publish","type":"post","link":"http:\/\/www.aymericlamboley.fr\/blog\/doubly-linked-list-and-object-pooling\/","title":{"rendered":"Doubly linked list and object pooling"},"content":{"rendered":"<p>After holidays, it&#8217;s time to get back to work \ud83d\ude42<br \/>\nI was really busy last month, so this is some news on what I did and what is going on :<\/p>\n<p>&#8211; I&#8217;ve made some experiments with the Citrus Engine on the Hero adding some functionality. But what appears is the Hero class becomes more and more complex&#8230; So I asked its creator if he knows a system\/model which has a modular way to add features to the hero. And he gives me some information about the <strong>Entity\/Component model<\/strong>. Woah, it is awesome! It&#8217;s really a new way of thinking about programming. No more OOP. This is 3 useful links\/resources if you are interested : <a target=\"_blank\" href=\"http:\/\/www.gamasutra.com\/blogs\/MeganFox\/20101208\/6590\/Game_Engines_101_The_EntityComponent_Model.php\">Gamasutra the Entity Component Model<\/a>, <a href=\"http:\/\/t-machine.org\/index.php\/2007\/09\/03\/entity-systems-are-the-future-of-mmog-development-part-1\/\" target=\"_blank\">Entity Systems are the future of MMOG development<\/a>, <a href=\"http:\/\/www.tomseysdavies.com\/2011\/01\/23\/entity-systems\/\" target=\"_blank\">Entity Systems<\/a>. This links are very interesting, but there isn&#8217;t any implementation. You can find implementations with the <a href=\"http:\/\/pushbuttonengine.com\/\" target=\"_blank\">PushButton Engine (flash)<\/a>, <a href=\"http:\/\/gamadu.com\/artemis\/\" target=\"_blank\">Artemis (java)<\/a>. However it is really complex, so I was not able to create a Component\/Entity System for the CE due to my lack of experience&#8230; but if its creator has time, he will do!<\/p>\n<p>&#8211; I was in holidays at Praha (Czech Republic), amazing city\/country! And beer is really cheap \ud83d\ude42<\/p>\n<p>&#8211; I&#8217;m currently reading the book of <a href=\"http:\/\/www.jesseschell.com\/\" target=\"_blank\">Jesse Schell<\/a>, <a href=\"http:\/\/artofgamedesign.com\/\" target=\"_blank\">The Art of Game Design<\/a> it&#8217;s a masterpiece! Really, really interesting, lots of awesome advices. Approved &#038; Recommended!<\/p>\n<p>&#8211; I&#8217;m working\/designing my next portfolio. It will be nice&#8230; \ud83d\ude09<\/p>\n<p>&#8211; On Thursday 15 September, I go back to the Gobelins school! And I will make a point with Tiffany about <a href=\"http:\/\/kinessia.aymericlamboley.fr\/\" target=\"_blank\">Kinessia<\/a>. We are thinking to create the game for mobile. I hope we will have enough time (there are already lots of project at school&#8230;), so stay tuned!<\/p>\n<p>&#8211; Mobile, tablet and game design\/programming is interesting me more and even more. This is two good links on mobile game programming : <a href=\"http:\/\/sierakowski.eu\/list-of-tips\/82-starting-with-air-for-android-and-ios-building-one-app-for-both-platforms.html\" target=\"_blank\">Starting with AIR for Android and iOS &#8211; building one app for both platforms<\/a>, and <a href=\"http:\/\/sierakowski.eu\/list-of-tips\/86-building-mobile-games-in-adobe-air-optimization-techniques-used-in-jumping-droid-game.html\" target=\"_blank\">Building mobile games in Adobe AIR &#8211; optimization techniques<\/a>.<\/p>\n<p>&#8211; And finally I&#8217;m also waiting <a href=\"http:\/\/fdt5.com\/\" target=\"_blank\">FDT5<\/a> to invest more time in <a href=\"http:\/\/haxe.org\/\" target=\"_blank\">haXe<\/a> and WebGL!<\/p>\n<p>I think it&#8217;s enough for the news at the moment! Now it&#8217;s time to speak about the topic, this week I wanted to make some algorithms, doubly linked list and object pooling are a good exercice. <a href=\"http:\/\/www.aymericlamboley.fr\/blog\/recursivity-and-data-structures\/\" target=\"_blank\">Previously<\/a> I made an oral in my school to introduce recurisivity and data structures (<a href=\"http:\/\/www.aymericlamboley.fr\/blog\/wp-content\/uploads\/2011\/01\/recusivity-and-data-structures.pdf\" target=\"_blank\">pdf link in french<\/a>). Doubly linked list and object pooling are techniques optimizations used in game development and especially on mobile devices.<\/p>\n<p><!--more--><\/p>\n<p>A Linked List is a data structure consisting of a group of nodes which together represent a sequence. Each node is composed of a data and a reference (a link) to the next node in the sequence. Whereas we use index to access a specific element in an array (myArray[2]), we are blind in a linked list. We know the first and the last element, that&#8217;s all. If we want to access to the 3 element, we need to go through our linked list and stop on the element : head.next.next.data<br \/>\nThis is simple function to do that :<\/p>\n<pre lang=\"actionscript3\">var count:uint = 1;\r\nvar tmpHead:Node = head;\r\n\r\nwhile (count < 3) {\r\n\ttmpHead = tmpHead.next;\r\n\t++count;\r\n}\r\n\r\nreturn tmpHead.data;<\/pre>\n<p>So what are the interests of the linked list? Why we should use them?<br \/>\nIf we have only some elements, we shouldn't use a linked list. Yet if we have many elements and make many operations (add\/remove in head or tail) on them, we should use one. Indeed when we use the unshift method in an array (to add an element to the beginning of the array), each index are moved. If we have an array with 5 000 000 elements and we add\/remove first elements in an EnterFrame (so 30 times by second), we imagine easily the performance problem. With a linked list you just add\/remove an element without moving all index!<br \/>\nMore informations on <a href=\"http:\/\/en.wikipedia.org\/wiki\/Linked_list\" target=\"_blank\">wikipedia<\/a>.<\/p>\n<p>Let's start coding, this is my implementation of a doubly linked list and a node :<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package alamboley.datastructures {\r\n\t\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class DoublyLinkedListNode {\r\n\t\t\r\n\t\tpublic var data:*;\r\n\t\tpublic var next:DoublyLinkedListNode;\r\n\t\tpublic var prev:DoublyLinkedListNode;\r\n\t\t\r\n\t\t\/**\r\n\t\t * A simple data node used for DoubleLinkedList and Pool\r\n\t\t * @param obj untyped data stored in the node\r\n\t\t *\/\r\n\t\tpublic function DoublyLinkedListNode(obj:* = null) {\r\n\t\t\t\r\n\t\t\tnext = prev = null;\r\n\t\t\tdata = obj;\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<pre lang=\"actionscript3\" line=\"1\">package alamboley.datastructures {\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class DoublyLinkedList {\r\n\r\n\t\tpublic var head:DoublyLinkedListNode;\r\n\t\tpublic var tail:DoublyLinkedListNode;\r\n\r\n\t\tprotected var _count:uint;\r\n\r\n\t\tpublic function DoublyLinkedList() {\r\n\r\n\t\t\thead = tail = null;\r\n\t\t\t_count = 0;\r\n\t\t}\r\n\r\n\t\t\/**\r\n\t\t * Append an object to the list.\r\n\t\t * @param data an object of any type added at the end of the list.\r\n\t\t * @return returns the tail.\r\n\t\t *\/\r\n\t\tpublic function append(data:*):DoublyLinkedListNode {\r\n\r\n\t\t\tvar node:DoublyLinkedListNode = new DoublyLinkedListNode(data);\r\n\r\n\t\t\tif (tail != null) {\r\n\r\n\t\t\t\ttail.next = node;\r\n\t\t\t\tnode.prev = tail;\r\n\t\t\t\ttail = node;\r\n\r\n\t\t\t} else {\r\n\t\t\t\thead = tail = node;\r\n\t\t\t}\r\n\r\n\t\t\t++_count;\r\n\r\n\t\t\treturn tail;\r\n\t\t}\r\n\r\n\t\t\/**\r\n\t\t * Append a node to the list.\r\n\t\t * @param node a DoubleLinkedListNode object of any type added at the end of the list.\r\n\t\t * @return returns the doubleLinkedList.\r\n\t\t *\/\r\n\t\tpublic function appendNode(node:DoublyLinkedListNode):DoublyLinkedList {\r\n\r\n\t\t\tif (head != null) {\r\n\r\n\t\t\t\ttail.next = node;\r\n\t\t\t\tnode.prev = tail;\r\n\t\t\t\ttail = node;\r\n\r\n\t\t\t} else {\r\n\t\t\t\thead = tail = node;\r\n\t\t\t}\r\n\r\n\r\n\t\t\t++_count;\r\n\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\t\/**\r\n\t\t * Prepend an object to the list.\r\n\t\t * @param data an object of any type added at the beginning of the list.\r\n\t\t * @return returns the head.\r\n\t\t *\/\r\n\t\tpublic function prepend(data:*):DoublyLinkedListNode {\r\n\r\n\t\t\tvar node:DoublyLinkedListNode = new DoublyLinkedListNode(data);\r\n\r\n\t\t\tif (head != null) {\r\n\r\n\t\t\t\thead.prev = node;\r\n\t\t\t\tnode.next = head;\r\n\t\t\t\thead = node;\r\n\r\n\t\t\t} else {\r\n\t\t\t\thead = tail = node;\r\n\t\t\t}\r\n\r\n\t\t\t++_count;\r\n\r\n\t\t\treturn head;\r\n\t\t}\r\n\r\n\t\t\/**\r\n\t\t * Prepend a node to the list.\r\n\t\t * @param data an object of any type added at the beginning of the list.\r\n\t\t * @return returns the doubleLinkedList.\r\n\t\t *\/\r\n\t\tpublic function prependNode(node:DoublyLinkedListNode):DoublyLinkedList {\r\n\r\n\t\t\tif (head != null) {\r\n\r\n\t\t\t\thead.prev = node;\r\n\t\t\t\tnode.next = head;\r\n\t\t\t\thead = node;\r\n\r\n\t\t\t} else {\r\n\t\t\t\thead = tail = node;\r\n\t\t\t}\r\n\r\n\t\t\t++_count;\r\n\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\t\/**\r\n\t\t * Remove a node from the list and return its data.\r\n\t\t * @param node the node to remove from the list.\r\n\t\t * @return returns the removed node data.\r\n\t\t *\/\r\n\r\n\t\tpublic function removeNode(node:DoublyLinkedListNode):* {\r\n\r\n\t\t\tvar data:* = node.data;\r\n\r\n\t\t\tif (node == head) {\r\n\r\n\t\t\t\tremoveHead();\r\n\r\n\t\t\t} else {\r\n\t\t\t\tnode.prev.next = node.next;\r\n\t\t\t}\r\n\r\n\t\t\tif (node == tail) {\r\n\r\n\t\t\t\tremoveTail();\r\n\r\n\t\t\t} else {\r\n\t\t\t\tnode.next.prev = node.prev;\r\n\t\t\t}\r\n\r\n\t\t\t--_count;\r\n\r\n\t\t\treturn data;\r\n\r\n\t\t}\r\n\r\n\t\tpublic function removeHead():* {\r\n\r\n\t\t\tvar node:DoublyLinkedListNode = head;\r\n\r\n\t\t\tif (head != null) {\r\n\r\n\t\t\t\tvar data:* = node.data;\r\n\r\n\t\t\t\thead = head.next;\r\n\r\n\t\t\t\tif (head != null) {\r\n\t\t\t\t\thead.prev = null ;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t--_count;\r\n\r\n\t\t\t\treturn data;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic function removeTail():* {\r\n\r\n\t\t\tvar node:DoublyLinkedListNode = tail;\r\n\r\n\t\t\tif (tail != null) {\r\n\r\n\t\t\t\tvar data:* = node.data;\r\n\r\n\t\t\t\ttail = tail.prev;\r\n\r\n\t\t\t\tif (tail != null) {\r\n\t\t\t\t\ttail.next = null;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t--_count;\r\n\r\n\t\t\t\treturn data;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t\/**\r\n\t\t * Get the lengh of the list.\r\n\t\t * @return the list length.\r\n\t\t *\/\r\n\t\tpublic function get length():uint {\r\n\t\t\treturn _count;\r\n\t\t}\r\n\r\n\t\tpublic function content():String {\r\n\r\n\t\t\tvar tmpHead:DoublyLinkedListNode = head;\r\n\t\t\tvar text:String = '';\r\n\r\n\t\t\twhile (tmpHead != null) {\r\n\t\t\t\ttext += String(tmpHead.data) + \" \";\r\n\t\t\t\ttmpHead = tmpHead.next;\r\n\t\t\t}\r\n\r\n\t\t\treturn text;\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p>Now an application usage :<\/p>\n<pre lang=\"actionscript3\">var doublyLinkedList:DoublyLinkedList = new DoublyLinkedList();\r\nvar node:DoublyLinkedListNode = new DoublyLinkedListNode(6);\r\ndoublyLinkedList.append(2);\r\ndoublyLinkedList.prepend(5);\r\ndoublyLinkedList.append(7);\r\ndoublyLinkedList.appendNode(node);\r\ntrace(doublyLinkedList.content());\r\n\r\ndoublyLinkedList.removeNode(node);\r\ndoublyLinkedList.append(9);\r\n\r\ntrace(doublyLinkedList.content());<\/pre>\n<p>The first output is : 5 2 7 6<br \/>\nAnd the second : 5 2 7 9<br \/>\nEasy to use, isn't it ?<\/p>\n<p>Now let's move on the second part : object pooling.<br \/>\nObject pooling is a datastructure based on a simple observation : the 'new' operator is costly, memory allocation necessary for the object creation is a slow process. And Garbage Collection too! So object pooling idea is really simple :<br \/>\n- create lots of object at the beginning of your level, if there is FPS reduction it shouldn't be a big problem.<br \/>\n- if you need more objects during the game create many of them that can be use later.<br \/>\n- destroy your object if you don't need it anymore, but keep a link to it! So it will be reassign!<br \/>\n- destroy all your objects and set them to null at the end of your level (garbage collector will work).<\/p>\n<p>That was for theorical advices, now more practical :<br \/>\n- object pooling is often a linked list and objects are in node data.<br \/>\n- never add params to your constructor! Add params to a init function. Indeed when you reassign an element, you don't use the constructor but your init function.<br \/>\n- create a destroy function to clear your object.<\/p>\n<p>So this is an implementation based on the works of <a href=\"http:\/\/blog.alkemi-games.com\/\" target=\"_blank\">Alkemi<\/a> (their turoials on blitting is really interesting). I added some functionality. Most of the time, we don't find object pooling implementation with graphics resources. I offer one at the end \ud83d\ude09<br \/>\nThe PooledSprite class :<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package alamboley.datastructures {\r\n\r\n\t\/**\r\n\t * @author Aymeric based on the works of Alkemi (Mickael Mouill\u00e9 & Alain Puget) www.alkemi-games.com \r\n\t *\/\r\n\tpublic class PooledSprite extends DoublyLinkedList {\r\n\r\n\t\tprotected var _poolType:Class;\r\n\t\tprotected var _poolSize:uint = 0;\r\n\t\tprotected var _poolGrowthRate:uint = 0;\r\n\r\n\t\t\/\/ Start of the list of free objects\r\n\t\tprotected var _freeListHead:DoublyLinkedListNode = null;\r\n\r\n\t\t\/**\r\n\t\t * An implementation of an object Pool to limit instantiation for better performances.\r\n\t\t * Though you pass the Class as a parameter at the pool creation, there's no way for it to send you back your object correctly typed\r\n\t\t * If you want that, reimplement the Pool class and the DoublyLinkedListNode for each of your pool or port these files to Haxe with Generics !\r\n\t\t * WARNING : Be sure to design your pooled objects with NO constructor parameters and an 'init' method of some kind that will reinitialized \r\n\t\t * all necessary properties each time your objects are 'recycled'.\r\n\t\t * WARNING : Remember to cast your objects in the correct type before using them each time you get on from a DoublyLinkedListNode.data !!!\r\n\t\t * \r\n\t\t * @param $pooledType the Class Object of the type you want to store in this pool\r\n\t\t * @param $poolSize the initial size of your pool. Ideally you should never have to use more than this number.\r\n\t\t * @param $poolGrowthRate the number of object to instantiate each time a new one is needed and the free list is empty\r\n\t\t *\/\r\n\t\tpublic function PooledSprite($pooledType:Class, $poolSize:uint, $poolGrowthRate:uint):void {\r\n\r\n\t\t\tsuper();\r\n\r\n\t\t\t_poolType = $pooledType;\r\n\t\t\t_poolSize = $poolSize;\r\n\t\t\t_poolGrowthRate = $poolGrowthRate;\r\n\r\n\t\t\tincreasePoolSize(_poolSize);\r\n\r\n\t\t}\r\n\r\n\t\t\/**\r\n\t\t * Create new objects of the _poolType type and store them in the free list for future needs.\r\n\t\t * Called once at the pool creation with _poolSize as a parameter, and once with _poolGrowthRate\r\n\t\t * each time a new Object is needed and the free list is empty.\r\n\t\t * \r\n\t\t * @param\t$sizeIncrease the number of objects to instantiate and store in the free list\r\n\t\t *\/\r\n\t\tprotected function increasePoolSize($sizeIncrease:uint):void {\r\n\r\n\t\t\tfor (var i:int = 0; i < $sizeIncrease; ++i) {\r\n\t\t\t\tvar node:DoublyLinkedListNode = new DoublyLinkedListNode();\r\n\t\t\t\tnode.data = new _poolType();\r\n\r\n\t\t\t\tif (_freeListHead) {\r\n\t\t\t\t\t_freeListHead.prev = node;\r\n\t\t\t\t\tnode.next = _freeListHead;\r\n\t\t\t\t\t_freeListHead = node;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t_freeListHead = node;\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t\/** Get an object from the free list and returns the node holding it in its data property\r\n\t\t * Don't forget to cast and reinitialize it !!!\r\n\t\t * @return a node holding the newly 'recycled' object\r\n\t\t *\/\r\n\t\tpublic  function create(bigCircleRadius:uint):DoublyLinkedListNode {\r\n\t\t\tvar node:DoublyLinkedListNode;\r\n\r\n\t\t\t\/\/ if no object is available in the freelist, make some more !\r\n\t\t\tif (!_freeListHead) increasePoolSize(_poolGrowthRate);\r\n\r\n\t\t\t\/\/ get the first free object\r\n\t\t\tnode = _freeListHead;\r\n\r\n\t\t\t\/\/ extract it from the free list\r\n\t\t\tif (node.next) {\r\n\t\t\t\t_freeListHead = node.next;\r\n\t\t\t\t_freeListHead.prev = null;\r\n\t\t\t\tnode.next = null;\r\n\t\t\t} else\r\n\t\t\t\t_freeListHead = null;\r\n\r\n\r\n\t\t\t\/\/ append it to the list of the pool\r\n\t\t\tif (head != null) {\r\n\t\t\t\ttail.next = node;\r\n\t\t\t\tnode.prev = tail;\r\n\t\t\t\ttail = node;\r\n\t\t\t} else\r\n\t\t\t\thead = tail = node;\r\n\r\n\t\t\t(node.data as _poolType).init(bigCircleRadius);\r\n\r\n\t\t\t++_count;\r\n\t\t\t\r\n\t\t\treturn node;\r\n\t\t}\r\n\r\n\t\tpublic function update(...params):void {\r\n\r\n\t\t\tvar tmpHead:DoublyLinkedListNode = head;\r\n\r\n\t\t\twhile (tmpHead != null) {\r\n\t\t\t\t(tmpHead.data as _poolType).update(params[0]);\r\n\t\t\t\ttmpHead = tmpHead.next;\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t\/**\r\n\t\t * Discard a now useless object to be stored in the free list.\r\n\t\t * @param\t$node the node holding the object to discard\r\n\t\t *\/\r\n\t\tprotected function _dispose($node:DoublyLinkedListNode):void {\r\n\t\t\t\/\/ Extract the node from the list\r\n\t\t\tif ($node == head) {\r\n\t\t\t\thead = $node.next;\r\n\t\t\t\tif (head != null) head.prev = null;\r\n\t\t\t} else {\r\n\t\t\t\t$node.prev.next = $node.next;\r\n\t\t\t}\r\n\r\n\t\t\tif ($node == tail) {\r\n\t\t\t\ttail = $node.prev;\r\n\t\t\t\tif (tail != null) tail.next = null;\r\n\t\t\t} else {\r\n\t\t\t\t$node.next.prev = $node.prev;\r\n\t\t\t}\r\n\r\n\r\n\t\t\t$node.prev = null;\r\n\r\n\r\n\t\t\t\/\/ Store the discarded object in the free list\r\n\t\t\tif (_freeListHead) {\r\n\t\t\t\t_freeListHead.prev = $node;\r\n\t\t\t\t$node.next = _freeListHead;\r\n\t\t\t\t_freeListHead = $node;\r\n\t\t\t} else {\r\n\t\t\t\t_freeListHead = $node;\r\n\t\t\t\t$node.next = null;\r\n\t\t\t}\r\n\r\n\t\t\t--_count;\r\n\r\n\t\t}\r\n\r\n\t\tpublic function disposeGraphicObject(node:DoublyLinkedListNode):DoublyLinkedListNode {\r\n\t\t\t\r\n\t\t\t(node.data as _poolType).destroy();\r\n\t\t\t\r\n\t\t\t_dispose(node);\r\n\r\n\t\t\treturn node;\r\n\t\t}\r\n\r\n\t\t\/**\r\n\t\t * Discard all currently used objects and send them all back to the free list\r\n\t\t *\/\r\n\t\tpublic function disposeAll():void {\r\n\t\t\twhile (head) {\r\n\t\t\t\tdisposeGraphicObject(head);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t\/**\r\n\t\t * Completely destroy all the content of the pool\r\n\t\t *\/\r\n\t\tpublic function clear():void {\r\n\t\t\tdisposeAll();\r\n\r\n\t\t\tvar node:DoublyLinkedListNode;\r\n\r\n\t\t\twhile (_freeListHead) {\r\n\t\t\t\tnode = _freeListHead;\r\n\t\t\t\tnode.data = null;\r\n\t\t\t\t_freeListHead = node.next;\r\n\t\t\t\tif (_freeListHead) _freeListHead.prev = null;\r\n\t\t\t\tnode.next = null;\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n}<\/pre>\n<p>It is well commented, it shouldn't be too hard to understand. Now a simple class to add point on a circle. There is some nice mathematical function :<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport flash.display.Shape;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class PointCircle extends Shape {\r\n\t\t\r\n\t\tprivate var _radius:uint;\r\n\r\n\t\tpublic function PointCircle() {\r\n\t\t}\r\n\t\t\r\n\t\tpublic function init(radius:uint = 2):void {\r\n\t\t\t\r\n\t\t\t_radius = radius;\r\n\t\t}\r\n\t\t\r\n\t\tpublic function update(bigCircleRadius:uint):void {\r\n\r\n\t\t\tgraphics.clear();\r\n\t\t\tgraphics.beginFill(Math.random() * 0xFFFFFF);\r\n\t\t\tgraphics.drawCircle(0, 0, _radius);\r\n\t\t\tgraphics.endFill();\r\n\r\n\t\t\tvar theta:Number = Math.random() * 360;\r\n\t\t\tvar phi:Number = Math.random() * 90;\r\n\r\n\t\t\tx = bigCircleRadius * Math.cos(phi) * Math.cos(theta);\r\n\t\t\ty = bigCircleRadius * Math.cos(phi) * Math.sin(theta);\r\n\t\t\tz = bigCircleRadius * Math.sin(phi);\r\n\t\t}\r\n\t\t\r\n\t\tpublic function destroy():void {\r\n\t\t\t\r\n\t\t\tgraphics.clear();\r\n\t\t}\r\n\t\t\t\r\n\t}\r\n}\r\n<\/pre>\n<p>Notice that there is nothing in the constructor method! If we just init this object, it will not be visible. The update method makes it visible. It depends on your need, that's not a big deal.<\/p>\n<p>And finally my main class :<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport alamboley.datastructures.DoublyLinkedList;\r\n\timport alamboley.datastructures.DoublyLinkedListNode;\r\n\timport alamboley.datastructures.PooledSprite;\r\n\timport alamboley.utils.FPSMemCounter;\r\n\r\n\timport flash.display.Sprite;\r\n\timport flash.events.Event;\r\n\timport flash.events.MouseEvent;\r\n\timport flash.text.TextField;\r\n\r\n\r\n\t[SWF(backgroundColor=\"#000000\", frameRate=\"24\", width=\"600\", height=\"500\")]\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class Main extends Sprite {\r\n\r\n\t\tprivate const _INIT_OBJECTS:uint = 500;\r\n\t\tprivate const _BIG_CIRCLE_RADIUS:uint = 200;\r\n\t\tprivate const _CIRCLE_RADIUS:uint = 2;\r\n\r\n\t\tprivate var _container:Sprite;\r\n\t\tprivate var _pool:PooledSprite;\r\n\t\tprivate var _tf:TextField;\r\n\r\n\t\tprivate var _radius:uint = 200;\r\n\t\tprivate var _radiusIncrease:Boolean = false;\r\n\r\n\t\tpublic function Main() {\r\n\r\n\t\t\tFPSMemCounter.init(stage, this, true);\r\n\r\n\t\t\t_container = new Sprite();\r\n\r\n\t\t\taddChild(_container);\r\n\t\t\t_container.x = stage.stageWidth * 0.5;\r\n\t\t\t_container.y = stage.stageHeight * 0.5;\r\n\r\n\t\t\t_initButtons();\r\n\r\n\t\t\tstage.addEventListener(Event.ENTER_FRAME, _ef);\r\n\r\n\t\t\t_pool = new PooledSprite(PointCircle, _INIT_OBJECTS, 50);\r\n\t\t\t\r\n\t\t\tvar i:uint = 0;\r\n\t\t\tfor (i = 0; i < _INIT_OBJECTS; ++i) {\r\n\t\t\t\ttrace('Creating Point ', _pool.length);\r\n\t\t\t\t_container.addChild(_pool.create(_CIRCLE_RADIUS).data);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t_tf.text = String(_pool.length) + \" objects\";\r\n\t\t}\r\n\r\n\t\tprivate function _ef(evt:Event):void {\r\n\t\t\t\r\n\t\t\tif (_radiusIncrease == true) {\r\n\t\t\t\t\r\n\t\t\t\t++_radius;\r\n\t\t\t\tif (_radius > _BIG_CIRCLE_RADIUS) {\r\n\t\t\t\t\t_radiusIncrease = false;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t} else {\r\n\t\t\t\t\r\n\t\t\t\t--_radius;\r\n\t\t\t\tif (_radius < 25) {\r\n\t\t\t\t\t_radiusIncrease = true;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t_pool.update(_radius);\r\n\t\t}\r\n\r\n\t\tprivate function _removeObjects(mEvt:MouseEvent):void {\r\n\r\n\t\t\tif (_pool.length > 50) {\r\n\t\t\t\tvar i:uint = 0;\r\n\t\t\t\tfor ( i = 0; i < 50; ++i ) {\r\n\t\t\t\t\ttrace('Disposing Point', _pool.length);\r\n\t\t\t\t\t_container.removeChild(_pool.disposeGraphicObject(_pool.tail).data);\r\n\t\t\t\t}\r\n\t\t\t\t_tf.text = String(_pool.length) + \" objects\";\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate function _addObjects(mEvt:MouseEvent):void {\r\n\r\n\t\t\tvar i:uint = 0;\r\n\t\t\tfor (i = 0; i < 50; ++i) {\r\n\t\t\t\ttrace('Creating Point ', _pool.length);\r\n\t\t\t\t_container.addChild(_pool.create(_CIRCLE_RADIUS).data);\r\n\t\t\t}\r\n\t\t\t_tf.text = String(_pool.length) + \" objects\";\r\n\t\t}\r\n\r\n\t\tprivate function _initButtons():void {\r\n\r\n\t\t\tvar addObject:Sprite = new Sprite();\r\n\t\t\taddObject.graphics.beginFill(0x0000FF);\r\n\t\t\taddObject.graphics.drawRect(0, 0, 75, 30);\r\n\t\t\taddObject.graphics.endFill();\r\n\t\t\taddObject.x = 500;\r\n\t\t\taddObject.y = 380;\r\n\t\t\taddChild(addObject);\r\n\t\t\taddObject.buttonMode = true;\r\n\t\t\taddObject.addEventListener(MouseEvent.CLICK, _addObjects);\r\n\r\n\t\t\tvar addObjectText:TextField = new TextField();\r\n\t\t\taddObjectText.selectable = false;\r\n\t\t\taddObjectText.mouseEnabled = false;\r\n\t\t\taddObjectText.textColor = 0x00FF00;\r\n\t\t\taddObject.addChild(addObjectText);\r\n\t\t\taddObjectText.text = \"Add 50 objects\";\r\n\t\t\taddObjectText.y = 10;\r\n\r\n\t\t\tvar removeObject:Sprite = new Sprite();\r\n\t\t\tremoveObject.graphics.beginFill(0xFF0000);\r\n\t\t\tremoveObject.graphics.drawRect(0, 0, 75, 30);\r\n\t\t\tremoveObject.graphics.endFill();\r\n\t\t\tremoveObject.x = 500;\r\n\t\t\tremoveObject.y = 430;\r\n\t\t\taddChild(removeObject);\r\n\t\t\tremoveObject.buttonMode = true;\r\n\t\t\tremoveObject.addEventListener(MouseEvent.CLICK, _removeObjects);\r\n\r\n\t\t\tvar removeObjectText:TextField = new TextField();\r\n\t\t\tremoveObjectText.selectable = false;\r\n\t\t\tremoveObjectText.mouseEnabled = false;\r\n\t\t\tremoveObjectText.textColor = 0x00FF00;\r\n\t\t\tremoveObject.addChild(removeObjectText);\r\n\t\t\tremoveObjectText.text = \"Remove 50\";\r\n\t\t\tremoveObjectText.y = 10;\r\n\r\n\t\t\t_tf = new TextField();\r\n\t\t\t_tf.selectable = false;\r\n\t\t\t_tf.mouseEnabled = false;\r\n\t\t\t_tf.x = 30;\r\n\t\t\t_tf.y = 450;\r\n\t\t\t_tf.textColor = 0x00FF00;\r\n\t\t\taddChild(_tf);\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p>If you have read all, congratulations! Now you can see my experiment with doubly linked list and object pooling : <a href=\"http:\/\/www.aymericlamboley.fr\/blog\/wp-content\/uploads\/2011\/09\/SphereObjectPooling.swf\" rel=\"lightbox[flash 600 500]\"><strong>a Sphere<\/strong><\/a>.<br \/>\nMy <a href=\"http:\/\/www.aymericlamboley.fr\/blog\/wp-content\/uploads\/2011\/09\/SphereObjectPooling.zip\" target=\"_blank\">zip<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After holidays, it&#8217;s time to get back to work \ud83d\ude42 I was really busy last month, so this is some news on what I did and what is going on : &#8211; I&#8217;ve made some experiments with the Citrus Engine on the Hero adding some functionality. But what appears is the Hero class becomes more &hellip; <a href=\"http:\/\/www.aymericlamboley.fr\/blog\/doubly-linked-list-and-object-pooling\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Doubly linked list and object pooling<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[4,151,147,11,149,6],"tags":[20,15,76,13,26,14,75,62,74],"_links":{"self":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/347"}],"collection":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/comments?post=347"}],"version-history":[{"count":14,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/347\/revisions"}],"predecessor-version":[{"id":1293,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/347\/revisions\/1293"}],"wp:attachment":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/media?parent=347"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/categories?post=347"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/tags?post=347"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}