Pregunta

Estoy dibujando una simulación autómata celular en un lienzo flexible. Alterno calcular el estado del autómata con la actualización de los gráficos en el panel. Sin embargo, no parece que la actualización del Panel de ser "mantenerse al día" con la actualización del estado de CA.

Me pregunto si estoy haciendo algo mal con mi manejo del código de gráficos. El código está por debajo. Siento que sea tan largo, pero no creo que el problema va a suceder con cualquier cosa más simple (así, probablemente lo hará, pero no estoy seguro de que quiera tomar el tiempo para encontrarlo).

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init();">
    <mx:Script>
        <![CDATA[
        private static const universeRadius:uint = 8;

        private var universes:Array = new Array();
        private var currentUniverse:uint = 0;
        private var squareHeight:uint;
        private var squareWidth:uint;

        private function init():void {
            squareHeight = myCanvas.height / universeRadius;
            squareWidth = myCanvas.width / universeRadius;
            initUniverses();

            while (true) {
                trace("Calling draw()");
                draw();
                trace("Calling updateUniverse()");
                updateUniverse();
            }
        }

        private function initUniverses():void {
            var universe0:Array = new Array();
            var universe1:Array = new Array();

            var i:int;
            for (i = 0; i < universeRadius; i++) {
                var universe0Row:Array = new Array();
                var universe1Row:Array = new Array();
                var j:int;
                for (j = 0; j < universeRadius; j++) {
                    if (Math.random() < 0.5) {
                        universe0Row[j] = 0;
                    } else {
                        universe0Row[j] = 1;
                    }
                    universe1Row[j] = 0;
                }
                universe0[i] = universe0Row;
                universe1[i] = universe1Row;
            }

            universes[0] = universe0;
            universes[1] = universe1;
        }

        private function normalize(pos:int):int {
            return (pos + universeRadius) % universeRadius;
        }

        private function updateUniverse():void {
            var newUniverse:int = 1 - currentUniverse;
            var i:int;
            for (i = 0; i < universeRadius; i++) {
                var j:int;
                for (j = 0; j < universeRadius; j++) {
                    var dx:int;
                    var dy:int;
                    var count:int = 0;
                    for (dx = -1; dx <= 1; dx++) {
                        var neighborX:int = normalize(i + dx);
                        for (dy = -1; dy <= 1; dy++) {
                            var neighborY:int = normalize(j + dy);
                            if ((dx != 0 || dy != 0) && 
                                universes[currentUniverse][neighborX][neighborY] == 1) {
                                    count++;
                                }
                        }
                    }
                    var currentCell:int = universes[currentUniverse][i][j];
                    if (currentCell == 1) {
                        // 1. Any live cell with fewer than two live neighbours 
                        //    dies, as if caused by underpopulation.
                        if (count < 2) {
                            universes[newUniverse][i][j] = 0;
                        }
                        // 2. Any live cell with more than three live neighbours
                        //    dies, as if by overcrowding.
                        else if (count > 3) {
                            universes[newUniverse][i][j] = 0;
                        }
                        // 3. Any live cell with two or three live neighbours 
                        //    lives on to the next generation.
                        else {
                            universes[newUniverse][i][j] = 1;
                        }
                    } else {
                        // 4. Any dead cell with exactly three live neighbours 
                        //    becomes a live cell.
                        if (count == 3) {
                            universes[newUniverse][i][j] = 1;
                        } else {
                            universes[newUniverse][i][j] = 0;
                        }
                    }
                }
            }

            currentUniverse = newUniverse;
        }

        private function draw():void {
            myCanvas.graphics.clear();
            myCanvas.graphics.beginFill(0xFFFFFF, 1.0);
            myCanvas.graphics.drawRect(0, 0, myCanvas.width, myCanvas.height);
            var i:int;
            for (i = 0; i < universeRadius; i++) {
                var j:int;
                for (j = 0; j < universeRadius; j++) {
                    if (universes[currentUniverse][i][j] == "1") {
                        myCanvas.graphics.beginFill(0x000000, 1.0);
                        myCanvas.graphics.drawRect(
                            j * squareWidth, i * squareHeight, squareWidth, squareHeight)
                    }
                }
            }
            myCanvas.graphics.endFill();
        }
        ]]>
    </mx:Script>
    <mx:Panel title="Life" height="95%" width="95%" 
        paddingTop="5" paddingLeft="5" paddingRight="5" paddingBottom="5">

        <mx:Canvas id="myCanvas" borderStyle="solid" height="100%" width="100%">
        </mx:Canvas>
    </mx:Panel>
</mx:Application>
¿Fue útil?

Solución

Scary:

while (true) {

Flex es de un solo subproceso, por lo que creo que nunca está dando a los UIComponents totalmente la oportunidad de actualización.

Las alternativas sería la de ejecutar los métodos de dibujo y actualizar en un temporizador, o ejecutarlos en el caso ENTER_FRAME. Cualquiera de ellas podría permitir que las actualizaciones de la lista de visualización se producen en medio de su

private function cycleUniverse(event:Event):void {
    updateUniverse();
    draw();
}

y luego o bien de

private var t:Timer;

private function init():void {
    t = new Timer(500); // every 500 ms
    t.addEventListener(TimerEvent.Timer, cycleUniverse);
    t.start();
}

o

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" enterFrame="cycleUniverse(event)">
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top