Jun 11 2008

Papervision3D: workaround for onReleaseOutside

Thomas Viktil

I just stumbled across a very simple way of achieving an onReleaseOutside event when working with Papervision3D.

Now, why would I bring up Papervision3D in such a setting? If you, like me, have included a Papervision3D scene on a stage where other 2D objects (like MovieClips and other Flash components) are scattered about, you have probably seen a few unexplainable events happening.

I’ve only done a few tests with PV3D and Flex, but it seems to be easy to limit the size of the 3D scene to the boundaries of a component. But when adding a PV3D scene in a Flash project (creating an instance of a PV3D class and adding it to stage using addChild()) other rules seems to apply.

Once I tried to limit the size of the Papervision3D (PV3D) scene to just a portion of the stage, and center it. But the bloody scene kept taking over the entire stage of the parent class. The result was that coordinate 0,0 i the PV3D class was aligned with 0,0 in the parent class. Way out of the area where it was supposed to be displayed. I managed to solve it somehow…

Today, working on a different project, I was facing a different challenge. I have a PV3D class added to stage. This class has a few public functions which I intend to access from the parent class using buttons and whatnot. These buttons and whatnot are added on a level (z-index) above the PV3D class, making them visible at all time. You could say the buttons are the GUI, and the PV3D class shows the content.

Listening for MouseEvent.MOUSE_DOWN on the button is easy, but adding a function for when releasing the mouse button outside of the button wasn’t that easy. I did a bit of googling and found some answers here and there. Derrick Grigg wrote a post about the issue. Some people dicussed it at ActionScript.org, where Tink gave a simple solution. And Senocular wrote about it over at Kirupa, confirming what everyone else has written; add an eventListener to stage which listens for MOUSE_UP events.

That’s a clever solution, and an easy one too. At MOUSE_DOWN you add an eventListener to stage which listens for MOUSE_UP events. When that event fires, it calls a handler which removes the eventListener from stage. Simple, and it works. Except for when you have a PV3D object covering the stage.

Even if the PV3D object is empty and therefore seems quite transparent, one would think that the stage is clickable. But it isn’t. The eventListener on stage will never fire because of the PV3D object. The solution must be to add an object above the PV3D object and make that one listen for MOUSE_UP events. But wait a second! That would make the PV3D object unclickable. We must make the listener object appear temporary.

We could use addChildAt and removeChildAt to dynamically place the object above the PV3D object, but underneath the button, and then remove it when not needed. But that would require us to keep track of where we place various objects and making sure we remove the right ones and so on. Sounds like hassle.

I decided to place a permanent MovieClip on a layer between the PV3D object and the button. Yes, the exact opposite of what I’ve just wrtten. It’s permanently stuck to stage, but appears temporary. This object is empty for most of the time but filled when needed. Filling the MovieClip is easily done by accessing the graphics property of the MovieClip. When I click the button I run a Fill() command to fill the object with a white color. When the button releases I simply run a clear() command to remove the fill. This way I can turn the object on or off.

The object also has the eventListener permanently attached making it unnecessary to add and remove the eventListener for each click and release.

The object has no alpha property set to 0, but yet it is transparent. I read somewhere that someone had found out that using blendMode was faster and less CPU intensive that using alpha = 0. I know from experience that semitransparent objects can reduce performance (and in this project, performance is an issue), so I chose to stick with blendMode. When I attach the object to stage, I set blendMode to multiply. Multiplying the color white to any other color makes it invisible. Wikipedia hasn’t the best explanation of multiply, but you’ll see that the formula is result color = top color * bottom color / 255. Since the bottom color remains unchanged when multiplying with white, white would represent the value 0. And multiplying anything with 0 results in 0.

So there you have it. Filling and clearing a MovieClip to turn it on and off.

As a final note I’d like to add one thing. If one would like to do something with the button (like changing it’s state) one would probably fall for the temptation of using the event object returned by the MouseEvent to refer to the button (event.currentTarget.something). Keep in mind that there are 2 separate objects calling this handler, making the event object refer to 2 different objects. So, as in my case, where I wanted to do things with the button, I had to directly refer to the button’s instance, and not use the event object.

Here are a few lines of code from my project:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class someclass extends MovieClip
{
	private var _square:Sprite = new Sprite();
	private var _btn:ButtonClass = new ButtonClass();
 
	public function someclass()
	{
		addChild(PV3D); // Add the PV3D object
 
		_square.blendMode = "multiply";
		_square.addEventListener(MouseEvent.MOUSE_UP, scrollRelease); // Listen for button release
		addChild(_square);
 
		addChild(_btn);
	}
 
	// This function has been added to the _btn object
	private function scrollPress(e:MouseEvent):void
	{
		_square.graphics.beginFill(0xFFFFFF);
		_square.graphics.drawRect(0, 0, 500, 250);
		_square.graphics.endFill();
	}
 
	private function scrollRelease(e:MouseEvent):void
	{
		_square.graphics.clear();
	}
}

Jun 2 2008

Actionscript: Outputting a grid using only one for-loop

Thomas Viktil

Sometime this winter a friend of mine (Knut Urdalen) introduced me to a part of mathematics called modular arithmetic. Now that is a nifty little thing.

In modular arithmetic, or modulus if you like, numbers reset themselves when reaching a given limit. Modulus is also known as “clock arithmetic”, and the clock is a very good example for explaining modulus.

A 12 hour clock has a limit of 12, making the hours reset at 12 o’clock. So instead of becoming 13, it simply jumps back to 1. The same thing happens with a 24 hour clock, but at 24 hours instead of 12. This is as simple as I would’ve explained it, but Wolfram has a more in-depth article with links to further reading. I’m sure Google has even more.

In ActionScript you can use modulus like this: x = y % z. Which reads like “x is y modulus to z”.

Following the example of the clock we would have to do a modulus of 12 on the total numbers of hours since the beginning of time to get the current time. Why? Ever since we started keeping track of time the numbers of hours have kept increasing. Time never stops. So instead of saying “oh, the time is 87654826253745 hours”, we do a modulus of 12 on 87654826253745 and get 7. And by looking out of the window we can tell if it is morning or evening.

Modulus can however not be used to count the number of turns the hour hand has turned at 87654826253745 o’clock. It only knows when it has reached the limit, not how many times it has turned.

So, as you probably have guessed already modulus is a drop dead simple way of outputting grids. And this is how I would’ve made a grid of images:

private _max:Number = 20; // Total number of items
private _rows:Number = 5; // Items per row
private _width:Number = 100;
private _height:Number = 100;
 
private function createGrid():void
{
       var ix:Number = 0;
        for(var i:int=0; i<_max; i++) // Iterate through all items
        {
                var col:Number = i % _rows;
                col==0 ? ++ix : void;
                x = ix * _width;
                y = col * _height;
    }
}

Let’s look at each of the lines;
01 : define max number of items in the grid
02 : define max number of items in each row
03 & 04 : width and height of each of the items
08 : x position of row <em>n</em> (increases for each new row)
09 : loop through all items
11 : col is ‘current item’ modulus to ‘items per row’
12 : if col has reset, increase ix by one. Here we jump to the next column
13 : place item at x position ‘ix * _width’
14 : place item at y position ‘col * _height’

And that’s about it. Simple, right?

If anyone of a more mathematical kind of person discovers something wrong, or would’ve explained modulus in a better way, do arrest me. I’m still learning.