Monday, May 24, 2010

Children

For me, one of  the most awkward words in ActionScript is that of child.  Children show up a great deal with addressing and including NodeSprites.  In fact, all display objects make use of children - a child is simply something attached in a particular way to another object.  So one display object might add another display object in a parent-child manner; the complexity comes in when identifying what manner the child was added.

The most obvious manner is to user the .addChild method.  This is clean and requires the added child to be of type displayObject.  Double adding a child has no effect - apparently it detects existing children.

The second most obvious manner is to use the .addChildAt method; the difference here is that, instead of simply adding it as if the parent were at stack, it offers the ability to add it in place of another existing child, or add it to the end.  Adding it at the end of the child array appends the standard addChild method; adding it anywhere else places the new child at the desired position and pushes all other children one further down the list.  Double adding a child using this method has no effect; much like earlier, if the desired index is out of scope of the parent child array, it will fail.

Regardless of which method, the number of children attached to a given parent display object may be found by using .numChildren.

Do not be misled by using the .childDegree property - this focuses on edges instead of nodes.  Instead of identifying the number of children by simply counting what children are attached to the parent node, one might instead go the route of looking to the number of child edges leaving a given node.  This might be intuitive - logically, each child of a parent should have an edge binding the two together.

This is not always the case.  In some architectures, the number of child edges may match, exceed, or be less than the number of children attached to a given parent node.  This is because the presence of an edge does not necessarily require the two nodes on either side of the edge to have a parent-child relationship.  It can also be the case that sometimes an edge will hold each of the nodes in question on either side of the edge, but the nodes will have a child-parent relationship; in these cases, simply having the child edge count is of necessity misleading.

Another concern when identifying children is the assumption of case; while looping through the children of a given parent, do not assume you know the type or the source.  I have seen at least one project where the children of a given parent-node had two types of children: NodeSprites and DisplayObjects (to which I would link but find the class to be unavailable).  Each has slightly different properties.  Likewise, although the displayObjects (as images) were cleanly available as children, the nodeSprite children were sometimes simply attached as the images, but were only completely available once one looped through the entire collection of nodes, identifying the nodes that had as a parent the original parent-node.

In short - do not be quick to assume you know the entire hierarchy or lineage of a given display object; it may be the case that other children exist, perhaps in the global node list, perhaps simply in the list of attached children, and perhaps hiding in the list of edges.

Friday, May 21, 2010

Event Listeners

One of the most powerful tools I've run across are Event Listeners.  In fact, I can safely say that, without Event Listeners, much of your application will appear lifeless.  Event Listeners allow your own drawn objects to respond to one another, to the mouse, to the keyboard, to events that happen outside them all (like a simple browser resize) and ultimately offer a means of providing interactivity.

I like to think of a listener as a link between a passive and an active.  You want the ball to roll, so you kick it.

The means by which a listener is associated with an object is through addition.  Specifically, most objects have a method called "addEventListener" which, simple enough, adds a listener - one triggered by a particular event.

There are different classes of Events.  There are generic Events (the browser resize mentioned earlier falls into this category), mouse-specific events (clicking is obvious, but also includes mouse-over and mouse out), and lots of others as well.  [Here] is the flash documentation for Events.

Making use of an Event Listener is fairly easy - the simplest requires knowing the object to which you would attach the listener (the ball), the event which you anticipate happening (the kick), and what you want to happen as a result (rolling).

Code samples:
Example with anonymous function
private function addButtonWithListener():void
{
  var button:TextSprite = new TextSprite();
  button.x = 50;
  button.y = 50;
  button.width = 10;
  button.height = 10;
  button.text = "blue!";
  addChild(button);

  button.addEventListener( MouseEvent.CLICK, function( m:MouseEvent):void
  {
      button.text = (button.text=="blue!") ? "red!" : "blue!";
  });
}

Example with a separate method (requiring a global button)
public class ListenerExample
{
    private var button:TextSprite;
  
    instantiateButton( 50, 50, 10, 10, "blue!" );
    addButtonListener();
  
    private function instantiateButton( _x:uint, _y:uint, _w:uint, _h:uint, initialText:String):void
    {
      button = new TextSprite();
      button.x = _x;
      button.y = _y;
      button.w = _w;
      button.h = _h;
      button.text = initialText;
      addChild( button );
    }

    private function addEventListener():void
    {
      button.addEventListener( MouseEvent.CLICK, toggleButtonText );
    }

    private function toggleButtonText( m:MouseEvent=null ):void
    {
      button.text = (button.text=="blue!") ? "red!" : "blue!";
    }
}

That should get you started.

Another, later post, will address removing event listeners.