I have this code which works perfectly but occasionally - whenever Flash thinks so - it crashes. Here is the debug text produced:
Error #2025
showResult:true
dolly = 10
Dolly added
Generic Chips added
Highlighting SH:[object SurfaceElement]10-[object TSprite]-vex!
ArgumentError: Error #2025
Note that "vex!" is the name of object vex, which is a TSprite (=Sprite).
public function update(players:Array, showResult:Boolean = false):void {
try {
var debug:String = "showResult:" + showResult.toString() + "\n";
debug += "dolly = " + dolly.toString();
// RESET columns
columns.length = 0;
billboards.removeAllChildren();
var column:ChipColumn;
// add dolly
var alfa:Number = 1;
if (showResult) {
column = getChipColumn(vex.getChildIndex(numberToSH[dolly]));
column.addChild(dollySpr);
alfa = LOSER_ALPHA; // fade-out (non-animated) non-winning columns
}
debug += "\nDolly added";
for (var k:* in players) {
var player:Player = players[k];
var bets:Array = player.getBets();
for (var i:* in bets) {
// is there a column already for these chips?
column = getChipColumn(i);
column.alpha = alfa; // loser..?
for (var j:int = bets[i]; j > 0; --j) {
var bmp:TBitmap = new TBitmap(chips[k], Align.CENTER, Align.CENTER);
bmp.y = - column.numChildren * 5;
column.addChild(bmp);
}
}
}
debug += "\nGeneric Chips added";
if (showResult) {
var shs:Array = SurfaceElement.NumberToAllSH[dolly];
for each (var sh:SurfaceElement in shs) {
debug += "\nHighlighting SH:" + String(sh);
debug += sh.corresponds.toString();
debug += "-" + String(sh.parent);
debug += "-" + String(sh.parent.name);
column = getChipColumn(vex.getChildIndex(sh)); // ERROR LINE ?!?
column.alpha = 1; // restore alpha
column.filters = [new GlowFilter(0xffffff, 1, 12, 12, 3, 3)];
}
}
debug += "\nEnd of Highlighting !!!!!!";
// sort columns by y
var sorted:Array = columns.sortOn("sortY", Array.NUMERIC | Array.RETURNINDEXEDARRAY);
debug += "\n" + sorted.toString();
for (i in sorted) {
column = columns[sorted[i]];
if (!column) break; // pointers to undefined data have arrived (put last)
billboards.addChild(column);
}
debug += "\nEnd of ALL";
} catch(e:Error) {
if (!Debug.field.text.length) {
Debug.field.textColor = 0xffffff;
Debug.field.appendText(e.message + "\n" + debug + "\n" + e.toString());
}
}
}
private function getChipColumn(i:int):ChipColumn {
var column:ChipColumn = columns[i];
if (!column) {
column = new ChipColumn();
// calc column properties
var sh:SurfaceElement = vex.getChildAt(i) as SurfaceElement;
var point:Point = sh.getCenterProjected();
point = billboards.globalToLocal(point);
column.sortY = sh.center.y;
column.x = point.x;
column.y = point.y;
columns[i] = column;
}
return column;
}
From the debugging text, it's obvious that the error happens here:
debug += "\nHighlighting SH:" + String(sh);
debug += sh.corresponds.toString();
debug += "-" + String(sh.parent);
debug += "-" + String(sh.parent.name);
column = getChipColumn(vex.getChildIndex(sh)); // ERROR LINE ?!?
Error 2025 happens when getChildIndex is called for a non-child object. But sh IS vex's child as the parent's name suggests (vex!). And there is only ONE vex.
Another peculiar thing is that the error message (e.message) simply produces: Error 2025 while error-to-string (e.toString()) produces: ArgumentError: Error #2025
Shouldn't it say more like:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller ??
Static global state is a bad thing. In this case, you have no way of knowing whether or not the sh objects you are retrieving from your static array have anything to do with the current "vex" object or not.
Instead of having SurfaceElement
track all instances of itself that have been added, consider having your Vex
Class expose a surfaceElements Array (or better yet, Vector). If these are built on the stage (I suspect you're tracking them statically because you don't have a good "handle" on working with timeline/stage objects), then you could do something like this in your constructor:
public var surfaceElements:Array = []; function Vex() { super(); var loops:int = numChildren; for (var i:int=0; i<loops; i++) { var surface:SurfaceElement = getChildAt(i) as SurfaceElement; if (surface) { surfaceElements[surfaceElements.length] = surface; } } }
Then, when you are done with that specific Vex, you are also done with its surfaceElements with no crossover.