Здравствуйте! Задача: создать эффект пластики с возможностью отмены последнего результата.
Сама реализация эффекта была позаимствована отсюда
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();
}
}
}
Помогите решить данную проблему.
Спасибо!
Исходник:
flasher.rar
Демка: