Recognize DisplayObject Transform Matrix Change Event in Flash AS3

If another object changes the transformation matrix of a DisplayObject, the DisplayObject has no means to recognize that it has been transformed, as it is transformed automatically. E.g., there is no kind of TRANSFORMATION_MATRIX_CHANGED event that is dispatched on the DisplayObject. If your DisplayObject still should react on a change of its transformation matrix, a workaround is necessary, which is described in the following approach. I show a short solution at first and will explain the actual problem and solution approach in more detail afterwards.

DISCLAIMER: I found no solution where the change of the transformation matrix can be recognized without changing the object that actually does the matrix transformation. If you know or find one, be so kind to post it in the comments.

Short Solution:

Your DisplayObject called UpdateDetectionSprite:

1
2
3
4
5
6
7
public class UpdateDetectionSprite extends Sprite{
public override function set transform(value:Transform):void{
	super.transform = value;
	this.updated = true;
}
//…
}

Object that does the matrix transformation called ActionObject:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ActionObject{
private function performTransformation():void{
	var transformedSprite:UpdateDetectionSprite = new UpdateDetectionSprite();
	var transform:Transform = transformedSprite.transform; 
	var matrix:Matrix = transform.matrix;
 
	//do something with matrix, e.g., move object by translation
	matrix.translate(10,20);
 
	//assign matrix to Transform object
	transform.matrix = matrix;
	//assign changed transform object to your DisplayObject. your overriden 
	//setter will be called, causing the update flag to be set.
	transformedSprite.transform = transform;
}
}

Actual Problem:
I have a Sprite (called UpdateDetectionSprite) in which I want to be informed, when the object has been transformed (moved, rotated or scaled). To establish that, one part of the approach is to override the appropriate setters for x, y, width, height, scaleX, scaleY and rotation in UpdateDetectionSprite. However, if the UpdateDetectionSprite is modified when its transformation matrix is changed, the mentioned setters will NOT be called, so UpdateDetectionSprite will not be informed on a matrix change, it will automatically transformed. My first idea was to override the setter for the matrix in order to react on the assignment of matrix to UpdateDetectionSprite, but the matrix itself actually is not a property of DisplayObject but a property of DisplayObject’s transform property. So I overrode the transform setter in UpdateDetectionSprite. In order to inform UpdateDetectionSprite that its matrix has been changed, you additionally have to set the transform property in ActionObject that does the transformation (see listing 2). That approach works as well with UpdateDetectionSprite as with each other DisplayObject.

Complete UpdateDetectionSprite:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class UpdateDetectionSprite extends Sprite{
 
private var _updated:Boolean;
 
public override function set transform(value:Transform):void{
	this.updated = true;
	super.transform = value;
}
public override function set x(x:Number):void{
	if(this.x != x){
		this.updated = true;
	}
	super.x = x;	
}
public override function set y(y:Number):void{
	if(this.y != y){
		this.updated = true;
	}
	super.y = y;	
}
public override function set rotation(rotation:Number):void{
	if(this.rotation != rotation){
		this.updated = true;
	}
	super.rotation = rotation;	
}
public override function set width(width:Number):void{
	if(this.width != width){
		this.updated = true;
	}
	super.width = width;	
}
public override function set height(height:Number):void{
	if(this.height != height){
		this.updated = true;
	}
	super.height = height;	
}
public override function set scaleX(scaleX:Number):void{
	if(this.scaleX != scaleX){
		this.updated = true;
	}
	super.scaleX = scaleX;	
}
public override function set scaleY(scaleY:Number):void{
	if(this.scaleY != scaleY){
		this.updated = true;
	}
	super.scaleY = scaleY;	
}
public function set updated(updated:Boolean):void{
	if(updated){
		this.addEventListener(Event.EXIT_FRAME, updatedSprite);
	}
	this._updated = updated;
}
protected function updatedSprite(event:Event):void{
	//do something
	//...
	//...
	updated = false;
	this.removeEventListener(Event.EXIT_FRAME, updatedSprite);
}
}

For testing purposes, I additionally tried to write a custom Transform object called UpdateDetectionTransform that inherits from Transform, assign it to UpdateDetectionSprite’s transformation property and override the matrix setter in UpdateDetectionTransform. I do not know why, but it is not possible to assign a custom Transform object to the transform property. This code

1
2
this.transform = new UpdateDetectionTransform(this);
trace(this.transform);

will print ‘[object Transform]’ to the console. This means that the assignment of UpdateDetectionTransform to this.transform does not work. I do not know why. If you know why, post it in the comments please.

Alternatively to my outlined approach above, you could dispatch a custom event in ActionObject on UpdateDetectionTransform.

Posted in Actionscript Tagged with: Actionscript, Adobe Air, as3, Flash, flex