I’ve registered a new domain, and I've moved to a new blog.
Future posts will be posted there.
Sunday, January 23, 2011
Friday, January 7, 2011
Stardust project homepage
Finally! Stardust version 1.3 is released!
I've updated all the examples, so they all work perfectly with the new particle handlers.
I'm currently working on the integration of Stardust and Minko, a new 3D engine that will support the Molehill APIs. Paq is working on the integration with Alternativa3D and Away3D, whilch will also support the Molehill APIs. I'm really looking forward to Stardust being used in Molehill-powered applications (especially games, of course), enriching the visual experience with 3D particles!.
Monday, January 3, 2011
Stardust project homepage
As a quick notice, Paq has joined the Stardust development team. He'll be working on plugins for Alternativa3D and Away3D, and Japanese localization. Horray!!
I'm currently working on the most important new features of Stardust 1.3, switching from renderers to particle handlers.
Previously, the particle data in Stardust are read and visually presented by the
Renderer class, whose
render methods take in
ParticleCollection objects as parameters, and traverse them to retrieve particle data, resulting in almost twice the processing overhead for particle traversal.
I've found this extra traversal effort quite unnecessary. Since a complete traversal of the internal particle collection of each emitter is already done in each emitter step, so why not "embed" the rendering process into the emitter step? This is how I came up with the idea for particle handlers.
The skeleton of the
ParticleHandler class looks like this:
stepBegin method is invoked at the beginning of each emitter step.
stepEnd method is invoked at the end of each emitter step.
particlesAdded method is invoked when a new particle is added to the emitter.
particlesRemoved method is invoked when a dead particle is removed from the emitter.
readParticle method is invoked when a particle is fully updated by all actions.
You may override these methods to create your own handlers. The concept is quite similar to that of the renderers, only that particle handlers do not require extra (and unnecessary) particle collection traversal. Everything is done in one single traversal.
A particle handler is assigned to an emitter through the
Emitter.particleHandler property, which is quite straightforward:
You may find the similarity between the code above and the use of its renderer counterpart:
Not until I finished the
ParticleHandler class did I realize how easy it is to implement a polling station as a particle handler, favoring those developers preferring polling over events.
For your information, a polling station is like a passive database. You access the data only when you need to, which is the opposite to an event system. An event system, as most Flash developers are already familiar with, is an active database, "pushing" data to you whenever there is new data available.
Some framework is designed to better work with polling stations rather than event systems. Thus, I've written a
PollingStation class that works as a polling station, recording all the relevant particles in each emitter step, and exposing an interface for data polling.
Friday, October 22, 2010
Currently I'm training in the School of Political Warfare, since I've passed the test for political officers. After two more months of training, I'll be working in the army as a political officer, hopefully having a much better and easier life than other ordinary soldiers.
In case you don't follow me on Twitter, I'm accepted into DigiPen's Bachelor of Science in Game Design program. This means I'm going to learn some real hard-core game development skills from the professionals after I get out of the army. I think I shouldn't waste my time on the boring and hollow training classes in the School of Political Warfare, so I've been constantly sketching game concepts in classes.
Recently, I've come up with this game concept, called MicroPlanet. The story takes place on a galaxy of microscopic planets, where there are bunny-like fungus creatures trying to expand their territory and fighting against opposing tribes.
Here's the first concept art I've drawn.
(Click on the image for larger view)
Saturday, August 7, 2010
I'm about to fulfill my compulsory military service tomorrow (August 9), and it ends in mid-July 2011. During my service, I can only have web access perhaps every one or two weeks, or even longer. So the updates and fixes to my projects will become far less frequent than normal. You may still email me if you've got any problems with the projects. I don't guarantee a quick response, but I'll reply as soon as possible.
I've applied for the "Bachelor of Science in Game Design (Fall 2011)" program in DigiPen. The result will come out several weeks later. I hope I could make it :)
P.S. I've shaved my head for the army, and it takes only 10 seconds to dry it after shower!
Sunday, August 1, 2010
Rusher project homepage
Rusher is now version 0.6 Beta. One of the most important changes is the extraction of entity-related code from the
Engine class into the
EntityManager class. So instead of writing things like:
I've also added a new MVC Pattern example. Actually, it was one of my experiments to try implementing the MVC Patern in Rusher. This one turned out nice, so I've committed it to the repository. This example is simply a proof of concept, and I might find out other better approaches to using the MVC Pattern in Rusher.
View example demo
View example source
This example is a very simple painter application, consisted of a color chooser, a clear button, and a bitmap canvas where you can draw with your cursor.
The entire application is represented by the
Context class, which extends the
Entity class. There are four components added to this entity:
Context class is pretty simple. It creates four components and adds it to itself. Another important modification to Rusher in version 0.6 is the one-clock-cycle-delayed invocation to the
Component.onAdd() method. In this way, the order in which the components are added to the entity does not affect whether accessing other components in a component's
onAdd() method yields a null value.
Signaller component is pretty much a "signal hub" consisted of several CJSignals signal objects. These signal objects dispatch application events listened by other components. Also, other components can cause these signal objects to dispatch events.
Model component contains the underlying application data, a
BitmapData object representing the canvas. Also, this component defines several public methods that modifies the bitmap data. These methods allow users to change the line color, move the drawing pen position, draw a line, and clear the entire canvas.
View component constructs and displays the visual representation of the application. In addition, this component listens for the mouse event dispatched by these display objects and relays these events to the signal objects in the
Controller component listens the signal objects in the
Signaller component and maps them to command objects. These command objects invokes the public methods provided by the
Model class to modify the underlying bitmap data.
Finally, below are the command classes.
This is the
LineColor command that changes the line color.
This is the
MoveTo command that moves the position of the drawing pen.
This is the
LineTo command that draws a line.
And this is the
Clear command that clears the entire bitmap data.
You may view the source of this example in its entirety here.
Wednesday, July 7, 2010
CJSignals project homepage
CJSignals is an observer framework I released a couple of days ago, based on Robert Penner's AS3 Signals.
For some performance comparison of the native event system, CJSignals, and AS3 Signals, you may check out my previous post. Here I'm going to describe the performance-improving techniques employed in CJSignals.
This technique can also be employed elsewhere when massive objects are added and removed from an array very rapidly, where the array must be sorted and performance is vital. Rusher also uses this technique to manage prioritized active components.
For each listener functions added, a corresponding
ListenerDataobject is created and stored in the internal array, which contains a reference to the listener, a boolean variable indicating whether the listener is a one-time listener, and an integer variable for keeping track of the index of the
ListenerDataobject in the array. Also, a mapping relation between the listener and the
ListenerDataobject is added to an internal dictionary for fast lookup.
CJSignals keeps track of the index of the first empty cell of the listener array with an integer variable, i.e. keeping track of the first null element. When a new listener is added, its corresponding
ListenerDataobject is inserted to the array cell corresponding to the index, and then the index is incremented by 1. If the array is full, then its size is doubled. This approach assigns elements directly to an array cell by index, instead of invoking
Array.push()every time a new listener is added.
Listeners can be removed from the array very efficiently. When a listener is removed from a signal, the listener dictionary is used to quickly retrieve the listener's corresponding
ListenerDataobject. From the
ListenerDataobject, the index of the object in the array can then be obtained (A). The index of the first empty cell is decremented by 1, thus pointing to the last non-null element (B). Cell A's content is replaced by cell B's, and cell B's content is replaced with a null value, so the first-null-element index is now keeping track of the new first null element.
Adding and removing listeners sets a listener-array-dirty flag to true, indicating the necessity to sort the listener array according to the listener priorities. The sorting is not necessary until the next signal dispatch or retrieval of the internal listener array through the public getter method
get listeners(), the flag set back to false afterwards. Thus, multiple calls to the
Signals.remove()methods do not cause the array to be re-sorted; it is deferred to the point when the sorting is really necessary. After the array is sorted, the
ListenerDataobjects are informed of and updated with their new indices.
I guess the native event system sorts the array every time a new listener is added, resulting in the huge performance difference between the system and CJSignals.
One good thing about the
Array.sort()method is that it always pushes null elements to the tail of the array, so it's okay to keep a sparse array, as long as the index of the first null element is kept track of.