Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Эффект пластики с отменой (http://www.flasher.ru/forum/showthread.php?t=207736)

alexandrratush 04.05.2014 23:44

Эффект пластики с отменой
 
Вложений: 2
Здравствуйте! Задача: создать эффект пластики с возможностью отмены последнего результата.
Сама реализация эффекта была позаимствована отсюда silin.su/AS3/bitmap/plasticDistort/

Изучив код, вроде понял что к чему, но вот вернуть корректно предыдущее состояние "пластики" не выходит.
К примеру: 3 раза взяли и потянули мишкой, потом нажали "отмена" (все отлично происходит), и если опять начинаем "тянуть" картинку, то состояние сетки опять стает как до первого нажатия "отмена" + только что "потянули" (демо версия и исходник в CS5 приложена).

Весь код собран в один класс, опишу кратко на что, по моему, стоит обратить внимание:
1. Сохранение текущего слепка в массив истории происходит в ф-ции savePlastic
2. Возврат - в undoPlastic

Код AS3:

package {
        import flash.display.*;
        import flash.events.*;
        import flash.geom.*;
        import flash.ui.*;
        import fl.controls.NumericStepper;
        import fl.controls.CheckBox;
        import fl.controls.Button;
 
 
        public class Main extends Sprite {
                // Компоненты
                private var _numStepper:NumericStepper;
                private var _gridCheckBox:CheckBox;
                private var _btnReset:Button;
                private var _btnUndo:Button;
 
                //
                private var divX:int = 30;
                private var divY:int = 40;
                //
                private var W:Number = 300;
                private var H:Number = 400;
                //
                private var _canvas:Sprite;
 
                private var indices:Vector.<int>;
                private var uvData:Vector.<Number>;
                private var verticies:Vector.<Number>;
                private var nodes:Vector.<Point>;
 
                private var _texture:BitmapData;
 
                private var anchor:Point = new Point();
                private var marker:Point = new Point();
 
                private var _plasticArrHistory:Array;
 
 
                public function Main():void {
                        _plasticArrHistory = new Array();
 
                        // картинка
                        _texture = new TestBD();
 
                        // Добавляем контейнер
                        _canvas = new Sprite();
                        addChild(_canvas);
 
                        // Инициализация компонентов
                        initComponents();
 
                        initGrid();
 
                        // Отрисовка
                        draw();
 
                        // Слушатели
                        _canvas.addEventListener(MouseEvent.MOUSE_DOWN, canvasMouseDown);
                        _canvas.addEventListener(MouseEvent.MOUSE_UP, stageMouseUp);
                        _canvas.addEventListener(MouseEvent.ROLL_OVER, canvasRollOver);
                        _canvas.addEventListener(MouseEvent.ROLL_OUT, canvasRollOut);
                }
 
                /** Инициализация компонентов */
                private function initComponents():void {
                        _numStepper = numStepper;
                        _numStepper.addEventListener(Event.CHANGE, update);
 
                        _gridCheckBox = gridCheckBox;
 
                        _btnReset = btnReset;
                        _btnReset.addEventListener(MouseEvent.CLICK, btnResetClick);
 
                        _btnUndo = btnUndo;
                        _btnUndo.addEventListener(MouseEvent.CLICK, btnUndoClick);
                }
 
                private function canvasRollOut(e:MouseEvent):void {
                        Mouse.cursor = MouseCursor.AUTO;
                }
 
                private function canvasRollOver(e:MouseEvent):void {
                        Mouse.cursor = MouseCursor.HAND;
                }
 
                /** Обработчик нажатия миши */
                private function canvasMouseDown(e:MouseEvent):void {
                        anchor.x = marker.x = mouseX;
                        anchor.y = marker.y = mouseY;
 
                        _canvas.addEventListener(MouseEvent.MOUSE_MOVE, canvasMouseMove);
                }
 
                /** Обработчик перемещения миши */
                private function canvasMouseMove(e:MouseEvent):void {
                        marker.x = mouseX;
                        marker.y = mouseY;
                        update();
                        anchor.x = marker.x;
                        anchor.y = marker.y;
                }
 
                /** Обработчик отпускания миши */
                private function stageMouseUp(e:MouseEvent):void {
                        _canvas.removeEventListener(MouseEvent.MOUSE_MOVE, canvasMouseMove);
 
                        // Сохраняем состояние
                        savePlastic();
                }
 
                /** Сохранение состояния */
                public function savePlastic():void {
                        var v:Vector.<Number> = verticies.concat();
                        var n:Vector.<Point> = nodes.concat();
 
                        // Сохраняем состояние в массив
                        _plasticArrHistory.push( {v:v, n:n} );
                }
 
                /** Шаг назад в пластике */
                public function undoPlastic():void {
                        var len:int = _plasticArrHistory.length;
 
                        // Если нету сохраненных состояний, то ...
                        if (len == 0) return;
 
                        // Срезаем последнее состояние в истории
                        _plasticArrHistory.length -= 1;
 
                        // Если сохраненных состояний больше чем 1
                        if (len != 1) {
                                // Получаем последнее состояние (перед срезом это было предпоследнее)
                                len = _plasticArrHistory.length;
                                var v:Vector.<Number> = _plasticArrHistory[len - 1].v;
                                var n:Vector.<Point> = _plasticArrHistory[len - 1].n;
 
                                // Пересохраняем значения
                                verticies = v.concat();
                                nodes = n.concat();
 
                                // Отрисовка
                                draw();
                                resampleGrid();
                        } else {
                                // Если 1 значение, то просто сброс сетки
                                resetGrid();
                        }
                }
 
                private function btnResetClick(e:MouseEvent):void {
                        resetGrid();
                }
 
                private function btnUndoClick(e:MouseEvent):void {
                        undoPlastic();
                }
 
                private function update(e:Event = null):void {
                        resampleGrid();
                        draw();
                }
 
                private function draw():void {
                        _canvas.graphics.clear();
 
                        if (_gridCheckBox.selected) {
                                _canvas.graphics.lineStyle(0, 0x80FF80, 0.35);
                        }
 
                        _canvas.graphics.beginBitmapFill(_texture, null, false, true);
                        _canvas.graphics.drawTriangles(verticies, indices, uvData);
                        _canvas.graphics.endFill();
                }
 
                private function initGrid():void {
                        uvData = new Vector.<Number>();
                        verticies = new Vector.<Number>();
                        indices = new Vector.<int>();
                        nodes = new Vector.<Point>();
 
                        var k:int = 0;
                        for (var i:int = 0; i <= divY; i++) {
                                for (var j:int = 0; j <= divX; j++) {
                                        verticies.push(W * j / divX, H * i / divY);
                                        uvData.push(j / divX, i / divY);
 
                                        if (i < divY && j < divX) {
                                                indices.push(k, k + 1, k + divX + 1, k + 1, k + divX + 2, k + divX + 1);
                                        }
                                        nodes.push(new Point(W * j / divX, H * i / divY));
                                        k++;
                                }
                        }
                }
 
                private function resampleGrid():void {
                        for (var i:int = 1; i < divY; i++) {
                                for (var j:int = 1; j < divX; j++) {
 
                                        var k:int = i * (divX + 1) + j;
                                        var node:Point = nodes[k];
                                        var fX:Number = (anchor.x - node.x < 0) ? ((W - node.x) / (W - anchor.x)) : (node.x / anchor.x);
                                        var fY:Number = (anchor.y - node.y < 0) ? ((H - node.y) / (H - anchor.y)) : (node.y / anchor.y);
                                        var f:Number = fX * fY;
 
                                        for (var m:int = 1; m < _numStepper.value; m++) {
                                                f *= f;
                                        }
 
                                        node.x += (marker.x - anchor.x) * f;
                                        node.y += (marker.y - anchor.y) * f;
                                        verticies[2 * k] = node.x;
                                        verticies[2 * k + 1] = node.y;
                                }
                        }
                }
 
                private function resetGrid():void {
                        for (var i:int = 0; i <= divY; i++) {
                                for (var j:int = 0; j <= divX; j++) {
                                        var k:int = i * (divX + 1) + j;
                                        nodes[k].x = W * j / divX;
                                        nodes[k].y = H * i / divY;
                                }
                        }
 
                        update();
                }
 
        }
}

Помогите решить данную проблему.
Спасибо!

Исходник:
Вложение 30841

Демка:
Main.swf   (82.7 Кб)

silin 05.05.2014 21:04

Вложений: 1
не возьмусь сказать, что конкретно косячит в вашем примере, но явно что-то с сохранением узлов в массиве точек (nodes который), он вообще в этом раскладе избыточный (у меня был приплетен ради выпендрежа с твином)
вот "отшкуренный' от лишних деталей вариант, может поможет разобраться

Код AS3:

package
{
 
        import com.bit101.components.*;
        import flash.display.*;
        import flash.events.*;
        import flash.geom.*;
 
        public class PlasticDeform extends Sprite
        {
 
                private var divX:int = 30;
                private var divY:int = 40;
 
                private var W:Number = 300;
                private var H:Number = 400;
 
                private var indices:Vector.<int>;
                private var uvData:Vector.<Number>;
                private var verticies:Vector.<Number>;
 
                [Embed(source="sample.jpg")]
                private var sample_jpg:Class;
 
                private var texture:BitmapData=Bitmap(new sample_jpg()).bitmapData;
 
                private var gridCheckBox:CheckBox;
                private var undoBut:PushButton;
 
 
                private var mX:Number;
                private var mY:Number;
 
                private var canvas:Sprite = new Sprite();
 
                private var undoList:Array = [];
 
 
                public function PlasticDeform():void
                {
 
                        stage.scaleMode = StageScaleMode.NO_SCALE;
                        stage.align = StageAlign.TOP_LEFT;
 
 
 
                        addChild(canvas);
                        gridCheckBox = new CheckBox(this, 20, 420, "grid", draw);
                        undoBut = new PushButton(this, 160, 420, "undo", undoBut_click);
 
                        initGrid();
                        draw();
 
                        canvas.addEventListener(MouseEvent.MOUSE_DOWN, canvas_mouseDown);
                        stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUp);
 
                }
 
                private function canvas_mouseDown(e:MouseEvent):void
                {
                        mX = mouseX;
                        mY = mouseY;
 
 
                        canvas.addEventListener(MouseEvent.MOUSE_MOVE, canvas_mouseMove);
                        undoList.push(verticies.concat());
 
                }
 
                private function canvas_mouseMove(e:MouseEvent):void
                {
 
                        for (var k:int = 0; k < verticies.length; k += 2)
                        {
                                var tX:Number = verticies[k];
                                var tY:Number = verticies[k + 1];
                                var fX:Number = (mX - tX < 0) ? ((W - tX) / (W - mX)) : (tX / mX);
                                var fY:Number = (mY - tY < 0) ? ((H - tY) / (H - mY)) : (tY / mY);
                                var f:Number = fX * fY;
                                f *= f;
 
                                verticies[k] += (mouseX - mX) * f;
                                verticies[k + 1] += (mouseY - mY) * f;
                        }
                        draw();
                        mX = mouseX;
                        mY = mouseY;
 
                }
 
                private function stage_mouseUp(e:MouseEvent):void
                {
                        canvas.removeEventListener(MouseEvent.MOUSE_MOVE, canvas_mouseMove);
                }
 
                private function undoBut_click(e:Event = null):void
                {
 
                        if (undoList.length)
                        {
                                verticies = undoList.pop();
                                draw();
                        }
 
                }
 
                private function draw(e:Event = null):void
                {
 
                        canvas.graphics.clear();
                        if (gridCheckBox.selected)
                        {
                                canvas.graphics.lineStyle(0, 0x80FF80, 0.35);
                        }
                        canvas.graphics.beginBitmapFill(texture, null, false, true);
                        canvas.graphics.drawTriangles(verticies, indices, uvData);
                        canvas.graphics.endFill();
 
                }
 
                private function initGrid():void
                {
 
                        uvData = new Vector.<Number>();
                        verticies = new Vector.<Number>();
                        indices = new Vector.<int>();
 
                        var k:int = 0;
                        for (var i:int = 0; i <= divY; i++)
                        {
                                for (var j:int = 0; j <= divX; j++)
                                {
 
                                        verticies.push(W * j / divX, H * i / divY);
                                        uvData.push(j / divX, i / divY);
                                        if (i < divY && j < divX)
                                        {
                                                indices.push(k, k + 1, k + divX + 1, k + 1, k + divX + 2, k + divX + 1);
                                        }
 
                                        k++;
                                }
                        }
 
                }
 
        }
 
}


grid.swf   (36.5 Кб)

alexandrratush 05.05.2014 22:30

Спасибо огромное, переделал все под ваш пример и все заработало.:)
Почему не работало у меня, нет времени разбираться.
Еще раз спасибо!


Часовой пояс GMT +4, время: 00:39.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2020, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.