Анимированый переворот страниц




Главная > Уроки > Анимация > Анимированый переворот страниц

Анимированый переворот страниц

Автор/переводчик статьи: Команда сайта flashmaster.org.ua

Дата: 2012-10-14

Пример page-flip гостевая silin.

Шаг 1: Учимся ловить заворачивающийся уголок.

Что должно выйти.

изображение точек, которые надо найти
на рисунке вы можете наблюдать перпендикуляр от переворачиваемого уголка на мышку, он находится по середине линии и пересекает границы книги.

По теме:

Как найти пересечение линий при помощи векторов?"


Базовые опереции с 2D векторами.
Подумал немного и грохнул P2V вместо него и Point теперь продвинутый lex.geom.V2. Ниче оригинального, скопипастено с glaze.
package lex.geom 
{
	/**
	 * ...
	 * @author Anton Vasilevsky /
	 */
	public class V2
	{

		public var x:Number;
		public var y:Number;

		public function V2(_x:Number = 0, _y:Number =0) 
		{
			x = _x;
			y = _y;
		}


		public function clone():V2 {
			return new V2(x, y);
		}

		/*создает новый вектор*/
		public static function create(a:V2, b:V2):V2 {
			return new V2(a.x - b.x, a.y - b.y);
		}

		/*копирование х и y в result
		 * */
		public function copy(b:V2):void {
			x = b.x;
			y = b.y;
		}

		/*сложение
		 * */
		public function plus(b:V2):void {
			x += b.x;
			y += b.y;
		}

		/*вычитание
		 * */
		public function minus(b:V2):void {
			x -= b.x;
			y -= b.y;
		}

		/*Правая нормаль
		 * */
		public function rightNormal():void {
			var _x:Number = x;
			x = -y;
			y = _x; 
		}

		/*Левая нормаль
		 * */
		public function leftNormal():void {
			var _x:Number = x;
			x = y;
			y = -_x; 
		}

		/*умножение на число
		 * */
		public  function scale(n:Number):void {
			x *= n;
			y *= n; 
		}

		/*скалярное умножение векторов*/
		public function dot(b:V2):Number {
			return x * b.x + y * b.y;
		}

		/*деление вектора на число*/
		public function div(s:Number):void {
			if (s == 0) s = 0.0001;
			x /= s; 
			y /= s;
		}

		public function cross(b:V2):Number {
			return x * b.y - y * b.x;
		}

		/*длина вектора*/
		public function length():Number {
			return Math.sqrt(x * x + y * y);
		}

		/*расстояние от точки до точки*/
		public function distance(v:V2):Number {
			var _x:Number = x - v.x;
			var _y:Number = y - v.y;
			return Math.sqrt(_x * _x + _y * _y);
		}

		/*приведение вектора к единичному виду*/
		public function normalize():void {
			 var m:Number = length();
			 if (m == 0) m = 0.0001;
			 scale(1 / m);
		}

		/*returns the scalar projection of this vector onto v
		 *//*
 public  function scalarProjectionOnto(v0:V2,v1:V2):Number {
			return (v0.x*v1.x + v0.y*v1.y)/v1.length;
		}*/
	}

}

Теперь в наш стиль страниц добавляем координаты уголков открытой книги и координаты центра книги.
Теперь так:
package lex.book 
{
	import lex.geom.V2;
	/**
	 * ...
	 * @author Alex Lexcuk http://www.murmadillo.tut.su
	 */
	public class BookStyle
	{
		public var width:Number;
		public var height:Number;
		public var tl:V2;
		public var tr:V2;
		public var bl:V2;
		public var br:V2;
		public var midTop:V2;
		public var midBottom:V2;
public function BookStyle(_width:int = 100 , _height:int = 120) 
		{
			width = _width;
			height = _height;
			tl = new V2 (-width,0);
			tr = new V2(width,0);
			bl = new V2(-width, height);
			br = new V2(width, height);
			midTop = new V2();
			midBottom = new V2(0, height);
		}
		
	}

}

Мышиная исправлялка, в связи с ныне покойным P2V, изменилась не в лучшую строну, она теперь такая:
package lex.book 
{
	import lex.geom.V2;
	import lex.book.BookStyle;
	/**
	 * ...
	 * @author Alex Lexcuk http://www.murmadillo.tut.su
	 */
	public class FixMouse
	{
		private var pageP:V2 = new V2();
		private var s:BookStyle;
		private var v:V2;
		private var diagonal:Number;
		public function FixMouse(bs:BookStyle) 
		{
			s = bs;
			v = new V2();
diagonal = Math.sqrt(s.width * s.width + s.height * s.height);
		}

		public function fix(p:V2):V2 {
			pageP.copy(p);
			fixDistTo(s.midBottom, s.width);
			pageP.copy(v);
			fixDistTo(s.midTop, diagonal);
			return v;
		}

		private function fixDistTo(start:V2, dist:Number):void {
			v.copy(pageP);
			v.minus(start);
if (v.length() > dist) {//если больше dist нормализируем dist-ом
				v.normalize();
				v.scale(dist)
			}
			v.plus(start);
		}

	}

}

Ну и теперь перечечения линий, ниче я не понял как оно пересекается, но не понять не значит нагуглить, абы работало, как можно быстрее, для этого сделал отдельный класс
package lex.book 
{
	import lex.geom.V2;
	/**
	 * ...
	 * @author Alex Lexcuk http://www.murmadillo.tut.su
	 */
	public class BendLine
	{
		private var s:BookStyle;
		private var va:V2 = new V2();
		private var vb:V2 = new V2();
		private var inter:V2 = new V2();
		private var mid:V2 = new V2();
		private var midR:V2 = new V2();
		public var interTop:V2 = new V2();
		
		public var interBottom:V2 = new V2();
		public function BendLine(s:BookStyle) 
		{
			this.s = s;
		}

	/*расчет перегиба страницы pageP - положение мыши на книге
		 * con0 - перелистываемый угол страницы
		 * результат пересечения interTop и interBottom
		 * */
		public function calcBendLine(pageP:V2, con0:V2):void {
			
			mid.copy(con0);
			
		mid.minus(pageP);//вектор от уголка книги на мышь
			
			mid.scale(0.5);
			
			midR.copy(mid);
			
		midR.leftNormal();//вектор от углка книги на мышь
			
			mid.plus(pageP);
			
			midR.plus(mid);
			
			var res:V2;
			var con1:V2;
			if (con0 == s.bl) con1 = s.tl; else con1 = s.tr;
			
		res = lineIntersect(s.midBottom, s.br, mid, midR);
			
			interBottom.copy(res);//нижняя пересекающаяся точка
			
			res = lineIntersect(con0, con1, mid, midR);
			
		if (res.y > 0 && res.y < s.height) interTop.copy(res); else{
		res = lineIntersect(s.midTop, s.tr, mid, midR);
	interTop.copy(res);//нижняя пересекающаяся точка
			}
		}

	private function lineIntersect(a0:V2, a1:V2, b0:V2, b1:V2):V2 {
			// http://forum.vingrad.ru/faq/topic-157574.html
			var crossA:Number, crossB:Number, div:Number;
			
			crossA = a0.cross(a1);
			crossB = b0.cross(b1);
			
			va.copy(a0);
			va.minus(a1);
			
			
			vb.copy(b0)
			vb.minus(b1);
			
			div = 1 / va.cross(vb);
			
			inter.x = (crossA*vb.x - va.x*crossB) * div;
			inter.y = (crossA*vb.y - va.y*crossB) * div;
			return inter;
		}
	}

}

Вот так, ниче не создается и не удаляется, а от этого не заморачивается Garbage collector и естественно, тормозить нечему
Документ класс теперь такой
package  
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import lex.book.BendLine;
	import lex.book.BookStyle;
	import lex.book.FixMouse;
	
	import lex.geom.V2;
	import lex.*;
	/**
	 * ...
	 * @author Alex Lexcuk http://www.murmadillo.tut.su
	 */
	public class TrueMouseDoc extends Sprite
	{
		private var s:BookStyle = new BookStyle();
		private var fixMouse:FixMouse = new FixMouse(s);
		private var bendLine:BendLine = new BendLine(s);
		private var book:Sprite;
		private var expert:Sprite;
		public function TrueMouseDoc() 
		{
			addChild(book = new Sprite());
			book.y = 100;
			book.x = book.y + s.width;
			book.addChild(expert = new Sprite());
			book.graphics.lineStyle(0);
			book.graphics.beginFill(0xC0C0C0);
		book.graphics.drawRect( -s.width, 0, s.width * 2, s.height);
			book.graphics.endFill();
			book.graphics.drawRect( -1, 0, 2, s.height);
	stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
		}

		private function mouseMoveHandler(evt:MouseEvent):void {
			var pageP:V2;
			pageP = fixMouse.fix(new V2(book.mouseX, book.mouseY));
			expert.graphics.clear();
			expert.graphics.lineStyle(0);
			expert.graphics.drawCircle(pageP.x, pageP.y, 5);
			
			/*расчет линии перегиба страницы*/
			if (pageP.distance(s.bl) < 5) pageP.x += 5; else
			if (pageP.distance(s.br) < 5) pageP.x -= 5;
			
			bendLine.calcBendLine(pageP, s.bl);
			
expert.graphics.drawCircle(bendLine.interTop.x, bendLine.interTop.y, 2);
expert.graphics.drawCircle(bendLine.interBottom.x, bendLine.interBottom.y, 2);
			
		}


	}

}

Вам нужен Flash Player.

Получить проигрыватель Adobe Flash Player



Как дему, для правого уголка, можно изменить строчку в документ классе
bendLine.calcBendLine(pageP, s.br);

Вам нужен Flash Player.

Получить проигрыватель Adobe Flash Player



Нарисуем перевораиваемую страницу.

Вот такая теория:
Мы перемещаем мышку и переворациваем страницу за нижний (левый или правый уголок), отсюда следует, что переворачиваемая страница, конечно же должна попадать уголком на мышь. Пока пусть так будет: нажимаем на книгу, если нажатие левостороннее, то ставим триггер типа left=true, и рисуем страницу за мышку правым уголком на мышь, если нажатие правостороннее, то левым.
Тут все просто, надо только изменить документ класс.
package  
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import lex.book.BendLine;
	import lex.book.BookStyle;
	import lex.book.FixMouse;
	
	import lex.geom.V2;
	import lex.*;
	/**
	 * ...
	 * @author Alex Lexcuk http://www.murmadillo.tut.su
	 */
	public class TrueMouseDoc extends Sprite
	{
		private var s:BookStyle = new BookStyle();
		private var fixMouse:FixMouse = new FixMouse(s);
		private var bendLine:BendLine = new BendLine(s);
		private var book:Sprite;
		private var expert:Sprite;
		private var downTr:Boolean;
		private var pageP:V2;
		private var leftTr:Boolean;
		private var inside:Sprite;
		public function TrueMouseDoc() 
		{
			addChild(book = new Sprite());
			
			//начало переворачиваемая страница
			book.addChild(inside = new Sprite());
			inside.mouseEnabled = true;
			inside.mouseChildren = true;
			inside.graphics.lineStyle(0);
			inside.graphics.drawRect(0, 0, s.width, s.height);
			inside.graphics.drawRect(0, 0, 10, 10);
			//конец переворачиваемая страница
			
			
			book.y = 100;
			book.x = book.y + s.width;
			book.addChild(expert = new Sprite());
			book.graphics.lineStyle(0);
			book.graphics.beginFill(0xC0C0C0);
		book.graphics.drawRect( -s.width, 0, s.width * 2, s.height);
			book.graphics.endFill();
			book.graphics.drawRect( -1, 0, 2, s.height);
	book.addEventListener(MouseEvent.MOUSE_DOWN, bookMouseDownHandler);
	stage.addEventListener(MouseEvent.MOUSE_UP, bookMouseUpHandler);
	stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
		}

		private function bookMouseDownHandler(evt:MouseEvent):void {
			downTr = true;
			if (book.mouseX < 0) leftTr = true; else leftTr = false;
		}

		private function bookMouseUpHandler(evt:MouseEvent):void {
			downTr = false;
		}

		private function mouseMoveHandler(evt:MouseEvent):void {
			if (downTr) {
			pageP = fixMouse.fix(new V2(book.mouseX, book.mouseY));
				pageMove();
			}
		}

		private function pageMove():void {
			expert.graphics.clear();
			expert.graphics.lineStyle(0);
			expert.graphics.drawCircle(pageP.x, pageP.y, 5);
			
		//расчет линии перегиба страницы
//здесь +5 и -5 нужно для старта,что бы страница не дергалась в начале 
			if (pageP.distance(s.bl) < 5) {
				if (leftTr) pageP.x += 5; 
			} else
			if (pageP.distance(s.br) < 5) if (!leftTr) pageP.x -= 5;
			
			if (leftTr) bendLine.calcBendLine(pageP, s.bl); else
				bendLine.calcBendLine(pageP, s.br);
			

expert.graphics.drawCircle(bendLine.interTop.x, bendLine.interTop.y, 2);
expert.graphics.drawCircle(bendLine.interBottom.x, bendLine.interBottom.y, 2);
expert.graphics.moveTo(bendLine.interTop.x, bendLine.interTop.y);
expert.graphics.lineTo(bendLine.interBottom.x, bendLine.interBottom.y);
			
			drawInside();
		}

		private function drawInside():void {
			var mat:Matrix = inside.transform.matrix;
			mat.identity();
			
			if (leftTr) {
//участок, где производится изменение координат и //ротация вокруг определенной точки фигуры //установка внутреннего центра фигуры (для ротации) mat.tx -= s.width; mat.ty -= s.height; //ротация фигуры (Math.PI/2) - это вроде 90 градусов mat.rotate( -Math.atan2(pageP.x - bendLine.interBottom.x, pageP.y - bendLine.interBottom.y) + Math.PI/2); //установка координат фигуры mat.tx += pageP.x; mat.ty += pageP.y; inside.transform.matrix = mat; } else { mat.ty -= s.height; mat.rotate( -Math.atan2(pageP.x - bendLine.interBottom.x, pageP.y - bendLine.interBottom.y) - Math.PI/2); mat.tx += pageP.x; mat.ty += pageP.y; inside.transform.matrix = mat; } } } }

Вам нужен Flash Player.

Получить проигрыватель Adobe Flash Player



Нарисуем маску на переворачиваемую страницу.

Теория:
Поверх переворачиваемой страницы ложим спрайт на котором рисуем маску. Нижняя тока полюбому нарисуется, поэтому рисовать будем с нижней точки, потом полюбому идет мышиная точка, затем: если вторая точка пересечения принадлежит боковым линиям книги, то эта маска треугольная, если нет то берем верхнюю точку тягаемого уголка, верхнюю точку пересечения и закрываем этот четырехугольник на нижнюю точку пересечения.
Подумал я и сделал все наоборот.
Добавляем на inside маскировочный спрайт
inside.addChild(inMask = new Sprite());

Теперь допишем-перепишем функцию drawInside, что-бы она рисовалась с маской
		private function drawInside():void {
			var mat:Matrix = inside.transform.matrix;
			mat.identity();
			mat.ty -= s.height;
			if (leftTr) {
				mat.tx -= s.width;
mat.rotate( -Math.atan2(pageP.x - bendLine.interBottom.x, 
pageP.y - bendLine.interBottom.y) + Math.PI/2);
				inside.transform.matrix = mat;
			} else {
mat.rotate( -Math.atan2(pageP.x - bendLine.interBottom.x, 
pageP.y - bendLine.interBottom.y) - Math.PI/2);
			}
			mat.tx += pageP.x;
			mat.ty += pageP.y;
			inside.transform.matrix = mat;
			
			//маскa переворачиваемой страницы
			inMask.graphics.clear();
			inMask.graphics.beginFill(0);
			inside.mask = inMask;
			if (leftTr) {
				inMask.graphics.moveTo( s.width, s.height);
				
				inMask.graphics.lineTo( s.width , bendLine.interTop.y);
				
				if (bendLine.interTop.y > 0) {
inMask.graphics.lineTo( s.width - (s.width + bendLine.interBottom.x), s.height);
				}else {
inMask.graphics.lineTo(s.width - (s.width + bendLine.interTop.x), 0);
inMask.graphics.lineTo(s.width - (s.width + bendLine.interBottom.x), s.height);
				}
				inMask.graphics.lineTo(s.width, s.height);
			} else {
				inMask.graphics.moveTo( 0, s.height);
				inMask.graphics.lineTo( 0, bendLine.interTop.y);
				if (bendLine.interTop.y > 0) {
inMask.graphics.lineTo( s.width - bendLine.interBottom.x, s.height);
				}else {
inMask.graphics.lineTo(s.width - bendLine.interTop.x, 0);
inMask.graphics.lineTo(s.width - bendLine.interBottom.x, s.height);
				}
				inMask.graphics.lineTo(0, s.height);
			}
			
			
		}

Все я теперь понял как дальше делать этот page-flip.

Вам нужен Flash Player.

Получить проигрыватель Adobe Flash Player



Просмотров: 4574


Понравился материал? Поделись с друзьями!





Подписаться на рассылку.

При перепечатки материалов ссылка на наш сайт обязательна!


 1