airsdk / Adobe-Runtime-Support

Report, track and discuss issues in Adobe AIR. Monitored by Adobe - and HARMAN - and maintained by the AIR community.
199 stars 11 forks source link

Request DisplayObjectContainer.sortChildrenBy() #3120

Open shaucky opened 5 months ago

shaucky commented 5 months ago

Description

Add new public method DisplayObjectContainer.sortChildrenBy() for sorting direct children by their property.

public function sortChildrenBy(property:String = null, asc:Boolean = true):void

So that developers can get an easy, efficient way to dynamically sort children of a DisplayObjectContainer. If the property is null, it means the program end dynamical sorting.

Application

If there is a container has numbers of children, dynamically sort them by ActionScript is inefficient. One way i know is dividing children into grids by coordinates and only sort the grid where the changing child in. But it's still not perfect.

Thanks.

ajwfrost commented 3 months ago

Hi @shaucky - I just came across this and am wondering what you're trying to do here. Do you mean to sort the children in such a way that their z-orders change?

This sounds fine, my only issue would be with the 'null' suggestion which implies we have to have some kind of memory of what positions they were in before the sort, and I don't think that would be retained anywhere. Do you think this aspect of it would be essential?

I'm curious as to the use case, anyway .. and wondering whether there are alternative mechanisms that could achieve the same sort of thing but more flexibly, such as by passing in a compare function (like Array.sort() with a compareFunction argument) - or would you prefer the speed (I note there's also Array.sortOn() which looks like what you're proposing here...)

thanks

shaucky commented 3 months ago

Oh guy, it's been a long time, let me memory about it.

This thing can be traced back to September last year, i tried to make a game which has large map and the window is expected to always face the player head-on. Based on the classic Flash display object mechanism. So when characters walk, sometime they should exchange z-orders with other objects on the map.

I did indeed use Array.sort() at the time, but the performance is not suitable (low frame rate). To be precise, i'm not sure that is it full stage redraw has a greater impact, or just the performance of sorting itself poor.

There is what i code at that time. But because the performance was too poor, i gave up on subsequent development.

        private function sortObjects(e: TimerEvent)
        {
            var gridY: int;
            var array: Array;
            var i: uint;
            var sceneScaleX: Number = _loader.content.scaleX;
            var sceneScaleY: Number = _loader.content.scaleY;
            var globalTop: Number = 0;
            var globalBottom: Number;
            var globalLeft: Number = 0;
            var globalRight: Number;
            var bounds: Rectangle;
            var point: Point;
            if (_needSort)
            {
                for each(var cell in _grids)
                {
                    i = 0;
                    while (i < cell.length)
                    {
                        _objectLayer.addChild(cell[i++]);
                    }
                }
                _needSort = false;
                _rebuildSortArray();
            }
            if (stage)
            {
                globalRight = stage.stageWidth;
                globalBottom = stage.stageHeight;
                array = new Array();
                i = 0;
                while (i < _objectLayer.numChildren)
                {
                    array.push(_objectLayer.getChildAt(i++));
                }
                for each(var obj in _objectLayer)
                {
                    bounds = obj.getBounds(_objectLayer);
                    point = _loader.content.localToGlobal(new Point(bounds.topLeft.x, bounds.topLeft.y));
                    bounds.top = point.y * sceneScaleY;
                    bounds.left = point.x * sceneScaleX;
                    point = _loader.content.localToGlobal(new Point(bounds.bottomRight.x, bounds.bottomRight.y));
                    bounds.right = point.x * sceneScaleX;
                    bounds.bottom = point.y * sceneScaleY;
                    if (bounds.right < globalLeft || bounds.left > globalRight || bounds.bottom < globalTop || bounds.top > globalBottom)
                    {
                        obj.visible = false;
                    }
                    else
                    {
                        obj.visible = true;
                    }
                }
            }
            array = new Array();
            i = 0;
            while (i < _uiLayer.numChildren)
            {
                array.push(_uiLayer.getChildAt(i));
                i++;
            }
            array.sort(byY); //i also tried sortOn("y") now.
            i = 0;
            while (i < array.length)
            {
                _uiLayer.addChild(array[i]);
                i++;
            }
        }
        private function byY(a: DisplayObject, b: DisplayObject): int
        {
            if (a.y < b.y)
            {
                return -1;
            }
            else if (a.y > b.y)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }

Do you mean to sort the children in such a way that their z-orders change?

Yes, sort children on their z-orders when some of 'em change specific property.

Do you think this aspect of it would be essential?

Never mind it. I think the method should just be something like a switch(turn on/ turn off).

whether there are alternative mechanisms that could achieve the same sort of thing but more flexibly

As above code. If there is any better solution i think it should be put in.

Thanks.