|
|
|
|||||
Эффект пластики с отменой
Здравствуйте! Задача: создать эффект пластики с возможностью отмены последнего результата.
Сама реализация эффекта была позаимствована отсюда silin.su/AS3/bitmap/plasticDistort/ Изучив код, вроде понял что к чему, но вот вернуть корректно предыдущее состояние "пластики" не выходит. К примеру: 3 раза взяли и потянули мишкой, потом нажали "отмена" (все отлично происходит), и если опять начинаем "тянуть" картинку, то состояние сетки опять стает как до первого нажатия "отмена" + только что "потянули" (демо версия и исходник в CS5 приложена). Весь код собран в один класс, опишу кратко на что, по моему, стоит обратить внимание: 1. Сохранение текущего слепка в массив истории происходит в ф-ции savePlastic 2. Возврат - в undoPlastic 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(); } } } Спасибо! Исходник: flasher.rar Демка: |
|
|||||
не возьмусь сказать, что конкретно косячит в вашем примере, но явно что-то с сохранением узлов в массиве точек (nodes который), он вообще в этом раскладе избыточный (у меня был приплетен ради выпендрежа с твином)
вот "отшкуренный' от лишних деталей вариант, может поможет разобраться 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++; } } } } } |
|
|||||
Спасибо огромное, переделал все под ваш пример и все заработало.
Почему не работало у меня, нет времени разбираться. Еще раз спасибо! |
Часовой пояс GMT +4, время: 07:23. |
|
« Предыдущая тема | Следующая тема » |
|
|